AndroidP_应用进程启动流程的梳理

前言

本来是要将之前Activity冷启动流程继续梳理清楚的,到了中间看到当进程尚未启动还需要启动新的进程,这也是需要梳理清楚的,于是就先将进程启动流程在源码层面给梳理一遍.

流程图

先上图,有个概况了解才能有梳理的方向:
AndroidP_应用进程启动流程的梳理_第1张图片

源码

建议在进入源码阅读之前,先将上面的流程图大概的进行两遍左右的阅读,然后相信会对下面的源码梳理的理解有很大的帮助:

1. AMS.startProcess

我们在开发中中应该知道,应用进程的管理通常是由AMS来进行的,但是进程的启动也是由AMS来发起的虽然是AMS发起的,但是创建却不是AMS,而是经由Zygote来实现的,(这点需要明确一下),下面会有基于源码层的详细介绍

AMS中有一个 方法叫startProcess,它就是AMS发起创建新的应用进程的开始,我们就进入到代码中看看:
frameworks/base/services/core/java/com/android/server/am.ActivityManagerService.java

private ProcessStartResult startProcess(String hostingType, String entryPoint,
      ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
      String seInfo, String requiredAbi, String instructionSet, String invokeWith,
      long startTime) {
		...
      startResult = Process.start(entryPoint,
               app.processName, uid, uid, gids, runtimeFlags, mountExternal,
               app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
               app.info.dataDir, invokeWith,
               new String[] {PROC_START_SEQ_IDENT + app.startSeq});
      checkTime(startTime, "startProcess: returned from zygote!");
      return startResult;
	  ...
}

startProcess()方法内部实现相对简单,主要就是通过调用Process的start()方法,我们就去Process中继续看看;

1.1 Process.start

我们先说明一下,这个Process类,这个类主要就是用来管理Android系统的的进程。
frameworks/base/core/java/android/os/Process.java

    public static final ProcessStartResult start(...) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }
    ...

    public static final ZygoteProcess zygoteProcess =
            new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);

我们看到,当前的start()方法内部是通过调用ZygoteProcess的成员方法start();这个zygoteProcess的创建需要传递参数,我们注意到这个参数是SOCKET字眼,恩恩,确实接下来需要使用到socket通信了;

1.2 ZygoteProcess.start

我们这里再对ZygoteProcess这个类进行简单的说明,它是和Zygote进程通信,主要负责打开给zygote的socket,并连接。
frameworks/base/core/java/android/os/ZygoteProcess.java

public final Process.ProcessStartResult start(...) {
	  return startViaZygote(processClass, niceName, uid, gid, gids,
	            runtimeFlags, mountExternal, targetSdkVersion, seInfo,
	            abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
	            zygoteArgs);
...
}

start()方法其实也没做啥,还是调用了一个成员变量startViaZygote(),我们就继续到startViaZygote()方法中;

1.3 ZygoteProcess.startViaZygote

frameworks/base/core/java/android/os/ZygoteProcess.java

     */
    private Process.ProcessStartResult startViaZygote(....)
                                                      throws ZygoteStartFailedEx {
        // 这是一个参数列表,用于向Zygote传递启动新的进程的参数
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--runtime-flags=" + runtimeFlags);
        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
            argsForZygote.add("--mount-external-default");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
            argsForZygote.add("--mount-external-read");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
            argsForZygote.add("--mount-external-write");
        }
        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
        // --setgroups is a comma-separated list
        // 省略代码,主要是参数的封装、
        synchronized(mLock) {
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

在startViaZygote()方法这种,我们首先注意这里创建了一个ArrayList,它里面就是填充由于启迪新的进程的参数,然后就会调用zygoteSendArgsAndGetResult()方法将参数传递进去,这里我们还看到,不光传入参数列表,还有个openZygoteSocketIfNeeded()的方法,【这个方法就是用于打开和Zygote socket通信的】;紧接着我们到zygoteSendArgsAndGetResult()方法中:

1.3 ZygoteProcess.zygoteSendArgsAndGetResult

frameworks/base/core/java/android/os/ZygoteProcess.java

@GuardedBy("mLock")
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
    try {
      ....
        final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;

        writer.write(Integer.toString(args.size()));
        writer.newLine();

        for (int i = 0; i < sz; i++) {
            String arg = args.get(i);
            writer.write(arg);
            writer.newLine();
        }
        writer.flush();
        // Should there be a timeout on this?
        Process.ProcessStartResult result = new Process.ProcessStartResult();
        ...
        result.pid = inputStream.readInt();
        result.usingWrapper = inputStream.readBoolean();
...
        return result;
...
}

zygoteSendArgsAndGetResult()方法向zygote进程发送参数列表,然后zygote进程启动一个新子进程并返回子进程的pid。
到此,AMS发起应用创建的流程就结束了,我们接下来就需要了解Zygote是怎么接受消息并创建新的进程的;

2. ZygoteServer.runSelectLoop

在Zygote进程启动完成后,就会进入一个loop循环,Zygote就是在当前的循环中响应请求并处理,当我们的AMS向Zygote发送创建新进程的请求时,Zygote端就会fork一个新的进程。我们这就到代码中看看其实现:
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

 Runnable runSelectLoop(String abiList) {
    ...
     while (true) {
     ....
     try {
          ZygoteConnection connection = peers.get(i);
          final Runnable command = connection.processOneCommand(this);
		....
       return command;
           ...
        }
        ...
     }
 }

runSelectLoop()方法在接收到来自AMS的请求后,马上就会调用ZygoteConnection的成员方法processOneCommand()进行处理;

2.1 ZygoteConnection.processOneCommand

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

Runnable processOneCommand(ZygoteServer zygoteServer) {
  ...
  //省略代码,主要工作是解析参数
  pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);
                ...
 try {
      if (pid == 0) {
          // in child
        ...
          return handleChildProc(parsedArgs, descriptors, childPipeFd,
                  parsedArgs.startChildZygote);
...

如上所示,在获取和解析完请求的参数后,zygote就会调用forkAndSpecialize()方法来创建新的进程,接下来我们就需要关心两个重点,

  1. forkAndSpecialize()方法的具体实现,是最后如何创建出的子进程
  2. handleChildProc()方法的具体实现,做了些什么

2.1.1 Zygote.forkAndSpecialize

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

    public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
        VM_HOOKS.preFork();
        // Resets nice priority for zygote process.
        resetNicePriority();
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  fdsToIgnore, startChildZygote, instructionSet, appDataDir);
       ...
        return pid;
    }

如上所示,在Zygote的forkAndSpecialize()方法中,是调用的一个native方法nativeForkAndSpecialize(),那么我们就需要去了解native层的实现了;

2.1.2 nativeForkAndSpecialize

frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits,
        jint mount_external, jstring se_info, jstring se_name,
        jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
        jstring instructionSet, jstring appDataDir) {
    jlong capabilities = 0;
...
    return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE,
            instructionSet, appDataDir);
}
....
// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(...) {
	...
 	pid_t pid = fork();
  	....
  	return pid;
}

如上所示,我们可以看到,com_android_internal_os_Zygote_nativeForkAndSpecialize()函数中调用ForkAndSpecializeCommon(),最后直接fork()出子进程并返回。在新的进程中,就会调用handleChildProc()进行进一步的初始化,

2.2 ZygoteConnection.handleChildProc()

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

    private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
        /**
         * By the time we get here, the native code has closed the two actual Zygote
         * socket connections, and substituted /dev/null in their place.  The LocalSocket
         * objects still need to be closed properly.
         */

        closeSocket();
       ...
        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }
			...
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
          ...
        }
    }

如上所示,在新的进程中执行handleChildProc()方法,首先关闭socket,因为当前的socket使用Zygote继承下来的,但是新的进程不需要了,然后调用ZygoteInit的zygoteInit()方法继续执行。

3 ZygoteInit.zygoteInit

到了这里,新的进程就已经创建完成了,但是还不能使用,因为我们当前的进程是从zygote直接继承下来的,很多初始化动作需要完成才能正常是使用,
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        ...
        // log初始化
        RuntimeInit.redirectLogStreams();
        // 一般功能的初始化
        RuntimeInit.commonInit();
        // 开启Binder线程池
        ZygoteInit.nativeZygoteInit();
        // 应用进程上层类的执行
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

如上所示,主要就是一些初始化的动作,这里我们关注一下binder线程池的创建过程;

3.1 ZygoteInit.nativeZygoteInit()

nativeZygoteInit是一个navtive方法,实现如下在:
frameworks/base/core/jni/AndroidRuntime.cpp

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

上述代码最终会走到如下:

frameworks/base/cmds/app_process/app_main.cpp

class AppRuntime : public AndroidRuntime
{
   ...
	  virtual void onZygoteInit()
  	 {
       sp<ProcessState> proc = ProcessState::self();
       ALOGV("App process: starting thread pool.\n");
       proc->startThreadPool();
   }
  ...
}

如上所示,nativeZygoteInit()方法在底层的实现就是调用ProcessState的成员函数startThreadPool()来创建Binder线程池,程序就可以进行bidner调用了,可以和AMS等进程进行通信。

3.2 RuntimeInit.applicationInit

紧接着,代码就会走到RuntimeInit的appliacationInit()方法中,我们继续查看其实现:
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
       ...
        // Remaining arguments are passed to the start class's static main
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
    ...
protected static Runnable findStaticMain(String className, String[] argv,
    ClassLoader classLoader) {
	Class<?> cl;
	...
	// 找到要启动的类
	cl = Class.forName(className, true, classLoader);
	...
	Method m;
	...
	// 找到其中的main方法
	m = cl.getMethod("main", new Class[] { String[].class });
	...
	// 通过MethodAndArgsCaller来调用启动类的main方法(ActivityThread的Main方法
	return new MethodAndArgsCaller(m, argv);
}
...
// MethodAndArgsCaller的实现
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 });
            ...
            }
}

如上所示,applicationInit()方法里面主要是调用findStaticMain()方法,而findStaticMain()方法就像其名称一样,通过传入的参数拿到要启动的类名,然后通过MethodAndArgsCaller来调用其Main方法,由于我们启动的是应用进程,这里就会调用ActivityThread的Main方法。
进程走到ActiviityThread中后,接下来就会向通过attach方法向AMS注册,向其传递一个当前应用的代理对象的句柄,如此一来,AMS和应用之间就可以双向调用了。

你可能感兴趣的:(AndroidP_应用进程启动流程的梳理)