从源码角度看 AMS.startProcessLocked

简介

注:本篇文章的所有源码与注释都可以在YogiAi/Process.start 中找到,只想阅读代码的同学可以直奔主题。

众所周知,Android 系统是基于 Linux 内核的移动操作系统。而 Linux 又是通过 fork 来复制进程,复制的时候只是创建唯一识别符等轻量操作,真正对于资源的使用是借助了写时复制的机制(copy-on-write)。进程与线程的概念在 Linux 的世界中只有资源拥有的差别,本质上它们的内核实现都使用了 task_struct 这同一个结构体,都拥有着各自的 PID, PPID。

在 Android 自成的上层 framework 世界中,进程的概念被层层的封装后已经很模糊了,基本开发者完成开发过程只需熟悉Activity, BroadcastReceiver, Service等四大组件的作用与使用场景,再加上网络访问、数据存储、UI 绘制等等组合而成的业务逻辑即可完成一个很不错的应用。

然而研究 Android 的进程启动时机与实现原理对于进阶学习还是大有裨益的,不仅能够学到进程线程的内功知识,也能够学到设计大师的封装奥妙。Android 应用进程的创建是通过 fork Zygote 进程来实现的,所以所有的应用进程的 PPID 都是 Zygote 的 PID。复制 Zygote 的实例后会得到一个虚拟机实例,除此之外,新建的进程还会获取到一个消息循环、 Binder 的进程通信池以及一个 Binder 主线程。

在这一篇文章中,我将详细解析Android 进程的创建过程。

system_server 端

AMS.startProcessLocked

ActivityManagerService 运行在 system_server 进程,为应用提供各种服务。系统可能因为发送广播,启动服务,运行 Activity 等原因启动一个新的进程。这时候会 binder call 到 AMS,调用 startProcessLocked 方法进行处理。

  • final ProcessRecord startProcessLocked(String processName,
  • ApplicationInfo info, boolean knownToBeDead, int intentFlags,
  • String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
  • ...
  • if (app == null) {
  • app = newProcessRecordLocked(null, info, processName);
  • mProcessNames.put(processName, info.uid, app);
  • } else {
  • // If this is a new package in the process, add the package to the list
  • app.addPackage(info.packageName);
  • }
  • ...
  • startProcessLocked(app, hostingType, hostingNameStr);
  • return (app.pid != 0) ? app : null;
  • }
  • private final void startProcessLocked(ProcessRecord app,
  • String hostingType, String hostingNameStr) {
  • ...
  • try {
  • // 获得创建的应用程序进程的用户 ID,用户组 ID
  • int uid = app.info.uid;
  • int[] gids = null;
  • try {
  • gids = mContext.getPackageManager().getPackageGids(
  • app.info.packageName);
  • } catch (PackageManager.NameNotFoundException e) {
  • Slog.w(TAG, "Unable to retrieve gids", e);
  • }
  • ...
  • // 创建进程,并制定这个进程的路口时 ActivityThread 的静态方法 main
  • int pid = Process.start("android.app.ActivityThread",
  • mSimpleProcessManagement ? app.processName : null, uid, uid,
  • gids, debugFlags, null);
  • ...
  • }

Process.start

进程的启动入口在 Process.start 方法,start 方法只做了初始化参数的工作,真正的复制进程工作是在 zygote 进行完成的,system_server 与 zygote 进程的通信使用的 socket。system_server 会将参数信息写入到 socket 中,然后阻塞等待 zygote 的回应。

  • public static final int start(final String processClass,
  • final String niceName,
  • int uid, int gid, int[] gids,
  • int debugFlags,
  • String[] zygoteArgs)
  • {
  • // 是否支持 Binder 进程间通信的机制
  • if (supportsProcesses()) {
  • try {
  • // 如果支持, 就请求 Zygote 来创建一个应用程序进程
  • return startViaZygote(processClass, niceName, uid, gid, gids,
  • debugFlags, zygoteArgs);
  • } catch (ZygoteStartFailedEx ex) {
  • Log.e(LOG_TAG,
  • "Starting VM process through Zygote failed");
  • throw new RuntimeException(
  • "Starting VM process through Zygote failed", ex);
  • }
  • } else {
  • // Running in single-process mode
  • // 如果不支持, 就使用一个线程来模拟进程
  • Runnable runnable = new Runnable() {
  • public void run() {
  • Process.invokeStaticMain(processClass);
  • }
  • };
  • // Thread constructors must not be called with null names (see spec).
  • if (niceName != null) {
  • new Thread(runnable, niceName).start();
  • } else {
  • new Thread(runnable).start();
  • }
  • return 0;
  • }
  • }
  • private static int startViaZygote(final String processClass,
  • final String niceName,
  • final int uid, final int gid,
  • final int[] gids,
  • int debugFlags,
  • String[] extraArgs)
  • throws ZygoteStartFailedEx {
  • int pid;
  • synchronized(Process.class) {
  • // 初始化进程的启动参数列表
  • ArrayList<String> argsForZygote = new ArrayList<String>();
  • ...
  • // 初始化完毕
  • pid = zygoteSendArgsAndGetPid(argsForZygote);
  • }
  • ...
  • return pid;
  • }
  • private static int zygoteSendArgsAndGetPid(ArrayList<String> args)
  • throws ZygoteStartFailedEx {
  • int pid;
  • // 创建一个连接到 Zygote 的 LocalSocket 对象
  • openZygoteSocketIfNeeded();
  • try {
  • // 将要创建的应用程序的进程启动参数传到 LocalSocket 对象中
  • sZygoteWriter.write(Integer.toString(args.size()));
  • sZygoteWriter.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");
  • }
  • sZygoteWriter.write(arg);
  • sZygoteWriter.newLine();
  • }
  • sZygoteWriter.flush();
  • // Should there be a timeout on this?
  • // 通过 Socket 读取 Zygote 创建成功的进程 PID
  • // Socket 对端的请求在 ZygoteInit.runSelectLoopMode中进行处理
  • // 读取成功之后会对 PID 进行检查,无异常的话就会推出
  • pid = sZygoteInputStream.readInt();
  • if (pid < 0) {
  • throw new ZygoteStartFailedEx("fork() failed");
  • }
  • } catch (IOException ex) {
  • ...
  • }
  • return pid;
  • }

zygote 端

ZygoteInit.main

zygote 进程的 Socket服务端是在此处进行创建初始化的,当接受到 socket 客户端的请求时会进行处理。本质上是启动了一个无限循环来处理客户端的请求。这里 system_server 与 zygote 是典型的 C/S 架构。

  • public static void main(String argv[]) {
  • try {
  • VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024);
  • // Start profiling the zygote initialization.
  • SamplingProfilerIntegration.start();
  • // 在 Zygote 服务端注册一个 Socket Server, 用来创建新进程
  • registerZygoteSocket();
  • ...
  • if (ZYGOTE_FORK_MODE) {
  • runForkMode();
  • } else {
  • // 开始处理进程创建的 Socket 请求
  • runSelectLoopMode();
  • }
  • closeServerSocket();
  • } catch (MethodAndArgsCaller caller) {
  • // ActivityThread 的静态方法在这被回调执行
  • // 这里间接调用方法,巧妙的利用了异常处理机制来清理前面的调用栈
  • caller.run();
  • } catch (RuntimeException ex) {
  • Log.e(TAG, "Zygote died with exception", ex);
  • closeServerSocket();
  • throw ex;
  • }
  • }
  • private static void runSelectLoopMode() throws MethodAndArgsCaller {
  • ArrayList<FileDescriptor> fds = new ArrayList();
  • ArrayList<ZygoteConnection> peers = new ArrayList();
  • FileDescriptor[] fdArray = new FileDescriptor[4];
  • fds.add(sServerSocket.getFileDescriptor());
  • peers.add(null);
  • int loopCount = GC_LOOP_COUNT;
  • while (true) {
  • ...
  • if (index < 0) {
  • throw new RuntimeException("Error in select()");
  • } else if (index == 0) {
  • // 新的进程创建请求
  • ZygoteConnection newPeer = acceptCommandPeer();
  • peers.add(newPeer);
  • fds.add(newPeer.getFileDesciptor());
  • } else {
  • boolean done;
  • // 处理这个进程请求
  • done = peers.get(index).runOnce();
  • if (done) {
  • peers.remove(index);
  • fds.remove(index);
  • }
  • }
  • }
  • }

ZygoteConnection.runOnce

在 zygote 进程主要执行这三个操作:

  1. 调用 Zygote.forkAndSpecialize 进行进程复制操作
  2. 调用 handleChildProc 处理新建进程资源初始化,如创建 Binder 线程池,启动一个主线程消息队列
  3. 调用 handleParentProc 将新建进程的 PID 返回给 system_server,表示创建结果
  • boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
  • String args[];
  • Arguments parsedArgs = null;
  • FileDescriptor[] descriptors;
  • try {
  • // 读取启动参数
  • args = readArgumentList();
  • descriptors = mSocket.getAncillaryFileDescriptors();
  • } catch (IOException ex) {
  • Log.w(TAG, "IOException on command socket " + ex.getMessage());
  • closeSocket();
  • return true;
  • }
  • ...
  • int pid;
  • try {
  • // 将 String 数组封装成 Arguments
  • parsedArgs = new Arguments(args);
  • applyUidSecurityPolicy(parsedArgs, peer);
  • applyDebuggerSecurityPolicy(parsedArgs);
  • applyRlimitSecurityPolicy(parsedArgs, peer);
  • applyCapabilitiesSecurityPolicy(parsedArgs, peer);
  • int[][] rlimits = null;
  • if (parsedArgs.rlimits != null) {
  • rlimits = parsedArgs.rlimits.toArray(intArray2d);
  • }
  • // fork 操作
  • // 将会有两个进程从这里返回
  • // PID=0意味着是子进程
  • pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
  • parsedArgs.gids, parsedArgs.debugFlags, rlimits);
  • } catch (IllegalArgumentException ex) {
  • logAndPrintError (newStderr, "Invalid zygote arguments", ex);
  • pid = -1;
  • } catch (ZygoteSecurityException ex) {
  • logAndPrintError(newStderr,
  • "Zygote security policy prevents request: ", ex);
  • pid = -1;
  • }
  • if (pid == 0) {
  • // in child
  • // 创建出的新进程
  • handleChildProc(parsedArgs, descriptors, newStderr);
  • // should never happen
  • return true;
  • } else { /* pid != 0 */
  • // in parent...pid of < 0 means failure
  • // 父进程将在这里进行处理
  • return handleParentProc(pid, descriptors, parsedArgs);
  • }
  • }

```java
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
...
if (parsedArgs.runtimeInit) {
// 在新创建的应用程序进程中初始化运行时库,创建一个 Binder 线程池
RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
} else {
ClassLoader cloader;

  • // 获取 classloader
  • if (parsedArgs.classpath != null) {
  • cloader
  • = new PathClassLoader(parsedArgs.classpath,
  • ClassLoader.getSystemClassLoader());
  • } else {
  • cloader = ClassLoader.getSystemClassLoader();
  • }
  • // 读取 ActivityThread 类名
  • String className;
  • try {
  • className = parsedArgs.remainingArgs[0];
  • } catch (ArrayIndexOutOfBoundsException ex) {
  • logAndPrintError (newStderr,
  • "Missing required class name argument", null);
  • return;
  • }
  • String[] mainArgs
top Created with Sketch.