前言

本篇是 Activity 发动进程(中)篇,接受上篇文章 Android Activity 发动进程(上)

本文中代码依据 android-security-11.0.0_r66 分支.

Android Activity 发动进程(上) – 主要描绘SystemServer 进程怎样处理startActivity恳求以及怎样走到恳求Zygote fork app 进程的流程

Android Activity 发动进程(下) – 主要描绘 App进程发动后绑定到SystemServer可被体系监控进程 和 根 Activity 创立进程

此篇主要是介绍Zygote进程接收到 来自SystemServer进程恳求创立App进程的音讯后,怎样去fork app 进程。

3. Zygote 进程 fork App进程进程

frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

Runnable runSelectLoop(String abiList) {
  ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
  ArrayList<ZygoteConnection> peers = new ArrayList<>();
  // 省掉
  mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
​
  while (true) {
    fetchUsapPoolPolicyPropsWithMinInterval();
    mUsapPoolRefillAction = UsapPoolRefillAction.NONE;
    // 省掉
    try {
      pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);//chld 正常情况下此处传入的值是 -1,即一向轮询等待数据
     } catch (ErrnoException ex) {
      throw new RuntimeException("poll failed", ex);
     }
​
    if (pollReturnValue == 0) {
      mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
      mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
     } else {
      boolean usapPoolFDRead = false;
      while (--pollIndex >= 0) {
        if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
          continue;
         }
​
        if (pollIndex == 0) {//chld - 走到 pollIndex 说明此刻没有需求处理的创立进程的需求,而是有的新的衔接到来
          // Zygote server socket
          ZygoteConnection newPeer = acceptCommandPeer(abiList);// chld 等待 新的链接,没有时 阻塞着
          peers.add(newPeer);
          socketFDs.add(newPeer.getFileDescriptor());
​
         } else if (pollIndex < usapPoolEventFDIndex) { //  chld  说明此刻体系不支持 usap.(如果有的话,pollIndex 值是大于等于 usapPoolEventFDIndex 的,原因具体情况Android 11 对应代码,此处相关逻辑已被删除)
          // Session socket accepted from the Zygote server socket
​
          try {
            ZygoteConnection connection = peers.get(pollIndex);
            final Runnable command = connection.processOneCommand(this);// 代码1 // TODO (chriswailes): Is this extra check necessary?
            if (mIsForkChild) {// chld 此刻处于fork出来的运用进程中,回来 Runnable 目标,去在`ZygoteInit::main`办法中履行
              // We're in the child. We should always have a command to run at
              // this stage if processOneCommand hasn't called "exec".
              if (command == null) {
                throw new IllegalStateException("command == null");
               }
​
              return command;
             } else {
              if (connection.isClosedByPeer()) {//代码2  Zygote 进程关闭 socket 衔接
                connection.closeSocket();
                peers.remove(pollIndex);
                socketFDs.remove(pollIndex);
               }
             }
           } catch (Exception e) {
            // 省掉
           } finally {
            // 重置标志
            mIsForkChild = false;
           }
​
         } else {// chld USAP 发动
          // 省掉
          usapPoolFDRead = true;
         }
       }
​
      if (usapPoolFDRead) {
        int usapPoolCount = Zygote.getUsapPoolCount();
​
        if (usapPoolCount < mUsapPoolSizeMin) {//chld  最小值默许是1,即表明此刻 可用USAP进程小于1个
          // Immediate refill
          mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE;
         } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) {//chld 可运用的USAP 进程低于阈值(最大10个,阈值一般是最大值的一半)
          // Delayed refill
          mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
         }
       }
     }
​
    if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) {// chld 说明此刻运用 usap 办法发动
      int[] sessionSocketRawFDs =
          socketFDs.subList(1, socketFDs.size())
               .stream()
               .mapToInt(FileDescriptor::getInt$)
               .toArray();
​
      final boolean isPriorityRefill =
          mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;// chld 判别是否立行将usap 进程弥补完
​
      final Runnable command =
          fillUsapPool(sessionSocketRawFDs, isPriorityRefill);// 代码3
​
      if (command != null) {
        return command;
       } else if (isPriorityRefill) {
        // Schedule a delayed refill to finish refilling the pool.
        mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
       }
     }
   }
}

代码3 处,是在运用usap 办法发动。此处暂时不细讲了,有爱好的同学自行查找下吧,usap 仅仅免除了进程的fork,加快了运用发动速度,其他流程根本共同。(USAP 进程默许会创立10个待用,待低于一半值时重新填空完成,同时其是在防止影响运用进程创立的,在没有运用创立恳求的时分去创立) 而在未开启 usap 发动办法的情况下,正常是走到代码1处, processOneCommand 回来一个 Runnable 目标,该 Runnable 目标将在 ZygnoteInit::main 被履行(注:在Android 8.1 及之前,是经过抛出反常的办法抛到 ZygnoteInit::main 办法中被捕获后履行的,一种奇奇怪怪的古怪办法,在Android 9开始终于才用 回来的办法了)。 该 Runnable目标的 run办法中将履行 ActivityThread 的创立办法。

接下来看下 ZygoteConnection::processOneCommand 办法吧

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

​
Runnable processOneCommand(ZygoteServer zygoteServer) {
  String[] args;
  try {
    args = Zygote.readArgumentList(mSocketReader);
   } catch (IOException ex) {
    throw new IllegalStateException("IOException on command socket", ex);
   }
 
  if (args == null) {
    isEof = true;
    return null;
   }
  ZygoteArguments parsedArgs = new ZygoteArguments(args);//代码1
​
  //... 省掉
​
  // 代码2
  pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
      parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
      parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
      parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
      parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList,
      parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
​
  try {
    if (pid == 0) {//代码3 子进程
      zygoteServer.setForkChild();
      zygoteServer.closeServerSocket();
      IoUtils.closeQuietly(serverPipeFd);// 关闭与server的通道
      serverPipeFd = null;
      return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);// 代码4
     } else {
      IoUtils.closeQuietly(childPipeFd);
      childPipeFd = null;
      handleParentProc(pid, serverPipeFd);// 代码5
      // 代码6 
      return null;
     }
   } finally {
    // 最终再尝试一次关闭管道
    IoUtils.closeQuietly(childPipeFd);
    IoUtils.closeQuietly(serverPipeFd);
   }
}

代码1处 将 SystemServer发送来的恳求数参数进行转换成 ZygoteArguments 目标。 代码2处 运用将依据这些参数调用 Zygote.forkAndSpecialize办法去fork 一个进程,forkAndSpecialize 下面的处理就涉及作者盲区了。 代码3处 fork后进入代码3判别处,此处依据 pid 的值判别当时是处于fork 处理的子进程仍是 父进程。 子线程将进入代码4处调用 handleChildProc 办法处理。而 Zygote 将进入代码5处,并在代码6处回来 null,经过null 来告知上层,此刻是处于子进程中。并且在 handleParentProc办法中 Zygote 进程将告知 SystemServer 创立的进程的id.

先看下 handleParentProc办法。

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

private void handleParentProc(int pid, FileDescriptor pipeFd) {
  //... 省掉
  try {
    mSocketOutStream.writeInt(pid);
    mSocketOutStream.writeBoolean(usingWrapper);
   } catch (IOException ex) {
    throw new IllegalStateException("Error writing to command socket", ex);
   }
}

此处经过socket 将进程pid 和 usingWrapper 数据传回给了 SysmtemServer 进程的 2.6 章节处 的 ZygoteProcess::attemptZygoteSendArgsAndGetResult办法中.

接下来回来看下 ZygoteConnection::handleChildProc 办法中是怎样去创立一个 Runnable 目标的。

 private Runnable handleChildProc(ZygoteArguments parsedArgs,
      FileDescriptor pipeFd, boolean isZygote) {
    closeSocket();
    Zygote.setAppProcessName(parsedArgs, TAG);//此刻设置进程名称
    // chld 运用进程此处 mInvokeWith:null  isZygote:false
    // 输出结果:  I/Zygote: chld handleChildProc setAppProcessName mNiceName:com.example.myapplication2 mPackageName:com.example.myapplication2 mInvokeWith:null isZygote:false
    Log.i(TAG,"chld handleChildProc setAppProcessName mNiceName:" + parsedArgs.mNiceName + " mPackageName:" + parsedArgs.mPackageName + " mInvokeWith:" + parsedArgs.mInvokeWith +" isZygote:" + isZygote);
    if (parsedArgs.mInvokeWith != null) {
      WrapperInit.execApplication(parsedArgs.mInvokeWith,
          parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
          VMRuntime.getCurrentInstructionSet(),
          pipeFd, parsedArgs.mRemainingArgs);
      // Should not get here.
      throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
     } else {
      if (!isZygote) {
        return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
            parsedArgs.mDisabledCompatChanges,
            parsedArgs.mRemainingArgs, null /* classLoader */);
       } else {// chld isZygote 判别创立的这个新的进程自身是不是一个Zygote(孵化器) 进程,创立的是运用进程显然是走此处
        return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
            parsedArgs.mRemainingArgs, null /* classLoader */);//代码2
       }
     }
   }

代码1 处此刻设置了进程的姓名,一般是运用的包名。在此之前 Zygote名称为 Zygote,有爱好的同学能够试试。注意:如果是UASP 办法发动,在调用 Zygote.setAppProcessName之前名称为 UASP 。 代码2 这个Runnable 目标还得再经过 ZygoteInit::childZygoteInit 办法去创立啊。此处还需求的参数只剩下了 parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs

接下来去看下 ZygoteInit::childZygoteInit 办法的实现吧。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

static final Runnable childZygoteInit(
      int targetSdkVersion, String[] argv, ClassLoader classLoader) {
  RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
  return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
}

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

protected static Runnable findStaticMain(String className, String[] argv,
    ClassLoader classLoader) {
  Class<?> cl;
​
  try {
    cl = Class.forName(className, true, classLoader);
   } catch (ClassNotFoundException ex) {
    throw new RuntimeException(
        "Missing class when invoking static main " + className,
        ex);
   }
​
  Method m;
  try {
    m = cl.getMethod("main", new Class[] { String[].class });
   } catch (NoSuchMethodException ex) {
    throw new RuntimeException(
        "Missing static main on " + className, ex);
   } catch (SecurityException ex) {
    throw new RuntimeException(
        "Problem getting static main on " + className, ex);
   }
​
  int modifiers = m.getModifiers();
  if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
    throw new RuntimeException(
        "Main method is not public and static on " + className);
   }
​
  /*
    * This throw gets caught in ZygoteInit.main(), which responds
    * by invoking the exception's run() method. This arrangement
    * clears up all the stack frames that were required in setting
    * up the process.
    */
  return new MethodAndArgsCaller(m, argv);// 代码1
}

findStaticMain 办法中传入的 className 就是 Android Activity 发动进程(上)2.5 章节 ProcessList ProcessList::startProcessLocked 办法中 final String entryPoint = "android.app.ActivityThread" 值;, 此处获取了该类的静态办法,并将参数传入。 然后一路回来到 ZygoteInit::main办法吧。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) {
  ZygoteServer zygoteServer = null;
  Runnable caller;
  try {
    //...
    zygoteServer = new ZygoteServer(isPrimaryZygote);
    if (startSystemServer) {// 代码1 fork SystemServer 进程
      Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
​
      // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
      // child (system_server) process.
      if (r != null) {
        r.run();
        return;
       }
     }
​
    Log.i(TAG, "Accepting command socket connections");
​
    // The select loop returns early in the child process after a fork and
    // loops forever in the zygote.
    caller = zygoteServer.runSelectLoop(abiList);// 代码2 等待AMS创立进行恳求,当创立完运用子进程后,运用子进程会回来一个`Runnable` 目标
   } catch (Throwable ex) {
    Log.e(TAG, "System zygote died with exception", ex);
    throw ex;
   } finally {
    if (zygoteServer != null) {
      zygoteServer.closeServerSocket();
     }
   }
  if (caller != null) {//chld  运用进程f 
    caller.run();
   }
}
​

能够看到此处履行了 MethodAndArgsCaller::run办法,在该 run办法中去进行了 ActivityAThread::main 办法的反射调用。

为什么不直接在 RuntimeInit::findStaticMain 调用呢? 这是为了清除 创立进程中堆栈,让运用进程看起来是直接从 ZygoteInit::main办法中直接发动的。(太长的栈,那遇到反常打印出来,得带着多少无用的栈数据啊)

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

static class MethodAndArgsCaller implements Runnable {
  /** method to call */
  private final Method mMethod;
​
  /** argument array */
  private final String[] mArgs;
​
  public MethodAndArgsCaller(Method method, String[] args) {
    mMethod = method;
    mArgs = args;
   }
​
  public void run() {
    try {
      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;
       } else if (cause instanceof Error) {
        throw (Error) cause;
       }
      throw new RuntimeException(ex);
     }
   }
}

如上是 MethodAndArgsCaller类,run 没什么可说的,就是一个反射调用。接下来就走到 ActivityThread类中啦,也真正的进入运用层了。

接下来请看下篇
Android Activity 发动进程(下)