文章内容
- 一、启动 Activity 时,进程不存在会发生什么
- 二、AMS 将创建请求发给 Zygote
- 2.1 AMS 准备进程参数
- 2.2 Process 组装 Zygote 参数
- 2.3 本地 socket 的连接与响应
- 三、Zygote 侧的接收循环
- 四、进程fork
- 五、fork 之后父子进程分道
- 六、建立 Binder 通信基础
- 七、进入 Java 层:zygoteInit 到 invokeStaticMain
- 八、ActivityThread.main:应用进程的 Java 主入口
- 九、AMS 绑定 Application 后启动 Activity
- 9.1 关联 ProcessRecord 与 ApplicationThread
- 9.2 bindApplication 先于 Activity 启动
- 十、Application 的创建与绑定
- 10.1 LoadedApk.makeApplication
- 9.2 Context 代理链
- 十一、ClassLoader 与 APK 路径
- 十二、小结
- 12.1 可执行的验证入口

一、启动 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 指定其他进程名,所以查询键不一定与包名相同。
// 定义启动指定 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()。
// 优先采用调用方覆盖的 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。
// 代码位置 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()。
// 对 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()。
// 定义连接指定 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()。
// 定义发送参数并读取启动结果的方法 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); // 结束异常处理 } // 结束方法 }
三、Zygote 侧的接收循环
ZygoteInit.main() 注册服务端 socket,完成启动期工作后进入 runSelectLoop()。registerZygoteSocket() 使用 init 放入环境变量 ANDROID_SOCKET_zygote 的文件描述符构造 LocalServerSocket;监听端并非在 Java 层重新绑定地址。
源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,main() 与 registerZygoteSocket()。
// 定义 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 方法 } // 定义 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()。
// 定义 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()。
// 处理当前连接上的一条命令 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); // 结束资源清理 } // 结束单次命令处理 }
四、进程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()。
// 定义应用进程 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()。
// 说明该工具方法负责 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()。
// 定义子进程后续处理方法 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 的服务循环继续处理请求。

六、建立 Binder 通信基础
RuntimeInit.zygoteInit() 的 native 初始化阶段会回调 AppRuntime::onZygoteInit()。这里通过 ProcessState::self() 取得进程级 Binder 状态,再启动 Binder 线程池。ProcessState::self() 内部负责建立 Binder 驱动连接;
源码位置:frameworks/base/cmds/app_process/app_main.cpp,AppRuntime::onZygoteInit()。
// 覆盖 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()。
// 构造 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 创建后再初始化。

图 5 进入 Java 层之前建立 Binder 通信基础
七、进入 Java 层:zygoteInit 到 invokeStaticMain
RuntimeInit.applicationInit() 设置进程退出策略、堆利用率和目标 SDK,解析剩余参数后调用 invokeStaticMain()。
源码位置:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java:299,applicationInit()。
// 定义应用进程 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()。
// 定义静态 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。
// 代码位置 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 主入口 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()。
// 定义 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()。
// 声明待绑定的进程记录 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()。
// 请求应用进程绑定 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。
// 代码位置 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; // 结束方法 } // 需要恢复 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 启动。

图 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()。
// 定义 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()。
// 定义应用 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。
// 定义包内可见的 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()。
// 原注释标明以下代码来自 ContextWrapper.java 第 85 至 88 行 // ContextWrapper.java 第 85–88 行 // 覆盖 Context 的资源获取方法 @Override // 定义资源获取方法 public Resources getResources() // 开始方法体 { // 转发到基础 Context return mBase.getResources(); // 结束方法 } // 原注释标明以下代码来自 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 信息。

图 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()。
// 把主 APK 加入类路径 zipPaths.add(mAppDir); // 存在 split APK 时加入全部 split 路径 if (mSplitAppDirs != null) { // 批量加入 split APK 路径 Collections.addAll(zipPaths, mSplitAppDirs); // 结束 split APK 分支 } // 把应用 native 库目录加入库路径 libPaths.add(mLibDir); // 用系统路径分隔符拼接类路径 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 启动请求到应用界面获得调度七个阶段依次为:
ActivityStackSupervisor按进程名和 uid 查询ProcessRecord。目标进程及app.thread不可用时,AMS 调用startProcessLocked()。- AMS 把 uid、gid、补充组、目标 SDK、进程名、ABI 和入口类等配置交给
Process.start();Process通过本地 socket 发给 Zygote,并同步等待 pid。 - Zygote 的
runSelectLoop()接收连接,ZygoteConnection.runOnce()解析请求,native 层调用fork()。父进程返回 pid,子进程完成身份、描述符和运行环境的专门化。 - 子进程进入
RuntimeInit.zygoteInit(),AppRuntime::onZygoteInit()初始化 BinderProcessState并启动线程池。 RuntimeInit.invokeStaticMain()通过MethodAndArgsCaller把控制权转移到ActivityThread.main();主线程准备 Looper 后调用attach(false)。- 应用进程把
IApplicationThread交给 AMS。AMS 关联ProcessRecord,调用bindApplication();应用进程据此创建ContextImpl、ClassLoader 和 Application,并执行Application.onCreate()。 - AMS 经
realStartActivityLocked()发出scheduleLaunchActivity()的 oneway 事务;对应的H.LAUNCH_ACTIVITY排在H.BIND_APPLICATION之后,由应用主线程按顺序处理。
12.1 可执行的验证入口
以下命令可以对照进程、AMS 记录和事件日志。不同 Android 版本的 ps、dumpsys 输出字段可能有差异,命令中的包名、进程名和 Activity 需要替换为实际值。
# 查看目标进程及其父进程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 生成