Android8 从系统启动到用户见到第一个Activity的流程源码分析(三)

前文回顾:

Android8 从系统启动到用户见到第一个Activity的流程源码分析(二)-CSDN博客文章浏览阅读484次,点赞13次,收藏6次。本文分析了Android系统启动第一个Activity的关键流程。首先通过ActivityStarter的startActivityUnchecked方法初始化状态并确定目标任务栈,接着调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法恢复焦点栈顶Activity。当检测到目标进程不存在时,AMS会通过startProcessLocked方法创建新进程,该方法经过多次重载最终调用Process.start,通过Zygote forkhttps://blog.csdn.net/g_i_a_o_giao/article/details/151027854?spm=1011.2124.3001.6209Android8 从系统启动到用户见到第一个Activity的流程源码分析(一)-CSDN博客文章浏览阅读412次,点赞3次,收藏4次。本文分析了Android系统启动过程中AMS(ActivityManagerService)的systemReady方法及其关键流程。当SystemService调用AMS的systemReady方法后,AMS会初始化各类服务,清理不允许运行的进程,最终通过startHomeActivityLocked启动主屏幕Activity。该流程涉及多个关键步骤: 创建Home Intent并解析对应Activity信息 通过ActivityStarter启动主屏幕Activity 在startActivityLochttps://blog.csdn.net/g_i_a_o_giao/article/details/150958400?spm=1011.2124.3001.6209紧接上篇文章,我们分析到了frameworks/base/core/java/android/os/Process.java中的start方法。

在这个方法中主要还是调用ZygoteProcess.java中的start方法。

java 复制代码
/**
 * 启动一个新的应用进程。这是Android框架中创建新进程的主要入口点。
 * 
 * <p>如果系统启用了Zygote进程机制(默认情况),将通过Zygote fork一个新的进程,
 * 并在新进程中执行指定{@code processClass}的静态{@code main()}函数。
 * 此函数调用返回后,新进程会继续运行。
 * 
 * <p>如果未启用Zygote进程机制(例如在某些特殊环境下),则会在调用者的当前进程中
 * 创建一个新线程,并在该线程中调用{@code processClass}的{@code main()}方法。
 * (这是一种退化情况,通常不会发生)。
 * 
 * <p>{@code niceName} 参数如果非空,将作为进程的自定义显示名称,替代{@code processClass}。
 * 这允许您即使使用相同的{@code processClass}启动多个进程,也能轻松区分它们。
 * (例如,为不同WebView服务进程设置可读的名称)。
 * 
 * <p>当{@code invokeWith}参数不为null时,进程将以"全新应用"(fresh app)的方式启动,
 * 而不是通过Zygote fork。请注意,这通常需要root权限(uid 0)或
 * {@code debugFlags}包含{@link Zygote#DEBUG_ENABLE_DEBUGGER}(即可调试状态)才被允许。
 * (这通常用于使用wrap.sh脚本或类似工具来启动进程进行调试)。
 * 
 * @param processClass 用作进程主入口点的类名(例如:"android.app.ActivityThread")。
 * @param niceName     进程的更可读名称(用于`ps`命令等),例如应用包名。
 * @param uid          进程运行时的用户ID。
 * @param gid          进程运行时的主组ID。
 * @param gids         与进程关联的附加组ID数组(用于权限管理)。
 * @param debugFlags   控制进程调试行为的附加标志位(例如:启用JDWP、CheckJNI)。
 * @param mountExternal 外部存储挂载模式(例如:{@link Zygote#MOUNT_EXTERNAL_NONE})。
 * @param targetSdkVersion 应用的目标SDK版本,用于控制兼容性行为。
 * @param seInfo       可为null,新进程的SELinux安全上下文信息。
 * @param abi          非null,启动此应用应使用的ABI(例如:"arm64-v8a")。
 * @param instructionSet 可为null,要使用的指令集(例如:"arm64")。
 * @param appDataDir   可为null,应用的数据目录。
 * @param invokeWith   可为null,用于启动进程的命令(例如:"/system/bin/logwrapper /data/app/wrap.sh")。
 * @param zygoteArgs   提供给Zygote进程的额外参数。
 * 
 * @return ProcessStartResult 一个描述进程启动尝试结果的对象,包含进程PID等信息。
 * @throws RuntimeException 如果启动过程中发生致命错误。
 * 
 * @hide 这是一个隐藏API,对普通应用开发者不可见,仅供系统内部使用。
 */
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String invokeWith,
                              String[] zygoteArgs) {
    // 将启动请求委托给一个ZygoteProcess实例处理。
    // zygoteProcess封装了与Zygote进程通信的细节(通过本地Socket)。
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

那我们继续看一下这个zygoteProcess.java中的start方法。在这个方法中又调用了startViaZygote方法。在startViaZygote方法中,创建了一个参数列表,然后解析参数并且添加到列表中,最后又调用了zygoteSendArgsAndGetResult方法。

java 复制代码
 public final Process.ProcessStartResult start(final String processClass,
                                                  final String niceName,
                                                  int uid, int gid, int[] gids,
                                                  int debugFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }



/**
     * Starts a new process via the zygote mechanism.
     *
     * @param processClass Class name whose static main() to run
     * @param niceName 'nice' process name to appear in ps
     * @param uid a POSIX uid that the new process should setuid() to
     * @param gid a POSIX gid that the new process shuold setgid() to
     * @param gids null-ok; a list of supplementary group IDs that the
     * new process should setgroup() to.
     * @param debugFlags Additional flags.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SELinux information for the new process.
     * @param abi the ABI the process should use.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     * @param extraArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws ZygoteStartFailedEx if process start failed for any reason
     */
    private Process.ProcessStartResult startViaZygote(final String processClass,
                                                      final String niceName,
                                                      final int uid, final int gid,
                                                      final int[] gids,
                                                      int debugFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
            argsForZygote.add("--enable-jni-logging");
        }
        if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
            argsForZygote.add("--enable-safemode");
        }
        if ((debugFlags & Zygote.DEBUG_ENABLE_JDWP) != 0) {
            argsForZygote.add("--enable-jdwp");
        }
        if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
            argsForZygote.add("--enable-checkjni");
        }
        if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
            argsForZygote.add("--generate-debug-info");
        }
        if ((debugFlags & Zygote.DEBUG_ALWAYS_JIT) != 0) {
            argsForZygote.add("--always-jit");
        }
        if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
            argsForZygote.add("--native-debuggable");
        }
        if ((debugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
            argsForZygote.add("--java-debuggable");
        }
        if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
            argsForZygote.add("--enable-assert");
        }
        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
            argsForZygote.add("--mount-external-default");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
            argsForZygote.add("--mount-external-read");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
            argsForZygote.add("--mount-external-write");
        }
        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

        // --setgroups is a comma-separated list
        if (gids != null && gids.length > 0) {
            StringBuilder sb = new StringBuilder();
            sb.append("--setgroups=");

            int sz = gids.length;
            for (int i = 0; i < sz; i++) {
                if (i != 0) {
                    sb.append(',');
                }
                sb.append(gids[i]);
            }

            argsForZygote.add(sb.toString());
        }

        if (niceName != null) {
            argsForZygote.add("--nice-name=" + niceName);
        }

        if (seInfo != null) {
            argsForZygote.add("--seinfo=" + seInfo);
        }

        if (instructionSet != null) {
            argsForZygote.add("--instruction-set=" + instructionSet);
        }

        if (appDataDir != null) {
            argsForZygote.add("--app-data-dir=" + appDataDir);
        }

        if (invokeWith != null) {
            argsForZygote.add("--invoke-with");
            argsForZygote.add(invokeWith);
        }

        argsForZygote.add(processClass);

        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }

        synchronized(mLock) {
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

在这个zygoteSendArgsAndGetResult方法中,首先检查传递的参数,然后通过socket通信向zygote进程发送符合通信协议的字符串。

java 复制代码
/**
 * 向Zygote进程发送一个参数列表,Zygote进程会根据这些参数启动一个新的子进程并返回其PID。
 * 请注意:当前实现不允许参数中包含换行符('\n'),如果发现则会用空格替换。
 * (根据注释,但实际代码是直接抛出异常,这是一个值得注意的细节)
 *
 * @param zygoteState 表示与Zygote进程连接状态的对象,包含Socket的读写流
 * @param args 要发送给Zygote的参数列表,这些参数将用于配置新进程
 * @return ProcessStartResult 包含新创建子进程PID的对象
 * @throws ZygoteStartFailedEx 如果进程启动因任何原因失败,则抛出此异常
 */
@GuardedBy("mLock") // 此方法需要持有mLock锁,保证多线程环境下的同步访问
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
    try {
        // 1. 参数预检:在发送前检查所有参数,确保没有嵌入的换行符('\n')
        // 这样做可以避免向Zygote写入部分响应,保证协议的完整性。
        int sz = args.size();
        for (int i = 0; i < sz; i++) {
            if (args.get(i).indexOf('\n') >= 0) {
                // 如果发现换行符,立即抛出异常,而不是替换它。
                // (注释说"替换",但代码实际是"抛出异常",这可能意味着注释过时或代码逻辑已更改)
                throw new ZygoteStartFailedEx("embedded newlines not allowed");
            }
        }

        /**
         * 与Zygote进程的通信协议格式(请参考com.android.internal.os.SystemZygoteInit.readArgumentList()):
         * a) 首先发送一个参数数量的字符串(本质上是argc),以换行符结束
         * b) 然后发送相应数量的参数字符串,每个参数都以换行符结束
         *
         * Zygote进程读取这些参数后,会进行fork操作,然后写入子进程的pid(失败则为-1),
         * 随后再写入一个布尔值表示是否使用了包装进程(wrapper process)。
         */
        final BufferedWriter writer = zygoteState.writer; // 获取Socket的字符输出流
        final DataInputStream inputStream = zygoteState.inputStream; // 获取Socket的数据输入流

        // 2. 发送参数数量
        writer.write(Integer.toString(args.size())); // 将参数个数转换为字符串并写入
        writer.newLine(); // 写入换行符,表示本条消息结束

        // 3. 逐个发送所有参数
        for (int i = 0; i < sz; i++) {
            String arg = args.get(i);
            writer.write(arg); // 写入参数内容
            writer.newLine(); // 每个参数后都写入一个换行符,作为分隔符
        }

        writer.flush(); // 强制刷新缓冲区,确保所有数据都立即发送到Zygote端

        // 4. 读取Zygote的响应
        // 这里有一个思考点:是否应该设置读取超时?目前没有。
        Process.ProcessStartResult result = new Process.ProcessStartResult();

        // 必须从输入流中读取完整的响应数据,避免有字节残留在流中,
        // 否则可能会被下一次进程启动操作意外读到,导致严重错误。
        result.pid = inputStream.readInt(); // 首先读取一个整数,即Zygote返回的PID
        result.usingWrapper = inputStream.readBoolean(); // 然后读取一个布尔值,表示是否使用了包装器

        // 5. 检查响应结果
        if (result.pid < 0) {
            // 如果PID小于0(通常是-1),表示Zygote端fork()系统调用失败
            throw new ZygoteStartFailedEx("fork() failed");
        }
        return result; // 返回成功的结果

    } catch (IOException ex) {
        // 6. 异常处理:如果在通信过程中发生IO异常
        zygoteState.close(); // 关闭与Zygote的连接状态(包括Socket)
        // 将IOException包装成ZygoteStartFailedEx并重新抛出
        throw new ZygoteStartFailedEx(ex);
    }
}

之前在分析Zygote进程启动的源码笔记中有分析过,ZygoteInit.java的main方法中会调用ZygoteServer.java中的runSelectLoop方法。在这个方法中,会通过多路复用的方式监听多个socket并且受到消息时创建一个ZygoteConnection对象,然后调用它的processOneCommand方法。那我们来看看这个performOneCommand方法。

java 复制代码
/**
 * 从命令Socket中读取一条启动命令并处理。如果成功,将fork一个子进程。
 * 在子进程中,返回一个用于调用子进程main方法(或等效方法)的{@code Runnable}。
 * 在父进程(即Zygote自身)中,始终返回{@code null}。
 *
 * 如果客户端关闭了socket,会设置一个{@code EOF}条件,调用者可以通过调用
 * {@code ZygoteConnection.isClosedByPeer}来检测。
 *
 * @param zygoteServer 管理ZygoteServer状态的对象
 * @return Runnable 在子进程中返回一个Runnable任务,在父进程中返回null
 */
Runnable processOneCommand(ZygoteServer zygoteServer) {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
        // 1. 读取参数:从Socket连接中读取客户端发送的参数列表
        args = readArgumentList();
        // 获取辅助文件描述符(通过Socket传递的FD,如启动Service时使用的FD)
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }

    // readArgumentList 仅在到达EOF(没有可用数据可读)时返回null。
    // 这只会发生在远程socket已断开连接的情况下。
    if (args == null) {
        isEof = true; // 标记连接已被对等方关闭
        return null;
    }

    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;

    // 2. 参数解析:将字符串参数解析为结构化的Arguments对象,便于后续处理
    parsedArgs = new Arguments(args);

    // 3. 处理特殊查询命令(这些命令不fork进程,直接返回响应)
    if (parsedArgs.abiListQuery) {
        handleAbiListQuery(); // 处理ABI列表查询
        return null;
    }

    if (parsedArgs.preloadDefault) {
        handlePreload(); // 处理默认预加载请求
        return null;
    }

    if (parsedArgs.preloadPackage != null) {
        // 处理特定包的预加载请求
        handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
                parsedArgs.preloadPackageCacheKey);
        return null;
    }

    // 4. 安全策略检查:确保客户端没有尝试设置任何能力(capabilities)
    //    能力控制应由Zygote根据策略决定,而不是由客户端指定。
    if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
        throw new ZygoteSecurityException("Client may not specify capabilities: " +
                "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
                ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
    }

    // 应用UID安全策略(检查请求的UID是否允许)
    applyUidSecurityPolicy(parsedArgs, peer);
    // 应用invoke-with安全策略(检查是否允许使用包装脚本启动)
    applyInvokeWithSecurityPolicy(parsedArgs, peer);

    // 应用调试器相关的系统属性
    applyDebuggerSystemProperty(parsedArgs);
    // 应用invoke-with相关的系统属性
    applyInvokeWithSystemProperty(parsedArgs);

    // 5. 准备资源限制(rlimits)
    int[][] rlimits = null;
    if (parsedArgs.rlimits != null) {
        rlimits = parsedArgs.rlimits.toArray(intArray2d);
    }

    // 6. 处理 invoke-with 模式(使用包装脚本启动)
    int[] fdsToIgnore = null;
    if (parsedArgs.invokeWith != null) {
        try {
            // 创建一对管道,用于父进程(Zygote)和子进程之间的通信
            FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
            childPipeFd = pipeFds[1]; // 子进程端
            serverPipeFd = pipeFds[0]; // 服务器(Zygote)端
            // 清除子进程端管道的FD_CLOEXEC标志,使其在execvp后仍然保持打开
            Os.fcntlInt(childPipeFd, F_SETFD, 0);
            // 设置要忽略的文件描述符数组(在fork时保持打开)
            fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
        } catch (ErrnoException errnoEx) {
            throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
        }
    }

    /**
     * 为了避免将描述符泄漏给Zygote子进程,本地代码必须在从Zygote-root切换到
     * 要启动的应用程序的UID和权限之前,关闭子进程中的两个Zygote socket描述符。
     *
     * 为了避免在关闭两个LocalSocket对象时出现"坏文件描述符"错误,
     * Posix文件描述符通过dup2()调用被释放,该调用会关闭socket并用一个
     * 指向/dev/null的打开描述符替代。
     */
    int [] fdsToClose = { -1, -1 }; // 初始化要关闭的FD数组

    // 获取当前命令socket的FD,并标记为需要在子进程中关闭
    FileDescriptor fd = mSocket.getFileDescriptor();
    if (fd != null) {
        fdsToClose[0] = fd.getInt$();
    }

    // 获取Zygote服务器主socket的FD,并标记为需要在子进程中关闭
    fd = zygoteServer.getServerSocketFileDescriptor();
    if (fd != null) {
        fdsToClose[1] = fd.getInt$();
    }

    fd = null; // 帮助GC

    // 7. 核心操作:fork子进程并进行专门化配置
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
            parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
            parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
            parsedArgs.appDataDir);

    try {
        if (pid == 0) {
            // 8. 子进程处理路径
            zygoteServer.setForkChild(); // 标记ZygoteServer当前处于子进程

            // 关闭子进程中不需要的Zygote server socket
            zygoteServer.closeServerSocket();
            // 安静地关闭服务器端管道(子进程不需要)
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;

            // 处理子进程逻辑,返回一个Runnable(这里是调用ActivityThread.main())
            return handleChildProc(parsedArgs, descriptors, childPipeFd);
        } else {
            // 9. 父进程(Zygote)处理路径
            // pid < 0 表示fork失败,将在handleParentProc中处理
            // 安静地关闭子进程端管道(父进程不需要)
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            // 处理父进程逻辑(如跟踪子进程状态、清理等)
            handleParentProc(pid, descriptors, serverPipeFd);
            return null; // 父进程总是返回null
        }
    } finally {
        // 10. 清理资源:确保在任何路径下都关闭管道FD,避免资源泄漏
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

在这个方法中会对传递过来的参数列表进行解析,然后根据参数进行判断是否要fork一个新的进程。如果需要的话,就需要调用Zygote.forkAndSpecialize方法(之前的文章已经解析过,可以查看Android8 Zygote源码分析学习笔记(二)-CSDN博客进行复习)。调用这个方法会fork一个新的进程,然后会对进程进行一系列配置,最后会调用handleChildProc方法来找到之前传递的参数android.app.ActivityThread。

if (entryPoint == null) entryPoint = "android.app.ActivityThread";

那么根据之前的分析,handleChildProc方法会找到ActivityThread.java的main函数并且封装成Runnable对象返回,在ZygoteInit的main方法中会执行这个runnable对象的run方法。

// We're in the child process and have exited the select loop. Proceed to execute the

// command.

if (caller != null) {

caller.run();

}

那么我们就要去看看/frameworks/base/core/java/android/app/ActivityThread.java中的main方法。它的主要作用是创建一个属于主线程的MainLooper,然后创建一个ActivityThread对象,最后调用了attch方法附着到系统进程中。

java 复制代码
/**
 * Android应用进程的主入口点。该方法由Zygote在fork出新应用进程后调用。
 * 它负责初始化应用的主线程、消息循环(Looper)和与应用进程生命周期相关的核心组件。
 *
 * @param args 命令行参数(通常由Zygote进程传递过来)
 */
public static void main(String[] args) {
    // 1. 开始性能跟踪:标记"ActivityThreadMain"阶段的开始,便于使用Systrace等工具分析启动性能。
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

    // 2. 禁用CloseGuard:CloseGuard默认是开启的,它会检测资源未关闭的情况,但日志非常冗长。
    //    这里先全局禁用它,后续在调试版本中会通过StrictMode有选择地开启(输出到DropBox而非Logcat)。
    CloseGuard.setEnabled(false);

    // 3. 初始化环境:为当前用户初始化环境变量、配置和存储路径。
    //    例如,设置数据目录(/data/user/0/<package_name>)。
    Environment.initForCurrentUser();

    // 4. 设置事件日志报告器:为libcore库设置一个事件日志报告器,
    //    允许系统库将事件记录到Android的EventLog中。
    EventLogger.setReporter(new EventLoggingReporter());

    // 5. 设置可信证书存储位置:确保TrustedCertificateStore在正确的位置查找CA证书。
    //    configDir 通常是 /data/misc/user/<user-id>/keystore
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    // 6. 设置进程参数:将进程的参数argv[0]设置为"<pre-initialized>"。
    //    这是一个临时状态,后续在attach过程中会被设置为实际的进程名(包名)。
    Process.setArgV0("<pre-initialized>");

    // 7. 准备主线程的消息循环(Looper):这是Android消息机制的核心。
    //    该方法会创建一个Looper对象并将其设置到当前线程(主线程)的ThreadLocal中。
    Looper.prepareMainLooper();

    // 8. 创建主线程对象:实例化ActivityThread,它是Android应用主线程的管理者,
    //    负责调度和执行AMS与应用之间的核心交互(如Activity生命周期回调)。
    ActivityThread thread = new ActivityThread();

    // 9. 附着到系统进程:调用attach方法,通过Binder通知ActivityManagerService(AMS)
    //    本应用进程已准备就绪。参数false表示这不是系统进程。
    //    这是一个非常关键的操作,它会:
    //    a) 获取AMS的代理对象(IActivityManager)
    //    b) 调用AMS的attachApplication方法,将本进程的ApplicationThread对象(Binder stub)传递给AMS
    //    c) AMS收到后,会开始调度启动本应用应该运行的Activity、Service等组件。
    thread.attach(false);

    // 10. 设置全局的主线程Handler:sMainThreadHandler是ActivityThread中的H Handler,
    //     它负责处理从AMS发送过来的消息(如LAUNCH_ACTIVITY, PAUSE_ACTIVITY等)。
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    // 11. (可选)设置消息循环的日志打印:此代码块被if (false)禁用,可用于调试消息循环的处理过程。
    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // 结束"ActivityThreadMain"阶段的性能跟踪。
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    // 12. 启动消息循环:开始无限循环,处理消息队列(MessageQueue)中的消息。
    //     主线程会阻塞在这里,不断地从消息队列中取出消息,并由H Handler及其target(如ActivityThread)进行处理。
    //     这是一个永不返回的调用(除非调用Looper.quit(),但主线程不允许这样做)。
    Looper.loop();

    // 13. 如果Looper.loop()意外返回(退出),则抛出运行时异常。
    //     因为Android应用的主消息循环设计上是永不停止的,所以执行到这里意味着发生了严重错误。
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

那继续分析这个attch方法,在这个方法中,主要是获取了AMS的binder对象,并且调用attachApplication方法将ApplicationThread对象mAppThread传递给AMS,至此,AMS获得了向本应用进程发送消息的能力。

java 复制代码
final ApplicationThread mAppThread = new ApplicationThread();

// 继承自Stub,说明这是个binder对象
private class ApplicationThread extends IApplicationThread.Stub { 
        .......省略代码......
}

/**
 * 将当前ActivityThread(应用进程)附着到系统进程或作为普通应用进程初始化。
 * 这是应用进程启动后与系统服务器建立通信的关键步骤。
 *
 * @param system 如果为true,表示当前是系统进程(如system_server)的初始化;
 *               如果为false,表示是普通应用进程的初始化。
 */
private void attach(boolean system) {
    sCurrentActivityThread = this; // 设置当前线程为全局的ActivityThread实例
    mSystemThread = system;        // 记录当前是否是系统进程

    if (!system) {
        // --- 普通应用进程的初始化路径 ---
        
        // 1. 添加首次绘制处理器:在View系统首次执行绘制前启用JIT编译器优化
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled(); // 确保JIT编译器已启用
            }
        });

        // 2. 设置DDM(Dalvik Debug Monitor)中的应用名称,用于调试和 profiling
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());

        // 3. 将ApplicationThread对象设置为Runtime的应用程序对象。
        //    ApplicationThread是一个Binder对象,是AMS与应用进程通信的接收端。
        RuntimeInit.setApplicationObject(mAppThread.asBinder());

        // 4. 获取ActivityManagerService(AMS)的Binder代理对象
        final IActivityManager mgr = ActivityManager.getService();

        try {
            // 5. 【关键调用】通过Binder调用AMS的attachApplication方法,
            //    将本进程的ApplicationThread对象(mAppThread)传递给AMS。
            //    至此,AMS获得了向本应用进程发送消息的能力(如启动Activity、Service等)。
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer(); // 处理来自系统服务的远程异常
        }

        // 6. 添加GC监视器:监控堆内存使用情况,在接近堆内存限制时通知AMS释放一些Activity
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return; // 如果没有Activity发生改变,则跳过
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();    // Dalvik堆的最大大小
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); // 已使用的大小
                // 如果已使用内存超过最大值的3/4,则认为内存紧张
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        // 通知AMS可以释放一些本进程中的Activity以节省内存
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
        // --- 系统进程(system_server)的初始化路径 ---
        
        // 系统进程不需要设置application object,因为如果系统崩溃,
        // 我们无法显示警报,只能直接退出。
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());

        try {
            // 创建Instrumentation对象,用于监控系统与应用的交互(主要用于测试)
            mInstrumentation = new Instrumentation();
            // 为系统进程创建应用上下文(Context)
            ContextImpl context = ContextImpl.createAppContext(
                    this, getSystemContext().mPackageInfo);
            // 创建并初始化系统应用的Application对象
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            mInitialApplication.onCreate(); // 调用Application的onCreate()生命周期方法
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    // 7. 为libcore添加dropbox日志报告器:当发生严重错误时,日志会被记录到DropBox中。
    DropBox.setReporter(new DropBoxReporter());

    // 8. 添加全局配置变更回调:当系统配置(如屏幕方向、语言等)发生变化时,此回调会被触发。
    ViewRootImpl.ConfigChangedCallback configChangedCallback
            = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // 需要立即将配置变更应用到资源管理器,因为返回后视图层级结构会被告知此变更。
            if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                    null /* compat */)) {
                // 更新本地化列表
                updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                        mResourcesManager.getConfiguration().getLocales());

                // 如果资源配置确实发生了改变,并且新配置比待处理的配置更新,则通知消息循环
                if (mPendingConfiguration == null
                        || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
                    mPendingConfiguration = globalConfig;
                    // 发送H.CONFIGURATION_CHANGED消息,最终会触发onConfigurationChanged回调
                    sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                }
            }
        }
    };
    // 将配置变更回调注册到ViewRootImpl
    ViewRootImpl.addConfigCallback(configChangedCallback);
}

至此,分析到这里进行一个小的总结。**FallbackHome应用的进程已经成功fork出来了,并且创建了ActivityThread对象和AMS进行了binder绑定。**那么接下来要分析,这个应用进程的Application的oncreate方法是怎样执行的,Activity的onCreate方法是怎么执行的,Activity又是怎么展示到前台的。

相关推荐
王喵喵喵3 小时前
每天一个安卓测试开发小知识之 (四)---常用的adb shell命令第二期 pm命令
android·测试
t_hj3 小时前
CentOS 创建站点
linux·运维·centos
星星火柴9363 小时前
C++“类吸血鬼幸存者”游戏制作的要点学习
c++·笔记·学习·游戏
BoomHe4 小时前
Android Studio 内联提示设置
android
2025年一定要上岸4 小时前
【日常学习】2025-9-2 学习控件Day1
学习
yjx233324 小时前
《应用密码学》——基础知识及协议结构模块(笔记)
笔记·密码学
paynnne4 小时前
TreeSet原理
android
永日456704 小时前
学习日记-SpringMVC-day48-9.2
学习
一条上岸小咸鱼4 小时前
Flutter 类和对象(二):继承
android·kotlin