Android进程创建流程-1

基于-Android 6.0,相关源码文件:

/frameworks/base/core/java/com/android/internal/os/
    - ZygoteInit.java
    - ZygoteConnection.java
    - RuntimeInit.java
    - Zygote.java

/frameworks/base/core/java/android/os/Process.java
/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/cmds/app_process/App_main.cpp (内含AppRuntime类)

/bionic/libc/bionic/fork.cpp
/bionic/libc/bionic/pthread_atfork.cpp

/libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
/art/runtime/native/dalvik_system_ZygoteHooks.cc
/art/runtime/Runtime.cc
/art/runtime/Thread.cc
/art/runtime/signal_catcher.cc

 

一、概述

1.1 准备知识

本文要介绍的是进程的创建,先简单说说进程与线程的区别:

(1) 进程:每个App在启动前必须先创建一个进程,该进程是由 Zygote fork 出来的,进程具有独立的资源空间,用于承载App上运行的各种 Activity/Service 等组件。进程对于上层应用来说是完全透明的,这也是 google 有意为之,让App程序都是运行在 Android Runtime。大多数情况一个App就运行在一个进程中,除非在 AndroidManifest.xml 中配置 Android:process 属性,或通过 native 代码 fork 进程。

(2) 线程:线程对应用开发者来说非常熟悉,比如每次 new Thread().start() 都会创建一个新的线程,该线程并没有自己独立的地址空间,而是与其所在进程之间资源共享。从Linux角度来说进程与线程都是一个 task_struct 结构体,除了是否共享资源外,并没有其他本质的区别。

在接下来的文章,会涉及到 system_server 进程和 Zygote 进程,下面简要这两个进程:

(1) system_server 进程:是用于管理整个 Java framework 层,包含 ActivityManager,PowerManager 等各种系统服务;

(2) Zygote进程:是 Android 系统的首个 Java 进程,Zygote 是所有 Java 进程的父进程,包括 system_server 进程以及所有的 App 进程都是 Zygote 的子进程,注意这里说的是子进程,而非子线程。

1.2 进程创建图

对于大多数的应用开发者来说创建线程比较熟悉,而对于创建进程并没有太多的概念。对于系统工程师或者高级开发者,还是有很必要了解 Android 系统是如何一步步地创建出一个进程的。先来看一张进程创建过程的简要图:

图解:

(1) App发起进程:当从桌面启动应用,则发起进程便是 Launcher 所在进程;当从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过 binder 发送消息给 system_server 进程;

(2) system_server 进程:调用 Process.start() 方法,通过 socket 向 zygote 进程发送创建新进程的请求;

(3) zygote 进程:在执行 ZygoteInit.main() 后便进入 runSelectLoop() 循环体内,当有客户端连接时便会执行 ZygoteConnection.runOnce() 方法,再经过层层调用后 fork 出新的应用进程;

(4) 新进程:执行 handleChildProc 方法,最后调用 ActivityThread.main() 方法。

接下来,依次从 system_server 进程发起请求到 Zygote 创建进程,再到新进程的运行这3大块展开讲解进程创建是一个怎样的过程。


二、system_server 发起请求

2.1 Process.start

[-> Process.java]

public static final ProcessStartResult start(final String processClass, final String niceName, int uid, 
    int gid, int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, 
    String abi, String instructionSet, String appDataDir, String[] zygoteArgs) {
    try {
         //【见2.2】
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        throw new RuntimeException("");
    }
}

2.2 startViaZygote

[-> Process.java]

private static ProcessStartResult startViaZygote(final String processClass, final String niceName, 
    final int uid, final int gid, final int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, 
    String seInfo, String abi, String instructionSet, String appDataDir, String[] extraArgs) 
    throws ZygoteStartFailedEx {
    synchronized(Process.class) {
        ArrayList<String> argsForZygote = new ArrayList<String>();

        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

        if (niceName != null) {
            argsForZygote.add("--nice-name=" + niceName);
        }
        if (appDataDir != null) {
            argsForZygote.add("--app-data-dir=" + appDataDir);
        }
        argsForZygote.add(processClass);

        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }
         //【见2.3】
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }
}

该过程主要工作是生成 argsForZygote 数组,该数组保存了进程的 uid、gid、groups、target-sdk、nice-name 等一系列的参数。

2.3 zygoteSendArgsAndGetResult

[-> Process.java]

private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args)
    throws ZygoteStartFailedEx {
    try {
        //其中zygoteState 【见3.3.1】
        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();
        }

        writer.flush();

        ProcessStartResult result = new ProcessStartResult();
        //等待 socket 服务端(即 zygote)返回新创建的进程 pid;
        //对于等待时长问题,Google 正在考虑此处是否应该有一个 timeout,但目前是没有的。
        result.pid = inputStream.readInt();
        if (result.pid < 0) {
            throw new ZygoteStartFailedEx("fork() failed");
        }
        result.usingWrapper = inputStream.readBoolean();
        return result;
    } catch (IOException ex) {
        zygoteState.close();
        throw new ZygoteStartFailedEx(ex);
    }
}

这个方法的主要功能是通过 socket 通道向 Zygote 进程发送一个参数列表,然后进入阻塞等待状态,直到远端的 socket 服务端发送回来新创建的进程 pid 才返回。

2.3.1 openZygoteSocketIfNeeded

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
            //向主 zygote 发起 connect() 操作
            primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
        } catch (IOException ioe) {
            ...
        }
    }

    if (primaryZygoteState.matches(abi)) {
        return primaryZygoteState;
    }

    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        //当主 zygote 没能匹配成功,则采用第二个 zygote,发起 connect()操作
        secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
    }

    if (secondaryZygoteState.matches(abi)) {
        return secondaryZygoteState;
    }
    ...

openZygoteSocketIfNeeded(abi) 方法是根据当前的 abi 来选择与 zygote 还是 zygote64 来进行通信。

既然 system_server 进程的 zygoteSendArgsAndGetResult() 方法通过 socket 向 Zygote 进程发送消息,这时便会唤醒 Zygote 进程,来响应 socket 客户端的请求(即 system_server 端),接下来的操作便是在 Zygote 来创建进程【见3.1】


三、Zygote创建进程

简单来说就是 Zygote 进程是由 init 进程而创建的,进程启动之后调用 ZygoteInit.main() 方法,经过创建 socket 管道,预加载资源后,便进程 runSelectLoop() 方法。

3.1 ZygoteInit.main

[–>ZygoteInit.java]

public static void main(String argv[]) {
    try {
        runSelectLoop(abiList); //【见3.2】
        ....
    } catch (MethodAndArgsCaller caller) {
        caller.run(); //【见4.3】
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}

后续会讲到 runSelectLoop() 方法会抛出异常 MethodAndArgsCaller,从而进入 caller.run() 方法。

3.2 runSelectLoop

[-> ZygoteInit.java]

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    //sServerSocket 是 socket 通信中的服务端,即 zygote 进程。保存到 fds[0]
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
            //处理轮询状态,当 pollFds 有事件到来则往下执行,否则阻塞在这里
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            ...
        }

        for (int i = pollFds.length - 1; i >= 0; --i) {
            //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
            //否则进入continue,跳出本次循环。
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            if (i == 0) {
                //即fds[0],代表的是 sServerSocket,则意味着有客户端连接请求;
                //则创建 ZygoteConnection 对象,并添加到 fds。//【见3.2.1】
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor()); //添加到fds.
            } else {
                //i>0,则代表通过socket接收来自对端的数据,并执行相应操作【见小节6】
                boolean done = peers.get(i).runOnce();
                if (done) {
                    peers.remove(i);
                    fds.remove(i); //处理完则从fds中移除该文件描述符
                }
            }
        }
    }
}

该方法主要功能:
客户端通过 openZygoteSocketIfNeeded() 来跟 zygote 进程建立连接。zygote 进程收到客户端连接请求后执行 accept();然后再创建 ZygoteConnection 对象,并添加到 fds 数组列表;建立连接之后,可以跟客户端通信,进入 runOnce() 方法来接收客户端数据,并执行进程创建工作。

3.2.1 acceptCommandPeer

[-> ZygoteInit.java]

private static ZygoteConnection acceptCommandPeer(String abiList) {
    try {
        return new ZygoteConnection(sServerSocket.accept(), abiList);
    } catch (IOException ex) {
        ...
    }
}

接收客户端发送过来的 connect() 操作,Zygote 作为服务端执行 accept() 操作。 再后面客户端调用 write() 写数据,Zygote 进程调用 read() 读数据。

没有连接请求时会进入休眠状态,当有创建新进程的连接请求时,唤醒 Zygote 进程,创建 Socket 通道 ZygoteConnection,然后执行 ZygoteConnection 的 runOnce() 方法。

3.3 runOnce

[-> ZygoteConnection.java]

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
        //读取 socket 客户端发送过来的参数列表
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        closeSocket();
        return true;
    }

    PrintStream newStderr = null;
    if (descriptors != null && descriptors.length >= 3) {
        newStderr = new PrintStream(new FileOutputStream(descriptors[2]));
    }

    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;

    try {
        //将 binder 客户端传递过来的参数,解析成 Arguments 对象格式
        parsedArgs = new Arguments(args);
        ...

        int [] fdsToClose = { -1, -1 };
        FileDescriptor fd = mSocket.getFileDescriptor();
        if (fd != null) {
            fdsToClose[0] = fd.getInt$();
        }

        fd = ZygoteInit.getServerSocketFileDescriptor();
        if (fd != null) {
            fdsToClose[1] = fd.getInt$();
        }
        fd = null;
        //【见3.4】
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
    } catch (Exception e) {
        ...
    }

    try {
        if (pid == 0) {
            //子进程执行
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            //【见4.1】
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

            //不应到达此处,子进程预期的是抛出异常 ZygoteInit.MethodAndArgsCaller 或者执行 exec().
            return true;
        } else {
            //父进程执行
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

3.4 forkAndSpecialize

[-> Zygote.java]

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) {
    VM_HOOKS.preFork(); //【见3.5】
    int pid = nativeForkAndSpecialize(
              uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
              instructionSet, appDataDir); //【见3.6】
    ...
    VM_HOOKS.postForkCommon(); //【见3.8】
    return pid;
}

VM_HOOKS 是 Zygote 对象的静态成员变量:VM_HOOKS = new ZygoteHooks();

3.4.1 Zygote进程

先说说 Zygote 进程,如下图:

从图中可知 Zygote 进程有4个 Daemon 子线程分别是 ReferenceQueueDaemon,FinalizerDaemon,FinalizerWatchdogDaemon,HeapTaskDaemon。图中线程名显示的并不完整是由于底层的进程结构体 task_struct 是由长度为16的char型数组保存,超过15个字符便会截断。

可能有人会问 zygote64 进程不是还有 system_server,com.android.phone 等子线程,怎么会只有4个呢?那是因为这些并不是 Zygote 子线程,而是 Zygote 的子进程。在图中用红色圈起来的是进程的VSIZE,virtual size),代表的是进程虚拟地址空间大小。线程与进程的最为本质的区别便是是否共享内存空间,图中 VSIZE 和 Zygote 进程相同的才是 Zygote 的子线程,否则就是 Zygote 的子进程。

3.5 preFork

[-> ZygoteHooks.java]

 public void preFork() {
    Daemons.stop(); //停止4个Daemon子线程【见3.5.1】
    waitUntilAllThreadsStopped(); //等待所有子线程结束【见3.5.2】
    token = nativePreFork(); //完成gc堆的初始化工作【见3.5.3】
}

3.5.1 Daemons.stop

public static void stop() {
    HeapTaskDaemon.INSTANCE.stop(); //Java堆整理线程
    ReferenceQueueDaemon.INSTANCE.stop(); //引用队列线程
    FinalizerDaemon.INSTANCE.stop(); //析构线程
    FinalizerWatchdogDaemon.INSTANCE.stop(); //析构监控线程
}

此处守护线程Stop方式是先调用目标线程interrrupt()方法,然后再调用目标线程join()方法,等待线程执行完成。

3.5.2 waitUntilAllThreadsStopped

private static void waitUntilAllThreadsStopped() {
    File tasks = new File("/proc/self/task");
    // 当/proc中线程数大于1,就出让CPU直到只有一个线程,才退出循环
    while (tasks.list().length > 1) {
        Thread.yield();
    }
}

3.5.3 nativePreFork

nativePreFork 通过JNI最终调用如下方法:

[-> dalvik_system_ZygoteHooks.cc]

static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
    Runtime* runtime = Runtime::Current();
    runtime->PreZygoteFork(); // 见下文
    if (Trace::GetMethodTracingMode() != TracingMode::kTracingInactive) {
      Trace::Pause();
    }
    //将线程转换为long型并保存到token,该过程是非安全的
    return reinterpret_cast<jlong>(ThreadForEnv(env));
}

至于 runtime->PreZygoteFork 的过程:

void Runtime::PreZygoteFork() {
    // 堆的初始化工作。这里就不继续再往下追art虚拟机
    heap_->PreZygoteFork();
}

VM_HOOKS.preFork() 的主要功能便是停止 Zygote 的4个 Daemon 子线程的运行,等待并确保 Zygote 是单线程(用于提升fork效率),并等待这些线程的停止,初始化gc堆的工作, 并将线程转换为long型并保存到token

3.6 nativeForkAndSpecialize

nativeForkAndSpecialize()通过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 debug_flags, jobjectArray rlimits,
    jint mount_external, jstring se_info, jstring se_name,
    jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
    // 将CAP_WAKE_ALARM赋予蓝牙进程
    jlong capabilities = 0;
    if (uid == AID_BLUETOOTH) {
        capabilities |= (1LL << CAP_WAKE_ALARM);
    }
    //【见3.7】
    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, instructionSet, appDataDir);
}

3.7 ForkAndSpecializeCommon

[-> com_android_internal_os_Zygote.cpp]

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, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, jstring instructionSet, jstring dataDir) {
  //设置子进程的signal信号处理函数
  SetSigChldHandler();
  //fork子进程 【见流程10.1】
  pid_t pid = fork();
  if (pid == 0) { //进入子进程
    DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符

    if (!is_system_server) {
        //对于非system_server子进程,则创建进程组
        int rc = createProcessGroup(uid, getpid());
    }
    SetGids(env, javaGids); //设置设置group
    SetRLimits(env, javaRlimits); //设置资源limit

    int rc = setresgid(gid, gid, gid);
    rc = setresuid(uid, uid, uid);

    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
    SetSchedulerPolicy(env); //设置调度策略

     //selinux上下文
    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);

    if (se_info_c_str == NULL && is_system_server) {
      se_name_c_str = "system_server";
    }
    if (se_info_c_str != NULL) {
      SetThreadName(se_name_c_str); //设置线程名为system_server,方便调试
    }
    //在Zygote子进程中,设置信号SIGCHLD的处理器恢复为默认行为
    UnsetSigChldHandler();
    //等价于调用zygote.callPostForkChildHooks() 【见流程10.2】
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                              is_system_server ? NULL : instructionSet);
    ...

  } else if (pid > 0) {
    //进入父进程,即Zygote进程
  }
  return pid;
}


3.7.1 fork()

fork() 采用 copy on write 技术,这是linux创建进程的标准方法,调用一次,返回两次,返回值有3种类型。

父进程中,fork返回新创建的子进程的pid;
子进程中,fork返回0;
当出现错误时,fork返回负数。(当进程数超过上限或者系统内存不足时会出错)

fork()的主要工作是寻找空闲的进程号pid,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。 Zygote 进程是所有Android进程的母体,包括 system_server 和各个App进程。zygote 利用 fork()方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A。其中下图中Zygote进程的libc、vm、preloaded classes、preloaded resources是如何生成的,可查看另一个文章Android系统启动-zygote篇,见下图:

copy-on-write过程:当父子进程任一方修改内存数据时(这是on-write时机),才发生缺页中断,从而分配新的物理内存(这是copy操作)。

copy-on-write原理:写时拷贝是指子进程与父进程的页表都所指向同一个块物理内存,fork过程只拷贝父进程的页表,并标记这些页表是只读的。父子进程共用同一份物理内存,如果父子进程任一方想要修改这块物理内存,那么会触发缺页异常(page fault),Linux收到该中断便会创建新的物理内存,并将两个物理内存标记设置为可写状态,从而父子进程都有各自独立的物理内存。

3.7.1.1 fork.cpp

[-> bionic/fork.cpp]

#define FORK_FLAGS (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD)
int fork() {
  __bionic_atfork_run_prepare();

  pthread_internal_t* self = __get_thread();

  //fork期间,获取父进程pid,并使其缓存值无效
  pid_t parent_pid = self->invalidate_cached_pid();
  //系统调用
  int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, NULL, &(self->tid));
  if (result == 0) {
    self->set_cached_pid(gettid());
    __bionic_atfork_run_child(); //fork完成执行子进程回调方法
  } else {
    self->set_cached_pid(parent_pid);
    __bionic_atfork_run_parent(); //fork完成执行父进程回调方法
  }
  return result;
}

功能说明:在执行syscall的前后都有相应的回调方法。

__bionic_atfork_run_prepare: fork完成前,父进程回调方法
__bionic_atfork_run_child: fork完成后,子进程回调方法
__bionic_atfork_run_paren: fork完成后,父进程回调方法

以上3个方法的实现都位于 bionic/pthread_atfork.cpp。如果有需要,可以扩展该回调方法,添加相关的业务需求。

3.7.2 Zygote.callPostForkChildHooks

[-> Zygote.java]

private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer, String instructionSet) {
    //调用 ZygoteHooks.postForkChild()
    VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
}

[-> ZygoteHooks.java]

public void postForkChild(int debugFlags, String instructionSet) {
    //【见3.7.3】
    nativePostForkChild(token, debugFlags, instructionSet);
    Math.setRandomSeedInternal(System.currentTimeMillis());
}

在这里,设置了新进程 Random 随机数种子为当前系统时间,也就是在进程创建的那一刻就决定了未来随机数的情况,也就是伪随机。

3.7.3 nativePostForkChild

nativePostForkChild 通过JNI最终调用调用如下方法:

[-> dalvik_system_ZygoteHooks.cc]

static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags, jstring instruction_set) {
    //此处token是由【3.5.3】创建的,记录着当前线程
    Thread* thread = reinterpret_cast<Thread*>(token);
    //设置新进程的主线程id
    thread->InitAfterFork();
    ..
    if (instruction_set != nullptr) {
      ScopedUtfChars isa_string(env, instruction_set);
      InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
      Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
      if (isa != kNone && isa != kRuntimeISA) {
        action = Runtime::NativeBridgeAction::kInitialize;
      }
      //【见流程3.7.4】
      Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
    } else {
      Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
    }
}


3.7.4 DidForkFromZygote

[-> Runtime.cc]

void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
  is_zygote_ = false;
  if (is_native_bridge_loaded_) {
    switch (action) {
      case NativeBridgeAction::kUnload:
        UnloadNativeBridge(); //卸载用于跨平台的桥连库
        is_native_bridge_loaded_ = false;
        break;
      case NativeBridgeAction::kInitialize:
        InitializeNativeBridge(env, isa);//初始化用于跨平台的桥连库
        break;
    }
  }
  //创建Java堆处理的线程池
  heap_->CreateThreadPool();
  //重置gc性能数据,以保证进程在创建之前的GCs不会计算到当前app上。
  heap_->ResetGcPerformanceInfo();
  if (jit_.get() == nullptr && jit_options_->UseJIT()) {
    //当flag被设置,并且还没有创建JIT时,则创建JIT
    CreateJit();
  }
  //设置信号处理函数
  StartSignalCatcher();
  //启动JDWP线程,当命令debuger的flags指定"suspend=y"时,则暂停runtime
  Dbg::StartJdwp();
}

关于信号处理过程,其代码位于signal_catcher.cc文件中,后续会单独讲解。

3.8 postForkCommon

[-> ZygoteHooks.java]

public void postForkCommon() {
    Daemons.start();
}

public static void start() {
    ReferenceQueueDaemon.INSTANCE.start();
    FinalizerDaemon.INSTANCE.start();
    FinalizerWatchdogDaemon.INSTANCE.start();
    HeapTaskDaemon.INSTANCE.start();
}

VM_HOOKS.postForkCommon 的主要功能是在 fork 新进程后,启动 Zygote 的4个 Daemon 线程,java 堆整理,引用队列,以及析构线程。

3.9. forkAndSpecialize 小结

该方法主要功能:

(1) preFork:停止Zygote的4个Daemon子线程的运行,初始化gc堆;

(2) nativeForkAndSpecialize:调用fork()创建新进程,设置新进程的主线程id,重置gc性能数据,设置信号处理函数等功能。

(3) postForkCommon:启动4个Deamon子线程。

其调用关系链:

Zygote.forkAndSpecialize
    ZygoteHooks.preFork
        Daemons.stop
        ZygoteHooks.nativePreFork
            dalvik_system_ZygoteHooks.ZygoteHooks_nativePreFork
                Runtime::PreZygoteFork
                    heap_->PreZygoteFork()
    Zygote.nativeForkAndSpecialize
        com_android_internal_os_Zygote.ForkAndSpecializeCommon
            fork()
            Zygote.callPostForkChildHooks
                ZygoteHooks.postForkChild
                    dalvik_system_ZygoteHooks.nativePostForkChild
                        Runtime::DidForkFromZygote
    ZygoteHooks.postForkCommon
        Daemons.start

时序图:

到此App进程已完成了创建的所有工作,接下来开始新创建的App进程的工作。在前面ZygoteConnection.runOnce方法中,zygote进程执行完forkAndSpecialize()后,新创建的App进程便进入handleChildProc()方法,下面的操作运行在App进程。


四、新进程运行

在前面【3.3】runOnce() 过程中调用 forkAndSpecialize() 创建完新进程后,返回值pid=0(即运行在子进程)继续开始执行 handleChildProc() 方法。

4.1 handleChildProc

[-> ZygoteConnection.java]

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
    throws ZygoteInit.MethodAndArgsCaller {

    //关闭Zygote的socket两端的连接
    closeSocket();
    ZygoteInit.closeServerSocket();

    if (descriptors != null) {
        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);
        }
    }

    if (parsedArgs.niceName != null) {
        //设置进程名
        Process.setArgV0(parsedArgs.niceName);
    }

    if (parsedArgs.invokeWith != null) {
        //据说这是用于检测进程内存泄露或溢出时场景而设计,后续还需要进一步分析。
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(),
                pipeFd, parsedArgs.remainingArgs);
    } else {
        //执行目标类的main()方法 【见流程14】
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                parsedArgs.remainingArgs, null);
    }
}


4.2 zygoteInit

[–>RuntimeInit.java]

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
    throws ZygoteInit.MethodAndArgsCaller {

    redirectLogStreams(); //重定向log输出

    commonInit(); // 通用的一些初始化【见4.2.1】
    nativeZygoteInit(); // zygote初始化 【见4.2.2】
    applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化【见流程14.3】
}


4.2.1 commonInit

[–>RuntimeInit.java]

private static final void commonInit() {
    // 设置默认的未捕捉异常处理方法
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

    // 设置市区,中国时区为"Asia/Shanghai"
    TimezoneGetter.setInstance(new TimezoneGetter() {
        public String getId() {
            return SystemProperties.get("persist.sys.timezone");
        }
    });
    TimeZone.setDefault(null);

    //重置log配置
    LogManager.getLogManager().reset();
    new AndroidConfig();

    // 设置默认的HTTP User-agent格式,用于 HttpURLConnection。
    String userAgent = getDefaultUserAgent();
    System.setProperty("http.agent", userAgent);

    // 设置socket的tag,用于网络流量统计
    NetworkManagementSocketTagger.install();
}

默认的HTTP User-agent格式,例如:"Dalvik/1.1.0 (Linux; U; Android 6.0.1;LenovoX3c70 Build/LMY47V)".

4.2.2 nativeZygoteInit

nativeZygoteInit()所对应的jni方法如下:

[–>AndroidRuntime.cpp]

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz) {
    //此处的gCurRuntime为AppRuntime,是在AndroidRuntime.cpp中定义的
    gCurRuntime->onZygoteInit();
}


4.2.2.1 onZygoteInit

[–>app_main.cpp]

virtual void onZygoteInit() {
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); //启动新binder线程
}

ProcessState::self():主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作。startThreadPool()是创建一个新的binder线程,不断进行talkWithDriver().
startThreadPool(): 启动Binder线程池, 详见进程的Binder线程池工作过程

4.2.3 applicationInit

[–>RuntimeInit.java]

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) 
    throws ZygoteInit.MethodAndArgsCaller {
    //true代表应用程序退出时不调用 AppRuntime.onExit(),否则会在退出前调用
    nativeSetExitWithoutCleanup(true);

    //设置虚拟机的内存利用率参数值为0.75
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try {
        args = new Arguments(argv); //解析参数
    } catch (IllegalArgumentException ex) {
        return;
    }

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    //调用 startClass 的static方法 main() 【见4.3】
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

此处args.startClass为”android.app.ActivityThread”。

4.3 invokeStaticMain

[–>RuntimeInit.java]

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
    throws ZygoteInit.MethodAndArgsCaller {

    Class<?> cl = Class.forName(className, true, classLoader);

    Method m = cl.getMethod("main", new Class[] { String[].class });

    int modifiers = m.getModifiers();
    ...

    //通过抛出异常,回到 ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率。【见4.4】
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

invokeStaticMain() 方法中抛出的异常 MethodAndArgsCaller caller,该方法的参数m是指 main() 方法, argv 是指 ActivityThread. 根据前面的【3.1】中可知,下一步进入 caller.run() 方法,也就是 MethodAndArgsCaller.run()。

4.4. MethodAndArgsCaller

[–>ZygoteInit.java]

public static class MethodAndArgsCaller extends Exception implements Runnable {

    public void run() {
        try {
            //根据传递过来的参数,此处反射调用 ActivityThread.main()方法【见4.5】
            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);
        }
    }
}

到此,总算是进入到了 ActivityThread 类的 main() 方法。

4.5 ActivityThread.main

[–> ActivityThread.java]

public static void main(String[] args) {
    ...
    Environment.initForCurrentUser();
    ...
    Process.setArgV0("<pre-initialized>");
    //创建主线程looper
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    //attach到系统进程
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    //主线程进入循环状态
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

 

五、总结

Process.start() 方法是阻塞操作,等待直到进程创建完成并返回相应的新进程pid,才完成该方法。

当App第一次启动时或者启动远程 Service,即 AndroidManifest.xml 文件中定义了 process:remote 属性时,都需要创建进程。比如当用户点击桌面的某个App图标,桌面本身是一个app(即 Launcher App),那么 Launcher 所在进程便是这次创建新进程的发起进程,该通过 binder 发送消息给 system_server 进程,该进程承载着整个 java framework 的核心服务。system_server 进程从 Process.start 开始,执行创建进程,流程图(以进程的视角)如下:

上图中,system_server 进程通过 socket IPC 通道向 zygote 进程通信,zygote 在 fork 出新进程后由于 fork 调用一次,返回两次,即在 zygote 进程中调用一次,在 zygote 进程和子进程中各返回一次,从而能进入子进程来执行代码。该调用流程图的过程:

(1) system_server进程(即【2.1~2.3):通过Process.start()方法发起创建新进程请求,会先收集各种新进程uid、gid、nice-name等相关的参数,然后通过socket通道发送给zygote进程;

(2) zygote进程(即【3.1~3.9】):接收到system_server进程发送过来的参数后封装成Arguments对象,图中绿色框forkAndSpecialize()方法是进程创建过程中最为核心的一个环节(详见流程6),其具体工作是依次执行下面的3个方法:
    a. preFork():先停止Zygote的4个Daemon子线程(java堆内存整理线程、对线下引用队列线程、析构线程以及监控线程)的运行以及初始化gc堆;
    b. nativeForkAndSpecialize():调用linux的fork()出新进程,创建Java堆处理的线程池,重置gc性能数据,设置进程的信号处理函数,启动JDWP线程;
    c. postForkCommon():在启动之前被暂停的4个Daemon子线程。

(3) 新进程(即【4.1~4.3】):进入 handleChildProc() 方法,设置进程名,打开 binder 驱动,启动新的 binder 线程;然后设置art虚拟机参数,再反射调用目标类的 main() 方法,即 Activity.main() 方法。

再之后的流程,如果是 startActivity 则将要进入 Activity 的 onCreate/onStart/onResume 等生命周期;如果是 startService 则将要进入Service的 onCreate 等生命周期。

system_server 进程等待 zygote 返回进程创建完成(ZygoteConnection.handleParentProc), 一旦 Zygote.forkAndSpecialize() 方法执行完成, 那么分道扬镳, zygote 告知 system_server 进程进程已创建, 而子进程继续执行后续的 handleChildProc 操作.

Tips: 【3.8】RuntimeInit.java 的方法 nativeZygoteInit() 会调用到 onZygoteInit(),这个过程中有 startThreadPool() 创建 Binder 线程池。也就是说每个进程无论是否包含任何 activity 等组件,一定至少会包含一个 Binder 线程。

 

参考:

理解Android进程创建流程:http://gityuan.com/2016/03/26/app-process-create/#forkandspecialize-1

posted on 2023-05-07 00:59  Hello-World3  阅读(478)  评论(0编辑  收藏  举报

导航