Android-Framework(十五)-进程的 fork 创建过程

文章内容

一次点击到 Activity 启动的七步总览

一、启动 Activity 时,进程不存在会发生什么

ActivityStackSupervisor.startSpecificActivityLocked() 以进程名和 uid 查询 ProcessRecord。记录存在且 app.thread 已绑定时,AMS 可以直接调用 realStartActivityLocked(),其余情况会进入 startProcessLocked()。
源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java:1365,startSpecificActivityLocked()。

进程名由 PackageManager Service(PMS)解析。它默认取包名,应用也可以通过 manifest 中的 android:process 指定其他进程名,所以查询键不一定与包名相同。

java
    // 定义启动指定 Activity 的方法    void startSpecificActivityLocked(ActivityRecord r,            // 接收恢复状态与配置检查参数            boolean andResume, boolean checkConfig) {        // Is this activity's application already running?        // 按进程名和 uid 查询进程记录        ProcessRecord app = mService.getProcessRecordLocked(r.processName,                // 传入应用 uid 并保留 Activity 进程查询语义                r.info.applicationInfo.uid, true);         // 记录 Activity 的启动时间        r.task.stack.setLaunchTime(r);         // 进程记录及 Binder 线程都可用时复用进程        if (app != null && app.thread != null) {            // 捕获远程调用异常            try {                // 非 framework 多进程 Activity 时补充包记录                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0                        // framework 包不走此补充条件                        || !"android".equals(r.info.packageName)) {                    // 把包及版本加入进程统计                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,                            // 传入 AMS 的进程统计对象                            mService.mProcessStats);                // 结束包记录条件分支                }                // 在现有进程中启动 Activity                realStartActivityLocked(r, app, andResume, checkConfig);                // 启动完成后返回                return;            // 处理应用进程远程调用失败            } catch (RemoteException e) {                // 记录启动 Activity 时的异常                Slog.w(TAG, "Exception when starting activity "                        // 输出目标组件和异常                        + r.intent.getComponent().flattenToShortString(), e);            // 结束异常处理            }        // 结束复用现有进程的分支        }         // 找不到可用进程时请求 AMS 创建进程        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,                // 标记启动原因及目标组件                "activity", r.intent.getComponent(), false, false, true);    // 结束方法    }

二、AMS 将创建请求发给 Zygote

2.1 AMS 准备进程参数

ActivityManagerService.startProcessLocked() 确定 ABI、指令集和数据目录。若调用方没有指定 entryPoint,AMS 将入口类设为 android.app.ActivityThread,再调用 Process.start()。
源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:3356,startProcessLocked()。

java
            // 优先采用调用方覆盖的 ABI            String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;            // 应用未声明 ABI 时采用系统首选 ABI            if (requiredAbi == null) {                // 读取系统支持列表的首项                requiredAbi = Build.SUPPORTED_ABIS[0];            // 结束 ABI 回退分支            }             // 初始化指令集名称            String instructionSet = null;            // 主 ABI 存在时换算指令集            if (app.info.primaryCpuAbi != null) {                // 由运行时取得 ABI 对应的指令集                instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);            // 结束指令集计算分支            }             // 保存补充组 id            app.gids = gids;            // 保存进程要求的 ABI            app.requiredAbi = requiredAbi;            // 保存进程指令集            app.instructionSet = instructionSet;             // 记录此次启动是否采用默认 Activity 入口            boolean isActivityProcess = (entryPoint == null);            // 未指定入口时使用 ActivityThread            if (entryPoint == null) entryPoint = "android.app.ActivityThread";            // 开始记录进程启动 trace            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +                    // 写入进程名                    app.processName);            // 记录向 Zygote 请求前的耗时点            checkTime(startTime, "startProcess: asking zygote to start proc");            // 把进程配置交给 Process.start            Process.ProcessStartResult startResult = Process.start(entryPoint,                    // 传入进程名、uid、gid 和补充组                    app.processName, uid, uid, gids, debugFlags, mountExternal,                    // 传入 SDK、SELinux、ABI 与指令集信息                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,                    // 传入数据目录和入口参数                    app.info.dataDir, entryPointArgs);            // 记录 Zygote 返回后的耗时点            checkTime(startTime, "startProcess: returned from zygote!");            // 结束进程启动 trace            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

Process.start() 返回后,AMS 把这次创建的结果登记到 ProcessRecord:写入 pid 与 usingWrapper,清掉上一轮的 removed / killed 标记,然后把记录放进以 pid 为键的 mPidsSelfLocked。对 Activity 进程,AMS 还会延迟投递一条 PROC_START_TIMEOUT_MSG:超过时限仍未收到应用进程的 attachApplication(),就走 processStartTimedOutLocked() 收尾。第九节里 attachApplicationLocked() 能用 mPidsSelfLocked.get(pid) 取回记录,前提就是这里已经写入。
源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:3420。

java
// 代码位置 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 第 3420—3442 行            // 把 Zygote 返回的 pid 写入进程记录            app.setPid(startResult.pid);            // 记录本次是否经由 wrapper 启动            app.usingWrapper = startResult.usingWrapper;            // 清除上一轮的移除标记            app.removed = false;            // 清除上一轮的杀进程标记            app.killed = false;            // 清除上一轮被 AMS 杀掉的标记            app.killedByAm = false;            // 记录写入 pid 映射前的耗时点            checkTime(startTime, "startProcess: starting to update pids map");            // 加锁更新 pid 到进程记录的映射            synchronized (mPidsSelfLocked) {                // 以 pid 为键保存进程记录                this.mPidsSelfLocked.put(startResult.pid, app);                // 只有 Activity 进程才注册启动超时检查                if (isActivityProcess) {                    // 申请一条进程启动超时消息                    Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);                    // 把进程记录挂到消息上                    msg.obj = app;                    // 按是否使用 wrapper 选择超时时长后延迟投递                    mHandler.sendMessageDelayed(msg, startResult.usingWrapper                            // 使用 wrapper 时用较长的超时值                            ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);                // 结束超时检查分支                }            // 结束映射更新同步块            }            // 记录映射更新完成的耗时点            checkTime(startTime, "startProcess: done updating pids map");        // 捕获启动进程过程中的运行时异常        } catch (RuntimeException e) {            // 原注释说明这里的错误恢复还不够完善            // XXX do better error recovery.            // 启动失败时把 pid 清零            app.setPid(0);            // 记录该进程已结束            mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);            // 隔离进程需要撤销已登记的 uid            if (app.isolated) {                // 移除隔离进程的 uid 记录                mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);            // 结束隔离进程分支            }            // 打印启动进程失败日志            Slog.e(TAG, "Failure starting process " + app.processName, e);        // 结束异常处理        }

2.2 Process 组装 Zygote 参数

Process.startViaZygote() 把标量配置转成字符串参数。协议要求 --runtime-args、uid、gid 和 groups 位于前部,入口类 processClass 位于配置参数之后;默认 Activity 进程的入口类就是前面设置的 android.app.ActivityThread。
源码位置:frameworks/base/core/java/android/os/Process.java:615,startViaZygote()。

java
        // 对 Process 类加锁以串行访问 Zygote 连接        synchronized(Process.class) {            // 创建待发送的参数列表            ArrayList<String> argsForZygote = new ArrayList<String>();             // 原注释列出必须位于前部的参数            // --runtime-args, --setuid=, --setgid=,            // 原注释继续说明 setgroups 的顺序要求            // and --setgroups= must go first            // 声明后续参数属于运行时参数            argsForZygote.add("--runtime-args");            // 写入目标 uid            argsForZygote.add("--setuid=" + uid);            // 写入目标 gid            argsForZygote.add("--setgid=" + gid);            // 按调试标记决定是否启用 JNI 日志            if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {                // 添加 JNI 日志开关                argsForZygote.add("--enable-jni-logging");            // 结束 JNI 日志分支            }            // 按调试标记决定是否启用安全模式            if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {                // 添加安全模式开关                argsForZygote.add("--enable-safemode");            // 结束安全模式分支            }            // 按调试标记决定是否启用调试器            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {                // 添加调试器开关                argsForZygote.add("--enable-debugger");            // 结束调试器分支            }            // 按调试标记决定是否启用 CheckJNI            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {                // 添加 CheckJNI 开关                argsForZygote.add("--enable-checkjni");            // 结束 CheckJNI 分支            }            // 按调试标记决定是否启用 JIT            if ((debugFlags & Zygote.DEBUG_ENABLE_JIT) != 0) {                // 添加 JIT 开关                argsForZygote.add("--enable-jit");            // 结束 JIT 分支            }            // 处理默认外部存储挂载模式            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");            // 结束挂载模式分支            }            // 写入目标 SDK 版本            argsForZygote.add("--target-sdk-version=" + targetSdkVersion);             // 原注释说明补充组采用逗号分隔            // --setgroups is a comma-separated list            // 有补充组时拼接 setgroups 参数            if (gids != null && gids.length > 0) {                // 创建参数字符串构造器                StringBuilder sb = new StringBuilder();                // 写入参数名前缀                sb.append("--setgroups=");                 // 取得补充组数量                int sz = gids.length;                // 逐项追加组 id                for (int i = 0; i < sz; i++) {                    // 非首项前写入逗号                    if (i != 0) {                        // 追加分隔符                        sb.append(',');                    // 结束分隔符分支                    }                    // 追加当前组 id                    sb.append(gids[i]);                // 结束补充组循环                }                 // 把完整 setgroups 参数加入列表                argsForZygote.add(sb.toString());            // 结束补充组分支            }             // 有进程别名时写入 nice name            if (niceName != null) {                // 添加进程别名参数                argsForZygote.add("--nice-name=" + niceName);            // 结束进程别名分支            }             // 有 SELinux 信息时写入参数            if (seInfo != null) {                // 添加 SELinux 信息                argsForZygote.add("--seinfo=" + seInfo);            // 结束 SELinux 信息分支            }             // 有指令集信息时写入参数            if (instructionSet != null) {                // 添加指令集参数                argsForZygote.add("--instruction-set=" + instructionSet);            // 结束指令集分支            }             // 有应用数据目录时写入参数            if (appDataDir != null) {                // 添加应用数据目录参数                argsForZygote.add("--app-data-dir=" + appDataDir);            // 结束数据目录分支            }             // 把进程入口类加入参数列表            argsForZygote.add(processClass);             // 有附加参数时逐项加入列表            if (extraArgs != null) {                // 遍历附加参数                for (String arg : extraArgs) {                    // 加入当前附加参数                    argsForZygote.add(arg);                // 结束附加参数循环                }            // 结束附加参数分支            }             // 连接匹配 ABI 的 Zygote 并发送参数            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);        // 结束同步块        }

2.3 本地 socket 的连接与响应

Android 6.0 的 ZygoteState.connect() 创建 LocalSocket,以 LocalSocketAddress.Namespace.ABSTRACT 命名空间连接 zygote。这种本地 socket 按名称寻址,不使用 IP 和端口;连接建立后还会查询服务端支持的 ABI。
源码位置:frameworks/base/core/java/android/os/Process.java:389,Process.ZygoteState.connect()。

java
        // 定义连接指定 Zygote socket 的方法        public static ZygoteState connect(String socketAddress) throws IOException {            // 初始化服务端输入流            DataInputStream zygoteInputStream = null;            // 初始化服务端文本输出流            BufferedWriter zygoteWriter = null;            // 创建本地 socket            final LocalSocket zygoteSocket = new LocalSocket();             // 捕获连接和流初始化异常            try {                // 连接抽象命名空间中的 socket 名称                zygoteSocket.connect(new LocalSocketAddress(socketAddress,                        // 指定 ABSTRACT 命名空间                        LocalSocketAddress.Namespace.ABSTRACT));                 // 取得二进制输入流                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());                 // 取得带缓冲的文本输出流                zygoteWriter = new BufferedWriter(new OutputStreamWriter(                        // 指定底层输出流和缓冲大小                        zygoteSocket.getOutputStream()), 256);            // 连接失败时清理 socket            } catch (IOException ex) {                // 尝试关闭已创建的 socket                try {                    // 关闭 socket                    zygoteSocket.close();                // 忽略关闭阶段的异常                } catch (IOException ignore) {                // 结束关闭异常处理                }                 // 向调用方重新抛出连接异常                throw ex;            // 结束连接异常处理            }             // 通过已建立的连接查询 ABI 列表            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);            // 记录连接成功及支持的 ABI            Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);             // 封装 socket、输入输出流与 ABI 列表            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,                    // 按逗号拆分 ABI 字符串                    abiListString.split(","));        // 结束连接方法        }

zygoteSendArgsAndGetResult() 先发送参数数量,再以一行一个参数的格式写入内容。
它拒绝含换行符的参数,flush() 后同步读取 pid 和 usingWrapper。
父进程稍后写回的两个字段与这里的 readInt()、readBoolean()。
源码位置:frameworks/base/core/java/android/os/Process.java:537,zygoteSendArgsAndGetResult()。

java
    // 定义发送参数并读取启动结果的方法    private static ProcessStartResult zygoteSendArgsAndGetResult(            // 接收连接状态和参数列表            ZygoteState zygoteState, ArrayList<String> args)            // 声明 Zygote 启动失败异常            throws ZygoteStartFailedEx {        // 捕获 socket 读写异常        try {            /**             * 说明这份实现参考 ZygoteInit.readArgumentList()             * See com.android.internal.os.ZygoteInit.readArgumentList()             * 说明当前发给 zygote 进程的报文格式             * Presently the wire format to the zygote process is:             * 第一项是参数个数             * a) a count of arguments (argc, in essence)             * 第二项是数量与参数个数相同、以换行分隔的参数字符串             * b) a number of newline-separated argument strings equal to count             *             * 说明 zygote 读完参数后的回写内容             * After the zygote process reads these it will write the pid of             * 失败时写入负值             * the child or -1 on failure, followed by boolean to             * 并附带一个布尔值表示是否使用了 wrapper 进程             * indicate whether a wrapper process was used.             */            // 取得文本输出流            final BufferedWriter writer = zygoteState.writer;            // 取得二进制输入流            final DataInputStream inputStream = zygoteState.inputStream;             // 先写入参数数量            writer.write(Integer.toString(args.size()));            // 用换行结束数量字段            writer.newLine();             // 保存参数数量            int sz = args.size();            // 逐项发送参数            for (int i = 0; i < sz; i++) {                // 取得当前参数                String arg = args.get(i);                // 禁止参数内部包含换行符                if (arg.indexOf('\n') >= 0) {                    // 抛出协议格式异常                    throw new ZygoteStartFailedEx(                            // 给出换行符错误信息                            "embedded newlines not allowed");                // 结束参数校验分支                }                // 写入当前参数                writer.write(arg);                // 用换行结束当前参数                writer.newLine();            // 结束参数发送循环            }             // 把缓冲区内容发送到 Zygote            writer.flush();             // 创建启动结果对象            ProcessStartResult result = new ProcessStartResult();            // 同步读取 Zygote 返回的 pid            result.pid = inputStream.readInt();            // 负 pid 表示 fork 失败            if (result.pid < 0) {                // 抛出 fork 失败异常                throw new ZygoteStartFailedEx("fork() failed");            // 结束 pid 校验分支            }            // 读取是否使用 wrapper            result.usingWrapper = inputStream.readBoolean();            // 返回完整启动结果            return result;        // 处理 socket 读写异常        } catch (IOException ex) {            // 关闭失效的 Zygote 连接            zygoteState.close();            // 把读写异常包装为启动失败            throw new ZygoteStartFailedEx(ex);        // 结束异常处理        }    // 结束方法    }

AMS 发给 Zygote 的参数报文与回读的 pid

三、Zygote 侧的接收循环

ZygoteInit.main() 注册服务端 socket,完成启动期工作后进入 runSelectLoop()。registerZygoteSocket() 使用 init 放入环境变量 ANDROID_SOCKET_zygote 的文件描述符构造 LocalServerSocket;监听端并非在 Java 层重新绑定地址。
源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,main() 与 registerZygoteSocket()。

java
    // 定义 Zygote 的 Java 入口    public static void main(String argv[]) {        // 捕获 Zygote 主流程异常        try {            // 启用 DDMS 支持            RuntimeInit.enableDdms();            // 原注释说明开始记录 Zygote 初始化性能            // Start profiling the zygote initialization.            // 启动采样分析集成            SamplingProfilerIntegration.start();             // 默认不启动 system_server            boolean startSystemServer = false;            // 设置默认 socket 名称            String socketName = "zygote";            // 初始化 ABI 列表            String abiList = null;            // 解析命令行参数            for (int i = 1; i < argv.length; i++) {                // 识别启动 system_server 的参数                if ("start-system-server".equals(argv[i])) {                    // 标记需要启动 system_server                    startSystemServer = true;                // 识别 ABI 列表参数                } else if (argv[i].startsWith(ABI_LIST_ARG)) {                    // 截取 ABI 列表内容                    abiList = argv[i].substring(ABI_LIST_ARG.length());                // 识别 socket 名称参数                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {                    // 截取 socket 名称                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());                // 拒绝未知参数                } else {                    // 抛出未知参数异常                    throw new RuntimeException("Unknown command line argument: " + argv[i]);                // 结束参数类型分支                }            // 结束参数解析循环            }             // ABI 列表是必需参数            if (abiList == null) {                // 缺少 ABI 时终止启动                throw new RuntimeException("No ABI list supplied.");            // 结束 ABI 校验分支            }             // 注册 Zygote 服务端 socket            registerZygoteSocket(socketName);            // 省略启动期与本文无关的调用            ...            // 按参数决定是否创建 system_server            if (startSystemServer) {                // 启动 system_server                startSystemServer(abiList, socketName);            // 结束 system_server 分支            }             // 记录开始接收命令连接            Log.i(TAG, "Accepting command socket connections");            // 进入命令连接的轮询循环            runSelectLoop(abiList);             // 循环退出时关闭服务端 socket            closeServerSocket();        // 捕获用于转移 main 调用的异常        } catch (MethodAndArgsCaller caller) {            // 在精简后的调用栈上执行目标 main            caller.run();        // 捕获 Zygote 运行时异常        } catch (RuntimeException ex) {            // 记录 Zygote 退出原因            Log.e(TAG, "Zygote died with exception", ex);            // 关闭服务端 socket            closeServerSocket();            // 继续抛出运行时异常            throw ex;        // 结束主流程异常处理        }    // 结束 main 方法    }
java
    // 定义 Zygote socket 注册方法    private static void registerZygoteSocket(String socketName) {        // 尚未构造服务端对象时执行注册        if (sServerSocket == null) {            // 保存 init 传入的文件描述符数值            int fileDesc;            // 拼出环境变量完整名称            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;            // 读取并解析环境变量            try {                // 读取 socket 文件描述符字符串                String env = System.getenv(fullSocketName);                // 转成整数文件描述符                fileDesc = Integer.parseInt(env);            // 处理环境变量缺失或格式错误            } catch (RuntimeException ex) {                // 抛出 socket 配置异常                throw new RuntimeException(fullSocketName + " unset or invalid", ex);            // 结束环境变量异常处理            }             // 用文件描述符创建服务端 socket            try {                // 创建 Java 文件描述符对象                FileDescriptor fd = new FileDescriptor();                // 写入底层文件描述符数值                fd.setInt$(fileDesc);                // 包装成 LocalServerSocket                sServerSocket = new LocalServerSocket(fd);            // 处理服务端 socket 构造失败            } catch (IOException ex) {                // 抛出绑定本地 socket 的异常                throw new RuntimeException(                        // 附带文件描述符信息                        "Error binding to local socket '" + fileDesc + "'", ex);            // 结束服务端 socket 异常处理            }        // 结束空值检查        }    // 结束注册方法    }

runSelectLoop() 把监听 socket 和每条客户端连接的文件描述符一起交给 poll()。
索引 0 对应监听描述符,它就绪时接受新连接;其他位置就绪时,Zygote 调用对应连接的 ZygoteConnection.runOnce()。这种多路复用让一个 Zygote 服务多个进程创建请求。

源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,runSelectLoop()。

java
    // 定义 Zygote 命令轮询循环    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {        // 保存参与轮询的文件描述符        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();        // 保存文件描述符对应的客户端连接        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();         // 首项固定为服务端监听描述符        fds.add(sServerSocket.getFileDescriptor());        // 监听描述符没有客户端对象        peers.add(null);         // 持续接收和处理命令        while (true) {            // 按当前描述符数量创建 poll 数组            StructPollfd[] pollFds = new StructPollfd[fds.size()];            // 初始化每个 poll 项            for (int i = 0; i < pollFds.length; ++i) {                // 创建 poll 描述对象                pollFds[i] = new StructPollfd();                // 关联当前文件描述符                pollFds[i].fd = fds.get(i);                // 监听可读事件                pollFds[i].events = (short) POLLIN;            // 结束 poll 项初始化            }            // 等待文件描述符事件            try {                // 无限期阻塞直到事件到达                Os.poll(pollFds, -1);            // 处理 poll 系统调用失败            } catch (ErrnoException ex) {                // 把系统错误转换为运行时异常                throw new RuntimeException("poll failed", ex);            // 结束 poll 异常处理            }            // 从后向前处理可读描述符            for (int i = pollFds.length - 1; i >= 0; --i) {                // 跳过没有可读事件的描述符                if ((pollFds[i].revents & POLLIN) == 0) {                    // 继续检查下一个描述符                    continue;                // 结束可读事件判断                }                // 索引零表示监听 socket 收到连接                if (i == 0) {                    // 接受一个新的命令连接                    ZygoteConnection newPeer = acceptCommandPeer(abiList);                    // 保存客户端连接                    peers.add(newPeer);                    // 保存客户端文件描述符                    fds.add(newPeer.getFileDesciptor());                // 其余索引表示已有连接收到命令                } else {                    // 处理该连接上的一条命令                    boolean done = peers.get(i).runOnce();                    // 返回 true 时移除连接                    if (done) {                        // 移除客户端对象                        peers.remove(i);                        // 移除对应文件描述符                        fds.remove(i);                    // 结束连接移除分支                    }                // 结束描述符类型分支                }            // 结束事件处理循环            }        // 结束无限轮询        }    // 结束轮询方法    }

runOnce() 读取参数及附带文件描述符,解析安全策略和资源限制,然后调用 Zygote.forkAndSpecialize()。
解析失败会被记录,连接读到 EOF 或发生 I/O 异常时返回 true,通知轮询层移除连接。

源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java:132,runOnce()。

java
    // 处理当前连接上的一条命令    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {         // 声明原始参数数组        String args[];        // 初始化解析后的参数        Arguments parsedArgs = null;        // 声明随 socket 传入的文件描述符        FileDescriptor[] descriptors;         // 读取参数和附带描述符        try {            // 按协议读取参数列表            args = readArgumentList();            // 取得 ancillary 文件描述符            descriptors = mSocket.getAncillaryFileDescriptors();        // 处理命令 socket 读取失败        } catch (IOException ex) {            // 记录读取异常            Log.w(TAG, "IOException on command socket " + ex.getMessage());            // 关闭当前客户端 socket            closeSocket();            // 通知轮询层移除此连接            return true;        // 结束读取异常处理        }         // 空参数表示连接到达 EOF        if (args == null) {            // 原注释说明已到达 EOF            // EOF reached.            // 关闭当前客户端 socket            closeSocket();            // 通知轮询层移除此连接            return true;        // 结束 EOF 分支        }         // 初始化 fork 结果为失败值        int pid = -1;        // 初始化子进程侧管道描述符        FileDescriptor childPipeFd = null;        // 初始化服务端侧管道描述符        FileDescriptor serverPipeFd = null;         // 解析请求并执行 fork        try {            // 把字符串参数解析为结构化参数            parsedArgs = new Arguments(args);             // ABI 查询请求不创建进程            if (parsedArgs.abiListQuery) {                // 直接返回 ABI 查询结果                return handleAbiListQuery();            // 结束 ABI 查询分支            }             // 应用 uid 安全策略            applyUidSecurityPolicy(parsedArgs, peer);            // 应用 wrapper 安全策略            applyInvokeWithSecurityPolicy(parsedArgs, peer);             // 合并系统属性中的调试配置            applyDebuggerSystemProperty(parsedArgs);            // 合并系统属性中的 wrapper 配置            applyInvokeWithSystemProperty(parsedArgs);             // 初始化资源限制数组            int[][] rlimits = null;             // 请求包含资源限制时转换数组            if (parsedArgs.rlimits != null) {                // 转成 native 调用所需的二维数组                rlimits = parsedArgs.rlimits.toArray(intArray2d);            // 结束资源限制分支            }             // 使用 wrapper 时创建 pid 传递管道            if (parsedArgs.invokeWith != null) {                // 创建带 close-on-exec 标记的管道                FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);                // 保存子进程写端                childPipeFd = pipeFds[1];                // 保存服务端读端                serverPipeFd = pipeFds[0];                // 清除子进程写端的 close-on-exec 标记                Os.fcntlInt(childPipeFd, F_SETFD, 0);            // 结束 wrapper 管道分支            }             // 初始化 fork 后需关闭的描述符数组            int [] fdsToClose = { -1, -1 };             // 取得当前命令 socket 描述符            FileDescriptor fd = mSocket.getFileDescriptor();            // 描述符有效时加入关闭列表            if (fd != null) {                // 保存命令 socket 的整数描述符                fdsToClose[0] = fd.getInt$();            // 结束命令 socket 分支            }             // 取得 Zygote 服务端监听描述符            fd = ZygoteInit.getServerSocketFileDescriptor();            // 描述符有效时加入关闭列表            if (fd != null) {                // 保存监听 socket 的整数描述符                fdsToClose[1] = fd.getInt$();            // 结束监听 socket 分支            }             // 释放临时 Java 引用            fd = null;             // 调用 Zygote 执行 fork 和子进程专门化            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,                    // 传入调试、资源、挂载及安全参数                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,                    // 传入进程名、关闭列表、指令集和数据目录                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,                    // 传入应用数据目录                    parsedArgs.appDataDir);        // 处理管道创建等系统调用错误        } catch (ErrnoException ex) {            // 记录创建管道异常            logAndPrintError(newStderr, "Exception creating pipe", ex);        // 处理参数格式错误        } catch (IllegalArgumentException ex) {            // 记录非法 Zygote 参数            logAndPrintError(newStderr, "Invalid zygote arguments", ex);        // 处理违反 Zygote 安全策略的请求        } catch (ZygoteSecurityException ex) {            // 记录安全策略拒绝信息            logAndPrintError(newStderr,                    // 写入安全策略错误前缀及异常                    "Zygote security policy prevents request: ", ex);        // 结束请求解析异常处理        }         // 根据 fork 返回值进入父子进程分支        try {            // pid 为零表示当前执行流位于子进程            if (pid == 0) {                // 原注释标明子进程分支                // in child                // 子进程关闭服务端管道端                IoUtils.closeQuietly(serverPipeFd);                // 清除已关闭描述符引用                serverPipeFd = null;                // 进入子进程初始化流程                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);                 // 原注释说明正常情况下不会执行到这里                // should never get here, the child is expected to either                // 原注释列出异常转移或 exec 两种出口                // throw ZygoteInit.MethodAndArgsCaller or exec().                // 异常返回时关闭当前连接                return true;            // 非零 pid 进入父进程分支            } else {                // 原注释说明负 pid 表示失败                // in parent...pid of < 0 means failure                // 父进程关闭子进程管道端                IoUtils.closeQuietly(childPipeFd);                // 清除已关闭描述符引用                childPipeFd = null;                // 处理父进程结果并写回客户端                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);            // 结束父子进程分支            }        // 无论分支结果如何都清理管道        } finally {            // 关闭残留的子进程管道端            IoUtils.closeQuietly(childPipeFd);            // 关闭残留的服务端管道端            IoUtils.closeQuietly(serverPipeFd);        // 结束资源清理        }    // 结束单次命令处理    }

Zygote 的 accept 循环与 runOnce

四、进程fork

Java 层的 Zygote.forkAndSpecialize() 在 native 调用前执行 VM_HOOKS.preFork(),取得 pid 后执行 VM_HOOKS.postForkCommon()。子进程还会重新启用 trace。

源码位置:frameworks/base/core/java/com/android/internal/os/Zygote.java:89,forkAndSpecialize()。

java
    // 定义应用进程 fork 与专门化入口    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,          // 接收资源、挂载、安全和名称参数          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,          // 接收指令集与数据目录          String instructionSet, String appDataDir) {        // 在 fork 前暂停运行时相关线程和状态        VM_HOOKS.preFork();        // 调用 native 方法执行 fork 与专门化        int pid = nativeForkAndSpecialize(                  // 传递身份、调试、资源和挂载参数                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,                  // 传递指令集和数据目录                  instructionSet, appDataDir);        // 原注释要求尽快为子进程启用 trace        // Enable tracing as soon as possible for the child process.        // pid 为零时当前代码运行在子进程        if (pid == 0) {            // 为子进程打开 trace            Trace.setTracingEnabled(true);             // 原注释说明该事件在 handleChildProc 末尾结束            // Note that this event ends at the end of handleChildProc,            // 开始记录 PostFork 事件            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");        // 结束子进程 trace 分支        }        // 恢复父子进程共用的运行时状态        VM_HOOKS.postForkCommon();        // 返回 fork 结果        return pid;    // 结束 forkAndSpecialize    }     // 声明执行 native fork 的方法    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,          // 声明资源、挂载、安全和名称参数          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,          // 声明指令集与数据目录参数          String instructionSet, String appDataDir);

native 层的 ForkAndSpecializeCommon() 调用 Linux fork()。返回值为 0 时,当前执行流属于新子进程;返回值大于 0 时,当前执行流仍在 Zygote 父进程,数值就是子进程 pid。
子进程随后关闭继承但不应继续持有的描述符,设置补充组、资源限制、uid/gid、能力和调度策略,并处理模拟存储及进程组。

源码位置:frameworks/base/core/jni/com_android_internal_os_Zygote.cpp:443,ForkAndSpecializeCommon()。

cpp
// 说明该工具方法负责 fork 并专门化子进程// Utility routine to fork zygote and specialize the child process.// 定义 native fork 共用方法static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,                                     // 接收调试标志和资源限制                                     jint debug_flags, jobjectArray javaRlimits,                                     // 接收进程能力参数                                     jlong permittedCapabilities, jlong effectiveCapabilities,                                     // 接收外部存储挂载模式                                     jint mount_external,                                     // 接收 SELinux 信息和名称                                     jstring java_se_info, jstring java_se_name,                                     // 接收进程类型、关闭列表、指令集和数据目录                                     bool is_system_server, jintArray fdsToClose,                                     // 完成函数参数声明                                     jstring instructionSet, jstring dataDir) {  // 安装 SIGCHLD 处理器  SetSigChldHandler();   // 调用 Linux fork 创建子进程  pid_t pid = fork();   // 返回零时进入子进程专门化分支  if (pid == 0) {    // 原注释标明当前为子进程    // The child process.    // 标记当前进程为 Zygote 子进程    gMallocLeakZygoteChild = 1;     // 原注释说明立即关闭指定描述符    // Clean up any descriptors which must be closed immediately    // 关闭 fork 请求列出的文件描述符    DetachDescriptors(env, fdsToClose);     // 原注释说明非 root uid 变更时保留能力    // Keep capabilities across UID change, unless we're staying root.    // 目标 uid 非 root 时启用能力保留    if (uid != 0) {      // 设置 keep capabilities      EnableKeepCapabilities(env);    // 结束非 root 分支    }     // 丢弃能力边界集中的多余能力    DropCapabilitiesBoundingSet(env);     // 判断是否需要 native bridge    bool use_native_bridge = !is_system_server && (instructionSet != NULL)        // 同时要求 native bridge 可用        && android::NativeBridgeAvailable();     // 按 uid 和模式挂载模拟存储    if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) {      // 挂载失败时记录警告      ALOGW("Failed to mount emulated storage: %s", strerror(errno));    // 结束模拟存储挂载分支    }     // 普通应用进程需要创建进程组    if (!is_system_server) {        // 以 uid 和当前 pid 创建进程组        int rc = createProcessGroup(uid, getpid());        // 非零返回值表示创建失败        if (rc != 0) {            // 记录进程组创建错误            ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));        // 结束进程组错误分支        }    // 结束普通应用进程分支    }     // 设置补充组 id    SetGids(env, javaGids);     // 设置进程资源限制    SetRLimits(env, javaRlimits);     // 设置真实、有效和保存的 gid    int rc = setresgid(gid, gid, gid);    // gid 设置失败时中止运行时    if (rc == -1) {      // 记录 gid 设置错误      ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));      // 中止当前运行时      RuntimeAbort(env);    // 结束 gid 错误分支    }     // 设置真实、有效和保存的 uid    rc = setresuid(uid, uid, uid);    // uid 设置失败时中止运行时    if (rc == -1) {      // 记录 uid 设置错误      ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));      // 中止当前运行时      RuntimeAbort(env);    // 结束 uid 错误分支    }     // 设置允许与生效的进程能力    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);     // 设置进程调度策略    SetSchedulerPolicy(env);  // 结束子进程专门化分支  }  // 向 Java 层返回 fork 结果  return pid;// 结束 native 方法}

fork 采用写时复制(copy-on-write)。父子进程起初共享物理页,其中一个进程写入页面时,内核才为它创建副本。文件描述符也会随 fork 进入子进程的描述符表,但子进程不会继续使用所有继承资源,Zygote 的命令 socket 就属于需要关闭的一类。

五、fork 之后父子进程分道

runOnce() 根据 pid 选择 handleChildProc() 或 handleParentProc()。子进程关闭命令连接和服务端监听 socket,完成标准输入输出及进程名设置,然后进入 RuntimeInit.zygoteInit();配置了 invokeWith 时,wrapper 接管后续启动。父进程维护子进程组,处理 wrapper 上报的内部 pid,再把最终 pid 和 usingWrapper 写回命令 socket。源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java:716,handleChildProc()、handleParentProc()。

java
    // 定义子进程后续处理方法    private void handleChildProc(Arguments parsedArgs,            // 接收标准流描述符、wrapper 管道和错误输出            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)            // 声明控制流转移异常            throws ZygoteInit.MethodAndArgsCaller {        // 开始原始块注释        /**         * 说明 native 代码已关闭两个 Zygote socket 连接         * By the time we get here, the native code has closed the two actual Zygote         * 说明原描述符位置已替换为 /dev/null         * socket connections, and substituted /dev/null in their place.  The LocalSocket         * 说明 Java LocalSocket 对象仍需正确关闭         * objects still need to be closed properly.         */         // 关闭当前命令 LocalSocket 对象        closeSocket();        // 关闭子进程继承的服务端 socket 对象        ZygoteInit.closeServerSocket();         // 调用方传入标准流描述符时进行重定向        if (descriptors != null) {            // 捕获 dup2 系统调用错误            try {                // 把首个描述符复制到标准输入                Os.dup2(descriptors[0], STDIN_FILENO);                // 把第二个描述符复制到标准输出                Os.dup2(descriptors[1], STDOUT_FILENO);                // 把第三个描述符复制到标准错误                Os.dup2(descriptors[2], STDERR_FILENO);                 // 遍历原始标准流描述符                for (FileDescriptor fd: descriptors) {                    // 关闭复制后的原始描述符                    IoUtils.closeQuietly(fd);                // 结束描述符清理循环                }                // 更新错误输出对象                newStderr = System.err;            // 处理标准流重定向失败            } catch (ErrnoException ex) {                // 记录重开标准流异常                Log.e(TAG, "Error reopening stdio", ex);            // 结束重定向异常处理            }        // 结束标准流重定向分支        }         // 有 nice name 时设置进程 argv0        if (parsedArgs.niceName != null) {            // 更新进程显示名称            Process.setArgV0(parsedArgs.niceName);        // 结束进程名分支        }         // 原注释说明 PostFork trace 在此结束        // End of the postFork event.        // 结束 PostFork trace        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        // 配置 wrapper 时执行 wrapper 入口        if (parsedArgs.invokeWith != null) {            // 通过 wrapper 启动应用            WrapperInit.execApplication(parsedArgs.invokeWith,                    // 传入进程名和目标 SDK                    parsedArgs.niceName, parsedArgs.targetSdkVersion,                    // 传入当前指令集                    VMRuntime.getCurrentInstructionSet(),                    // 传入管道和剩余参数                    pipeFd, parsedArgs.remainingArgs);        // 默认路径进入 RuntimeInit        } else {            // 进入应用进程的 Zygote 初始化            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,                    // 原注释说明此处不指定 ClassLoader                    /* classLoader */                    // 传入剩余参数与空 ClassLoader                    parsedArgs.remainingArgs, null);        // 结束 wrapper 分支        }    // 结束子进程处理方法    }     // 定义父进程结果处理方法    private boolean handleParentProc(int pid,            // 接收附带描述符、wrapper 管道和解析参数            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {         // fork 成功时设置子进程组        if (pid > 0) {            // 调整子进程的进程组            setChildPgid(pid);        // 结束 pid 检查        }         // 清理父进程不再需要的附带描述符        if (descriptors != null) {            // 遍历附带描述符            for (FileDescriptor fd: descriptors) {                // 静默关闭当前描述符                IoUtils.closeQuietly(fd);            // 结束描述符清理循环            }        // 结束描述符清理分支        }         // 默认标记未使用 wrapper        boolean usingWrapper = false;        // wrapper 管道与有效 pid 同时存在时读取内部 pid        if (pipeFd != null && pid > 0) {            // 包装管道输入流            DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));            // 初始化 wrapper 上报的 pid            int innerPid = -1;            // 尝试读取内部 pid            try {                // 从管道读取 wrapper 创建的进程 pid                innerPid = is.readInt();            // 处理 pid 读取失败            } catch (IOException ex) {                // 记录 wrapper 子进程可能退出                Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);            // 确保输入流被关闭            } finally {                // 尝试关闭管道输入流                try {                    // 关闭输入流                    is.close();                // 忽略关闭阶段的异常                } catch (IOException ex) {                // 结束关闭异常处理                }            // 结束管道清理            }             // 原注释要求内部 pid 必须是 fork 子进程或其后代            // Ensure that the pid reported by the wrapped process is either the            // 原注释继续说明父子关系约束            // child process that we forked, or a descendant of it.            // wrapper 返回有效 pid 时核对父子关系            if (innerPid > 0) {                // 从内部 pid 开始向父进程回溯                int parentPid = innerPid;                // 直到找到原 fork pid 或到达根进程                while (parentPid > 0 && parentPid != pid) {                    // 查询当前进程的父 pid                    parentPid = Process.getParentPid(parentPid);                // 结束父链回溯                }                // 找到原 fork pid 表示关系有效                if (parentPid > 0) {                    // 记录 wrapper 的实际 pid                    Log.i(TAG, "Wrapped process has pid " + innerPid);                    // 用实际 pid 替换初始 fork pid                    pid = innerPid;                    // 标记使用了 wrapper                    usingWrapper = true;                // 父子关系不符时保留原 pid                } else {                    // 记录非法 wrapper pid                    Log.w(TAG, "Wrapped process reported a pid that is not a child of "                            // 附带初始 pid 和内部 pid                            + "the process that we forked: childPid=" + pid                            // 完成日志内容                            + " innerPid=" + innerPid);                // 结束父子关系判断                }            // 结束内部 pid 校验            }        // 结束 wrapper 处理分支        }         // 把 fork 结果写回命令 socket        try {            // 写回最终 pid            mSocketOutStream.writeInt(pid);            // 写回 wrapper 标记            mSocketOutStream.writeBoolean(usingWrapper);        // 处理结果写回失败        } catch (IOException ex) {            // 记录命令 socket 写入异常            Log.e(TAG, "Error writing to command socket", ex);            // 通知轮询层关闭连接            return true;        // 结束写回异常处理        }         // 保持连接并继续服务后续命令        return false;    // 结束父进程处理方法    }

子进程关闭 Zygote socket 明确了所有权边界:应用进程不再承担创建新进程的职责,但 fork 已把相关文件描述符复制到它的描述符表。
这些副本若未关闭,会延长底层资源的引用周期,还会让普通应用进程持有不需要的监听描述符。handleParentProc() 返回 false,Zygote 的服务循环继续处理请求。

fork 之后父子进程分道

六、建立 Binder 通信基础

RuntimeInit.zygoteInit() 的 native 初始化阶段会回调 AppRuntime::onZygoteInit()。这里通过 ProcessState::self() 取得进程级 Binder 状态,再启动 Binder 线程池。ProcessState::self() 内部负责建立 Binder 驱动连接;

源码位置:frameworks/base/cmds/app_process/app_main.cpp,AppRuntime::onZygoteInit()。

cpp
    // 覆盖 Zygote 子进程初始化回调    virtual void onZygoteInit()    // 开始回调方法体    {        // 取得当前进程的 Binder ProcessState        sp<ProcessState> proc = ProcessState::self();        // 记录启动 Binder 线程池        ALOGV("App process: starting thread pool.\n");        // 启动 Binder 线程池        proc->startThreadPool();    // 结束回调方法    }

app_process 的 native main() 还会构造 AppRuntime 并解析运行时选项。该进程已经从 Zygote 继承 ART 运行时状态,后续可以加载 Java 类。

源码位置:frameworks/base/cmds/app_process/app_main.cpp,main()。

cpp
    // 构造 AndroidRuntime 派生对象    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));    // 去掉程序名参数    argc--;    // 把参数指针移到首个业务参数    argv++;    // 省略与本文无关的中间代码    ...    // 声明参数循环索引    int i;    // 扫描 runtime 选项    for (i = 0; i < argc; i++) {        // 非短横线开头表示选项扫描结束        if (argv[i][0] != '-') {            // 跳出选项循环            break;        // 结束普通参数判断        }        // 单独的双短横线表示选项终止        if (argv[i][1] == '-' && argv[i][2] == 0) {            // 原注释说明跳过双短横线            // Skip --.            // 移到双短横线后的参数            ++i;            // 跳出选项循环            break;        // 结束选项终止判断        }        // 把当前参数加入运行时选项        runtime.addOption(strdup(argv[i]));    // 结束 runtime 选项循环    }

因此,ActivityThread.attach(false) 能直接取得 AMS 的 Binder 代理并发起 attachApplication()。进入应用 Java 主流程前,进程已经建立 Binder 通信所需的基础状态,不需要等到 Application 创建后再初始化。

进入 Java 层之前建立 Binder 通信基础

图 5 进入 Java 层之前建立 Binder 通信基础

七、进入 Java 层:zygoteInit 到 invokeStaticMain

RuntimeInit.applicationInit() 设置进程退出策略、堆利用率和目标 SDK,解析剩余参数后调用 invokeStaticMain()。

源码位置:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java:299,applicationInit()。

java
    // 定义应用进程 Java 初始化方法    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)            // 声明控制流转移异常            throws ZygoteInit.MethodAndArgsCaller {        // 设置退出时不执行常规清理        nativeSetExitWithoutCleanup(true);         // 设置目标堆利用率        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);        // 向运行时设置目标 SDK 版本        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);         // 声明解析后的运行参数        final Arguments args;        // 解析应用入口参数        try {            // 构造运行参数对象            args = new Arguments(argv);        // 处理非法参数        } catch (IllegalArgumentException ex) {            // 输出参数错误            Slog.e(TAG, ex.getMessage());            // 原注释说明让进程退出            // let the process exit            // 参数非法时返回            return;        // 结束参数异常处理        }         // 结束 ActivityManager 的启动 trace        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);         // 原注释说明剩余参数传给入口类的静态 main        // Remaining arguments are passed to the start class's static main        // 查找并转移到入口类 main 方法        invokeStaticMain(args.startClass, args.startArgs, classLoader);    // 结束应用初始化方法    }

invokeStaticMain() 通过 Class.forName() 加载入口类,查找 public static main(String[]),但没有在当前栈帧直接反射调用。它抛出 ZygoteInit.MethodAndArgsCaller,由 ZygoteInit.main() 的对应 catch 捕获并调用 caller.run()。这样,建立进程期间压入的中间栈帧会随着异常展开而清除,应用主入口从较干净的调用栈开始运行。

源码位置:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java:198,invokeStaticMain()。

java
    // 定义静态 main 查找方法    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)            // 声明控制流转移异常            throws ZygoteInit.MethodAndArgsCaller {        // 声明目标入口类        Class<?> cl;         // 尝试加载入口类        try {            // 初始化并加载指定类            cl = Class.forName(className, true, classLoader);        // 处理入口类不存在        } catch (ClassNotFoundException ex) {            // 包装为运行时异常            throw new RuntimeException(                    // 写入缺失类信息                    "Missing class when invoking static main " + className,                    // 附带原始异常                    ex);        // 结束类加载异常处理        }         // 声明 main 反射方法        Method m;        // 查找 main 方法        try {            // 获取接收字符串数组的公开 main            m = cl.getMethod("main", new Class[] { String[].class });        // 处理 main 方法不存在        } catch (NoSuchMethodException ex) {            // 包装为运行时异常            throw new RuntimeException(                    // 写入缺失 main 信息                    "Missing static main on " + className, ex);        // 处理反射安全检查失败        } catch (SecurityException ex) {            // 包装为运行时异常            throw new RuntimeException(                    // 写入获取 main 失败信息                    "Problem getting static main on " + className, ex);        // 结束方法查找异常处理        }         // 取得 main 方法修饰符        int modifiers = m.getModifiers();        // 要求 main 同时为 static 和 public        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {            // 修饰符不符时抛出异常            throw new RuntimeException(                    // 写入方法签名要求                    "Main method is not public and static on " + className);        // 结束修饰符校验        }         // 用专用异常把方法和参数带回 ZygoteInit.main        throw new ZygoteInit.MethodAndArgsCaller(m, argv);    // 结束静态 main 查找方法    }

MethodAndArgsCaller 同时是一个 Runnable,mMethod 就是上面 cl.getMethod("main", String[].class) 返回的 android.app.ActivityThread.main。
ZygoteInit.main() 捕获它之后执行 caller.run(),用反射进入 ActivityThread.main()。源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:711。

java
// 代码位置 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 第 711—739 行    // 定义携带目标方法与参数的异常类,同时实现 Runnable    public static class MethodAndArgsCaller extends Exception            // 实现 Runnable 接口            implements Runnable {        // 保存要调用的静态 main 方法        private final Method mMethod;         // 保存传给 main 方法的参数        private final String[] mArgs;         // 构造方法接收目标方法与参数        public MethodAndArgsCaller(Method method, String[] args) {            // 保存目标方法            mMethod = method;            // 保存调用参数            mArgs = args;        // 结束构造方法        }         // 实现 Runnable 的执行入口        public void run() {            // 捕获反射调用可能抛出的异常            try {                // 反射调用静态 main 方法                mMethod.invoke(null, new Object[] { mArgs });            // 处理访问权限异常            } catch (IllegalAccessException ex) {                // 包装为运行时异常抛出                throw new RuntimeException(ex);            // 处理目标方法内部抛出的异常            } catch (InvocationTargetException ex) {                // 取出目标方法真正抛出的原因                Throwable cause = ex.getCause();                // 原因本身是运行时异常时直接抛出                if (cause instanceof RuntimeException) {                    // 抛出原始运行时异常                    throw (RuntimeException) cause;                // 原因是 Error 时直接抛出                } else if (cause instanceof Error) {                    // 抛出原始 Error                    throw (Error) cause;                // 结束原因类型判断                }                // 其余情况包装为运行时异常                throw new RuntimeException(ex);            // 结束反射调用异常处理            }        // 结束 run 方法        }    // 结束 MethodAndArgsCaller 类    }

八、ActivityThread.main:应用进程的 Java 主入口

默认入口类是 android.app.ActivityThread。其 main() 完成进程级环境初始化,准备主线程 Looper,创建 ActivityThread 并执行 attach(false),最后进入 Looper.loop()。

源码位置:frameworks/base/core/java/android/app/ActivityThread.java:5379,main()。

java
    // 定义应用进程 Java 主入口    public static void main(String[] args) {        // 开始记录 ActivityThread 主流程 trace        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");        // 启动采样分析集成        SamplingProfilerIntegration.start();         // 关闭 CloseGuard 检查        CloseGuard.setEnabled(false);         // 初始化当前用户环境        Environment.initForCurrentUser();         // 安装事件日志报告器        EventLogger.setReporter(new EventLoggingReporter());         // 安装 AndroidKeyStore Provider        AndroidKeyStoreProvider.install();         // 取得当前用户配置目录        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());        // 设置可信证书存储的用户目录        TrustedCertificateStore.setDefaultUserDirectory(configDir);         // 设置进程初始化阶段的 argv0        Process.setArgV0("<pre-initialized>");         // 为主线程准备 Looper        Looper.prepareMainLooper();         // 创建 ActivityThread 实例        ActivityThread thread = new ActivityThread();        // 以普通应用进程身份连接 AMS        thread.attach(false);         // 尚未缓存主线程 Handler 时进行初始化        if (sMainThreadHandler == null) {            // 保存 ActivityThread 的 Handler            sMainThreadHandler = thread.getHandler();        // 结束 Handler 初始化分支        }         // 结束 ActivityThread 主流程 trace        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        // 进入主线程消息循环        Looper.loop();         // 消息循环意外退出时终止进程        throw new RuntimeException("Main thread loop unexpectedly exited");    // 结束 main 方法    }

attach(false) 把 mAppThread 交给 AMS。mAppThread 的类型是 ApplicationThread,它经由 ApplicationThreadNative 实现 IApplicationThread.Stub,因此 AMS 此后可以通过这个 Binder 接口反向调用应用进程。

源码位置:frameworks/base/core/java/android/app/ActivityThread.java:5230,attach()。

java
    // 定义 ActivityThread 与系统服务的绑定方法    private void attach(boolean system) {        // 保存当前 ActivityThread        sCurrentActivityThread = this;        // 记录是否为系统进程        mSystemThread = system;        // 普通应用进程执行 AMS 注册流程        if (!system) {            // 注册首次绘制回调            ViewRootImpl.addFirstDrawHandler(new Runnable() {                // 覆盖回调方法                @Override                // 定义首次绘制时执行的逻辑                public void run() {                    // 确保 JIT 已启用                    ensureJitEnabled();                // 结束回调方法                }            // 完成首次绘制回调注册            });            // 设置 DDMS 中的预初始化应用名            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",                                                    // 指定当前用户 id                                                    UserHandle.myUserId());            // 向 RuntimeInit 注册应用线程 Binder            RuntimeInit.setApplicationObject(mAppThread.asBinder());            // 获取 AMS 的 IActivityManager 代理            final IActivityManager mgr = ActivityManagerNative.getDefault();            // 发起应用进程注册            try {                // 把应用线程 Binder 交给 AMS                mgr.attachApplication(mAppThread);            // 处理 AMS 远程调用失败            } catch (RemoteException ex) {                // 原注释说明忽略该异常                // Ignore            // 结束远程异常处理            }        // 系统进程进入另一条初始化路径        } else {            // 省略系统进程分支            ...        // 结束进程类型分支        }    // 结束 attach 方法    }

这次调用把新进程的应用线程接口注册到 AMS。AMS 在此前仅拿到 Zygote 返回的 pid;收到 attachApplication() 后,它才得到可调用的 IApplicationThread。

九、AMS 绑定 Application 后启动 Activity

9.1 关联 ProcessRecord 与 ApplicationThread

AMS 根据 Binder 调用者 pid 从 mPidsSelfLocked 取回 ProcessRecord,该记录在启动请求阶段已经按 pid 放入映射。没有对应的等待绑定记录时,AMS 会丢弃这个进程。记录中已有线程时,AMS 先按旧进程死亡处理。随后,AMS 注册 Binder 死亡通知,并通过 app.makeActive() 保存新的 IApplicationThread。

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:6017,attachApplicationLocked()。

java
        // 声明待绑定的进程记录        ProcessRecord app;        // 排除 system_server 自身及无效 pid        if (pid != MY_PID && pid >= 0) {            // 在 pid 映射锁内查询记录            synchronized (mPidsSelfLocked) {                // 按 pid 取得等待绑定的进程记录                app = mPidsSelfLocked.get(pid);            // 结束 pid 映射同步块            }        // system_server 或无效 pid 不关联应用记录        } else {            // 设置为空记录            app = null;        // 结束 pid 类型分支        }         // 找不到待绑定记录时丢弃进程        if (app == null) {            // 记录没有待处理进程记录            Slog.w(TAG, "No pending application record for pid " + pid                    // 附带应用线程 Binder 信息                    + " (IApplicationThread " + thread + "); dropping process");            // 写入进程丢弃事件            EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);            // 外部有效进程采用 kill 处理            if (pid > 0 && pid != MY_PID) {                // 静默终止目标 pid                Process.killProcessQuiet(pid);            // 其余情况通知应用线程退出            } else {                // 捕获退出调度异常                try {                    // 请求应用线程退出                    thread.scheduleExit();                // 原注释说明忽略异常                } catch (Exception e) {                    // Ignore exceptions.                // 结束退出异常处理                }            // 结束丢弃方式分支            }            // 返回绑定失败            return false;        // 结束空记录分支        }         // 进程记录已绑定线程时处理旧进程死亡        if (app.thread != null) {            // 清理旧的应用进程状态            handleAppDiedLocked(app, true, true);        // 结束旧线程分支        }         // 保存进程名供失败重启使用        final String processName = app.processName;        // 注册 Binder 死亡通知        try {            // 创建应用进程死亡接收器            AppDeathRecipient adr = new AppDeathRecipient(                    // 传入进程记录、pid 和线程接口                    app, pid, thread);            // 把死亡接收器链接到应用线程 Binder            thread.asBinder().linkToDeath(adr, 0);            // 在进程记录中保存死亡接收器            app.deathRecipient = adr;        // 处理 Binder 已经死亡        } catch (RemoteException e) {            // 重置进程包列表            app.resetPackageList(mProcessStats);            // 因链接失败重新启动进程            startProcessLocked(app, "link fail", processName);            // 返回绑定失败            return false;        // 结束死亡通知注册        }         // 记录进程完成绑定事件        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);         // 把 IApplicationThread 设为活动线程        app.makeActive(thread, mProcessStats);        // 临时设置进程 oom 调整值        app.curAdj = app.setAdj = -100;        // 设置默认调度组        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;        // 清除强制前台来源        app.forcingToForeground = null;        // 更新进程前台状态        updateProcessForegroundLocked(app, false, false);        // 清除已显示界面标记        app.hasShownUi = false;        // 清除调试状态        app.debugging = false;

9.2 bindApplication 先于 Activity 启动

AMS 调用 thread.bindApplication(),把 ApplicationInfo、provider、Instrumentation、配置和系统服务等进程初始化数据发送给应用进程。

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:6150,attachApplicationLocked()。

java
            // 请求应用进程绑定 Application            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,                    // 传入性能分析及 Instrumentation 参数                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,                    // 传入自动化连接、测试模式和 OpenGL trace 配置                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,                    // 传入备份、持久化和当前配置                    isRestrictedBackupMode || !normalMode, app.persistent,                    // 复制当前 Configuration 并传入兼容信息                    new Configuration(mConfiguration), app.compat,                    // 传入公共系统服务与核心设置                    getCommonServicesLocked(app.isolated),                    // 取得并传入核心设置                    mCoreSettingsObserver.getCoreSettingsLocked());

bindApplication() 在 IApplicationThread 里是 oneway(异步) 调用。AMS 侧由 ApplicationThreadNative.bindApplication() 以 IBinder.FLAG_ONEWAY 发出事务,不等应用进程处理结果;
应用进程侧的实现只是把绑定数据打包成 AppBindData,再用 sendMessage(H.BIND_APPLICATION, data) 投递给主线程就返回。AMS 在这次调用返回后,仍在 attachApplicationLocked() 的同一个同步块里调用 mStackSupervisor.attachApplicationLocked(app),随后到达 realStartActivityLocked();scheduleLaunchActivity() 同样是 oneway,只把 ActivityClientRecord 投递到应用进程的主线程消息队列。

因此 Application 先于 Activity 创建,靠的不是 AMS 阻塞等待,而是两条消息的入队顺序:H.BIND_APPLICATION 先于 H.LAUNCH_ACTIVITY 进入应用进程同一个主线程 Handler 队列,主线程按顺序处理,handleBindApplication() 里创建 Application 并执行 onCreate() 的动作先完成。应用进程侧确实存在一次同步等待,但等的是它自己发出的 IActivityManager.attachApplication(mAppThread):这次调用不是 oneway,主线程要等 AMS 的 attachApplicationLocked() 跑完才从 attach(false) 返回,之后才进入 Looper.loop() 消费队列。

源码位置:frameworks/base/core/java/android/app/ApplicationThreadNative.java:1025。

连接 bindApplication 与 realStartActivityLocked 的是 ActivityStackSupervisor.attachApplicationLocked(ProcessRecord app):它按 app.uid 与 processName 在前台任务栈里查找顶部记录,命中条件是 hr.app == null,也就是第一节里因进程不存在而被搁置的那个 ActivityRecord。

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java:610。

java
// 代码位置 frameworks/base/core/java/com/android/server/am/ActivityStackSupervisor.java 第 610—641 行    // 定义新进程绑定后尝试启动等待中顶部 Activity 的方法    boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {        // 记录新进程的进程名        final String processName = app.processName;        // 记录是否触发了启动动作        boolean didSomething = false;        // 从后向前遍历所有显示屏        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {            // 取得当前显示屏的任务栈列表            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;            // 从后向前遍历任务栈            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {                // 取得当前任务栈                final ActivityStack stack = stacks.get(stackNdx);                // 只处理前台任务栈                if (!isFrontStack(stack)) {                    // 跳过非前台任务栈                    continue;                // 结束前台判断                }                // 取得栈顶正在运行的 Activity 记录                ActivityRecord hr = stack.topRunningActivityLocked(null);                // 栈顶记录存在时判断它是否在等待当前新进程                if (hr != null) {                    // 栈顶 Activity 未绑定进程,且 uid 与进程名都匹配                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid                            // 继续匹配进程名                            && processName.equals(hr.processName)) {                        // 捕获启动过程中的远程调用异常                        try {                            // 在这个新进程里真正启动该 Activity                            if (realStartActivityLocked(hr, app, true, true)) {                                // 标记已触发启动动作                                didSomething = true;                            // 结束启动结果判断                            }                        // 处理启动失败的远程异常                        } catch (RemoteException e) {                            // 记录新进程启动 Activity 的异常                            Slog.w(TAG, "Exception in new application when starting activity "                                  // 附带目标组件描述                                  + hr.intent.getComponent().flattenToShortString(), e);                            // 继续向上抛出异常                            throw e;                        // 结束异常处理                        }                    // 结束进程匹配判断                    }                // 结束栈顶记录判断                }            // 结束任务栈遍历            }        // 结束显示屏遍历        }        // 没有触发任何启动动作时刷新可见性状态        if (!didSomething) {            // 重新计算所有任务栈可见性            ensureActivitiesVisibleLocked(null, 0);        // 结束兜底刷新分支        }        // 返回是否触发了启动动作        return didSomething;    // 结束方法    }
java
            // 需要恢复 Activity 时更新界面状态            if (andResume) {                // 标记进程已经显示界面                app.hasShownUi = true;                // 标记需要清理待处理界面状态                app.pendingUiClean = true;            // 结束恢复状态分支            }            // 把进程状态提升到顶部进程要求            app.forceProcessStateUpTo(mService.mTopProcessState);            // 通过应用线程调度 Activity 启动            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,                    // 传入 Activity 标识、信息和全局配置                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),                    // 传入栈覆盖配置、兼容信息和来源包                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,                    // 传入语音交互、进程状态及保存状态                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,                    // 传入新 Intent、暂停标记、转场方向和 profiler                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

Zygote 负责创建进程,ActivityThread 负责向 AMS 注册应用线程;AMS 依次投递 bindApplication() 与 scheduleLaunchActivity(),应用主线程按消息入队顺序完成 Application 初始化和 Activity 启动。

新进程与 AMS 的双向 Binder 绑定及 Application 回调

图 6 新进程与 AMS 的双向 Binder 绑定及 Application 回调

十、Application 的创建与绑定

10.1 LoadedApk.makeApplication

应用进程收到 bindApplication() 后,ActivityThread.handleBindApplication() 取得 LoadedApk。它通过 ContextImpl.createAppContext() 创建应用 Context,随后调用 LoadedApk.makeApplication()。mApplication 非空时直接复用,因此同一进程中的 Application 只创建一次;应用声明多个进程时,各进程有各自的 LoadedApk 与 Application 实例。

makeApplication() 选择 manifest 声明的 Application 类,未声明或强制使用默认类时采用 android.app.Application。它取得 ClassLoader,创建 ContextImpl,再由 Instrumentation.newApplication() 实例化 Application。完成外层 Context 关联后,Instrumentation.callApplicationOnCreate() 调用 Application 的 onCreate()。

源码位置:frameworks/base/core/java/android/app/LoadedApk.java:554,makeApplication()。

java
    // 定义 Application 创建方法    public Application makeApplication(boolean forceDefaultAppClass,            // 接收负责创建与回调的 Instrumentation            Instrumentation instrumentation) {        // 已创建 Application 时直接复用        if (mApplication != null) {            // 返回当前进程已有的 Application            return mApplication;        // 结束复用分支        }         // 初始化 Application 引用        Application app = null;         // 读取 manifest 中的 Application 类名        String appClass = mApplicationInfo.className;        // 强制默认类或未声明类名时采用框架 Application        if (forceDefaultAppClass || (appClass == null)) {            // 设置默认 Application 类名            appClass = "android.app.Application";        // 结束 Application 类选择        }         // 创建 Application 实例        try {            // 取得当前 LoadedApk 的 ClassLoader            java.lang.ClassLoader cl = getClassLoader();            // 非 framework 包初始化线程上下文 ClassLoader            if (!mPackageName.equals("android")) {                // 初始化 Java context ClassLoader                initializeJavaContextClassLoader();            // 结束 framework 包判断            }            // 为应用创建 ContextImpl            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);            // 通过 Instrumentation 实例化 Application            app = mActivityThread.mInstrumentation.newApplication(                    // 传入 ClassLoader、类名和 Context                    cl, appClass, appContext);            // 把 Application 设为 ContextImpl 的外层对象            appContext.setOuterContext(app);        // 处理 Application 创建异常        } catch (Exception e) {            // 交给 Instrumentation 判断是否已处理异常            if (!mActivityThread.mInstrumentation.onException(app, e)) {                // 未处理时抛出运行时异常                throw new RuntimeException(                    // 写入 Application 类名                    "Unable to instantiate application " + appClass                    // 附带原始异常信息                    + ": " + e.toString(), e);            // 结束异常接管判断            }        // 结束 Application 创建异常处理        }        // 加入当前 ActivityThread 的 Application 列表        mActivityThread.mAllApplications.add(app);        // 缓存当前进程的 Application        mApplication = app;         // Instrumentation 存在时回调 Application.onCreate        if (instrumentation != null) {            // 调用 Application 生命周期方法            try {                // 通过 Instrumentation 调用 onCreate                instrumentation.callApplicationOnCreate(app);            // 处理 onCreate 异常            } catch (Exception e) {                // 交给 Instrumentation 判断是否已处理异常                if (!instrumentation.onException(app, e)) {                    // 未处理时抛出运行时异常                    throw new RuntimeException(                        // 写入 Application 实际类名                        "Unable to create application " + app.getClass().getName()                        // 附带原始异常信息                        + ": " + e.toString(), e);                // 结束异常接管判断                }            // 结束 onCreate 异常处理            }        // 结束 Instrumentation 分支        }         // 原注释说明为所有库 APK 重写 R 常量        // Rewrite the R 'constants' for all library apks.        // 取得资源中的包标识映射        SparseArray<String> packageIdentifiers = getAssets(mActivityThread)                // 读取已分配的包标识                .getAssignedPackageIdentifiers();        // 保存包标识数量        final int N = packageIdentifiers.size();        // 遍历包标识        for (int i = 0; i < N; i++) {            // 取得当前资源包 id            final int id = packageIdentifiers.keyAt(i);            // 跳过 framework 与应用自身资源 id            if (id == 0x01 || id == 0x7f) {                // 继续处理下一个包                continue;            // 结束保留 id 判断            }            // 用当前 ClassLoader 重写库 R 值            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);        // 结束资源包循环        }         // 返回创建并缓存的 Application        return app;    // 结束 makeApplication    }

9.2 Context 代理链

ContextImpl.createAppContext() 以 ActivityThread 和 LoadedApk 构造应用 Context。

源码位置:frameworks/base/core/java/android/app/ContextImpl.java:1783,createAppContext()。

java
    // 定义应用 Context 创建方法    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {        // LoadedApk 为空时拒绝创建        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");        // 构造应用级 ContextImpl        return new ContextImpl(null, mainThread,                // 传入 LoadedApk 及其余应用 Context 参数                packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);    // 结束 Context 创建方法    }

Instrumentation.newApplication() 实例化 Application 后会调用 Application.attach()。attachBaseContext() 先把 ContextImpl 放入继承自 ContextWrapper 的 mBase,随后 Application 保存 LoadedApk。
源码位置:frameworks/base/core/java/android/app/Application.java:186,attach()。

Instrumentation.newApplication() 先反射实例化 Application,紧接着调用 app.attach(context),然后才把实例返回给 makeApplication(),因此后面紧跟的 appContext.setOuterContext(app) 发生在 attachBaseContext() 之后。
源码位置:frameworks/base/core/java/android/app/Instrumentation.java:993。

java
    // 定义包内可见的 Application 绑定方法    /* package */ final void attach(Context context) {        // 把 ContextImpl 绑定为基础 Context        attachBaseContext(context);        // 从 ContextImpl 中保存 LoadedApk        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;    // 结束 Application 绑定方法    }

Application 的 Context 调用沿代理链转发。ContextWrapper.getResources() 调用 mBase.getResources(),最终由 ContextImpl.getResources() 返回 mResources。

源码位置:frameworks/base/core/java/android/content/ContextWrapper.java:85,getResources();frameworks/base/core/java/android/app/ContextImpl.java:202,getResources()。

java
    // 原注释标明以下代码来自 ContextWrapper.java 第 85 至 88 行    // ContextWrapper.java 第 85–88 行    // 覆盖 Context 的资源获取方法    @Override    // 定义资源获取方法    public Resources getResources()    // 开始方法体    {        // 转发到基础 Context        return mBase.getResources();    // 结束方法    }
java
    // 原注释标明以下代码来自 ContextImpl.java 第 202 至 205 行    // ContextImpl.java 第 202–205 行    // 覆盖 Context 的资源获取方法    @Override    // 定义资源获取方法    public Resources getResources() {        // 返回 ContextImpl 保存的 Resources        return mResources;    // 结束方法    }

构造函数执行期间,attach() 尚未把 ContextImpl 设为 mBase,所以从 Application 构造函数调用 getResources() 得不到已经绑定的资源;到了 onCreate(),attach() 已经完成,资源代理链才具备有效基础 Context。
这里的调用关系是 Application(继承 ContextWrapper)→ mBase(ContextImpl)→ mResources,ContextImpl 又持有与包和资源管理相关的 LoadedApk 信息。

Application、Context、Resources 与 ClassLoader 的代理关系

图 7 Application、Context、Resources 与 ClassLoader 的代理关系

十一、ClassLoader 与 APK 路径

Android 6.0 的 LoadedApk.getClassLoader() 分别组装类路径和 native 库路径。zipPaths 包含主 APK、split APK 及共享库,libPaths 包含应用 native 库目录,并可追加各 APK 内当前 ABI 对应的 !/lib/<abi> 路径。

源码位置:frameworks/base/core/java/android/app/LoadedApk.java:288、:353,getClassLoader()。

java
                // 把主 APK 加入类路径                zipPaths.add(mAppDir);                // 存在 split APK 时加入全部 split 路径                if (mSplitAppDirs != null) {                    // 批量加入 split APK 路径                    Collections.addAll(zipPaths, mSplitAppDirs);                // 结束 split APK 分支                }                 // 把应用 native 库目录加入库路径                libPaths.add(mLibDir);
java
                // 用系统路径分隔符拼接类路径                final String zip = TextUtils.join(File.pathSeparator, zipPaths);                 // 原注释说明加入当前 ABI 的 APK 内库路径                // Add path to libraries in apk for current abi                // 主 ABI 存在时扫描所有 APK                if (mApplicationInfo.primaryCpuAbi != null) {                    // 遍历 APK 路径                    for (String apk : apkPaths) {                        // 加入 APK 内当前 ABI 的库目录                        libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);                    // 结束 APK 路径循环                    }                // 结束主 ABI 分支                }                 // 用系统路径分隔符拼接 native 库路径                final String lib = TextUtils.join(File.pathSeparator, libPaths);                 // 调试日志打开时输出类路径与 JNI 路径                if (ActivityThread.localLOGV)                    // 记录 ClassLoader 路径                    Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + lib);                 // 临时放宽线程磁盘读取策略                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();                 // 以类路径、库路径和父加载器取得 ClassLoader                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,                        // 指定基础 ClassLoader                        mBaseClassLoader);                 // 恢复原线程磁盘访问策略                StrictMode.setThreadPolicy(oldPolicy);

传给 ApplicationLoaders.getDefault().getClassLoader() 的 zip 决定 ClassLoader 可搜索的类定义范围,lib 提供 native 库搜索路径。

十二、小结

Activity 启动请求到应用界面获得调度七个阶段依次为:

  1. ActivityStackSupervisor 按进程名和 uid 查询 ProcessRecord。目标进程及 app.thread 不可用时,AMS 调用 startProcessLocked()。
  2. AMS 把 uid、gid、补充组、目标 SDK、进程名、ABI 和入口类等配置交给 Process.start();Process 通过本地 socket 发给 Zygote,并同步等待 pid。
  3. Zygote 的 runSelectLoop() 接收连接,ZygoteConnection.runOnce() 解析请求,native 层调用 fork()。父进程返回 pid,子进程完成身份、描述符和运行环境的专门化。
  4. 子进程进入 RuntimeInit.zygoteInit(),AppRuntime::onZygoteInit() 初始化 Binder ProcessState 并启动线程池。
  5. RuntimeInit.invokeStaticMain() 通过 MethodAndArgsCaller 把控制权转移到 ActivityThread.main();主线程准备 Looper 后调用 attach(false)。
  6. 应用进程把 IApplicationThread 交给 AMS。AMS 关联 ProcessRecord,调用 bindApplication();应用进程据此创建 ContextImpl、ClassLoader 和 Application,并执行 Application.onCreate()。
  7. AMS 经 realStartActivityLocked() 发出 scheduleLaunchActivity() 的 oneway 事务;对应的 H.LAUNCH_ACTIVITY 排在 H.BIND_APPLICATION 之后,由应用主线程按顺序处理。

12.1 可执行的验证入口

以下命令可以对照进程、AMS 记录和事件日志。不同 Android 版本的 ps、dumpsys 输出字段可能有差异,命令中的包名、进程名和 Activity 需要替换为实际值。

bash
# 查看目标进程及其父进程adb shell ps -A | grep <包名或进程名># 查看 AMS 保存的进程记录、oom_adj 与绑定状态adb shell dumpsys activity processes | grep -A 20 <包名># 查看 AMS 记录的进程启动事件adb logcat -b events | grep -i am_proc_start# 查看 Zygote 与 ActivityManager 日志adb logcat -s Zygote ActivityManager# 手动拉起 Activity 并观察上述输出变化adb shell am start -n <包名>/<Activity 全类名>

本文由 AgentWorkFlow 生成

觉得不错?给作者点个赞吧

分类:Android系统

评论 (0)

无需注册,留言经站长审核后公开。

加载评论中…

Android-Framework(十五)-进程的 fork 创建过程 · Yinchen 的博客