赞
踩
在 Android 系统中,DVM(Dalvik 虚拟机)/ART,系统服务进程 system_server 以及应用程序进程都是由 Zygote 进程来创建的(而 Native 程序,也就是 C/C++ 开发的程序则是由 init 进程创建启动的)。Zygote 进程也称孵化器,通过 fork(复制进程) 的形式来创建应用程序进程和 system_server 进程,由于 Zygote 进程在启动时会创建 DVM 或者 ART ,因此通过 fork 而创建的应用程序进程和 system_server 进程可以在内部获取一个 DVM 或者 ART 的实例副本。
Zygote 进程是在 init 进程启动时创建的,起初,Zygote 进程的名称并不是 Zygote,而是 app_process。Zygote 进程启动后,Linux 系统下的 pctrl 系统会调用 app_process,将其名称换成了 Zygote。
Zygote 是一个 C/S模型。Zygote 进程作为服务端,主要负责创建 Java 虚拟机,加载系统资源,启动 system_server 进程以及后续运行过程中启动普通的应用程序进程。其他进程作为客户端向它发送 fork 请求,Zygote 进程接收到这个请求后会 fork 出一个新的进程。
Zygote 通过 Socket 的方式和其他进程进行通信,这里的“其他进程”主要指的是系统服务进程 system_server。
在 Linux 系统中,调用 fork 函数创建子进程的时候,不会复制父进程的内存,而是父子进程共享一个内存空间,只有当子进程或者父进程对内存数据进行修改时才会进行内存复制,从而,父进程和子进程才有各自的内存空间。在此之前,只会以只读的方式共享。
写时拷贝(copy-on-write):等到修改数据的时候才真正的分配内存空间,是一种可以推迟甚至避免拷贝数据的技术。这是对程序性能的优化,这样做的目的是为了避免不必要的拷贝。
Zygote 作为孵化器,可以提前加载一些资源,这样 fork 出的子进程就可以直接使用这些资源,而不用重新加载。比如,system_server 进程就可以直接使用 Zygote 进程中的 JNI 函数、共享库、常用类以及主题资源。
在 init进程启动过程 中讲到,init 进程会解析 init.rc 文件,然后创建和加载 service 字段指定的进程,Zygote 进程就是以这种方式被 init 进程加载的。在 init.rc 文件中采用 Import 类型语句来引入 Zygote 启动脚本,这些启动脚本都是由 Android 初始化语言(Android Init Language)来编写的:
// /system/core/rootdir/init.rc
import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc // ${ro.zygote} 由厂商定义,与平台无关
可以看出,init.rc 不会直接引入一个固定的文件,而是根据 ro.zygote 的内容来引入不同的文件。
从 Android 5.0 开始,开始支持 64 位程序,Zygote 也就有了 32 位和 64 位的区别,所以用 ro.zygote 属性来控制使用不同的 Zygote 启动脚本,从而也就启动了不同版本的 Zygote 进程,从而也就启动了不同版本的 Zygote 进程,ro.zygote 属性的取值有以下 4 种:
这些 Zygote 启动脚本都放在 system/core/rootdir 目录中,如下所示:
Android 初始化语言的 Service 类型语句:
service <name> <pathname> [ <argument>]* // <service 的名字><执行程序路径><传递参数>
<option> // option 是 Service 的修饰词,影响什么时候、如何启动 Service
<option>
...
以 64 位处理器为例,init.zygote64_32.rc 的代码如下所示:
脚本中有两个 Service 类型语句,说明会启动两个 Zygote 进程,一个名称为 zygote,执行程序为 app_process64,作为主模式;另一个名称为 zygote_secondary,执行程序为 app_process32,作为辅模式。其他的脚本文件与此类似。
以下是 Zygote 启动的时序图:
init 进程启动 Zygote 进程时主要是通过调用 app_main.cpp 文件中的 main 函数中的 AppRuntime.start 方法来启动 Zygote 进程的。
// /frameworks/base/cmds/app_process/app_main.cpp int main(int argc, char* const argv[]) { ... // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { // 1 zygote = true; // 2 如果当前运行在 Zygote 进程中,则将 zygote 设置为 true niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { // 3 startSystemServer = true; // 4 如果当前运行在 system_server 进程中,则将 startSystemServer 设为 true } ... } ... if (zygote) { // 5 如果运行在 Zygote 进程中 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 6 } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); } } AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
Zygote 进程都是通过 fork 自身来创建子进程的,这样,Zygote 进程以及它的子进程都可以进入 app_main.cpp 的 main 函数,因此,main 函数中为了区分当前运行在哪个进程, 会在注释 1 处判断参数 arg 中是否包含了 --zygote,如果包含了则说明 main 函数是运行在 Zygote 进程中的,并在注释 2 处将 Zygote 设置为 true。同理在注释 3 处判断参数 arg 中是否包含 --start-system-server,如果包含了则说明 main 函数试运行在 system_server 进程中的,并在注释 4 处将 startSystemServer 设置为 true。
在 app_main.cpp 的 main 函数中,主要做的事情是参数解析,这个函数有两种启动模式:
两者最终到示调用 AppRuntime/AndroidRuntime.start 函数,加载 ZygoteInit 或者 RuntimeInit 两个 Java 类,并将之前的参数也传入进去。
注释 5 处,如果 zygote 为 true,就说明当前运行在 zygote 进程中,就会调用注释 6 处的 AppRuntime 的 start 函数。AppRuntime 继承自 AndroidRuntime,且没有重写 start 方法,因此,Zygote 的流程进入了 AndroidRutime 中,代码如下所示:
// /frameworks/base/core/jni/AndroidRuntime.cpp void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... /* start the virtual machine 启动虚拟机 */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { // 1 return; } onVmCreated(env); /* * Register android functions. 为虚拟机注册 JNI 方法 */ if (startReg(env) < 0) { // 2 ALOGE("Unable to register all android natives\n"); return; } ... // 从 app_main 的 main 函数得知 className 为 com.android.internel.os.ZygoteInit classNameStr = env->NewStringUTF(className); // 3 assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. * 将 className 的 "." 替换为 “/” */ char* slashClassName = toSlashClassName(className != NULL ? className : ""); // 4 // 找到 ZygoteInit jclass startClass = env->FindClass(slashClassName); // 5 if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { // 找到 ZygoteInit 的 main 函数 jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); // 6 if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { // 通过 JNI 调用 ZygoteInit 的 main 方法 env->CallStaticVoidMethod(startClass, startMeth, strArray); // 7 ... }
在注释 1 出调用 startVm 函数来创建 Java 虚拟机,在注释 2 处调用 startReg 函数为 Java 虚拟机注册 JNI 方法。在注释 3 处的 className 的值是传进来的参数,它的值为 com.android.internal.os.ZygoteInit。在注释 4 处通过 toSlashClassName 函数,将 className 的 . 替换成 /,替换后的值为 com/android/internal/os/ZygoteInit,并赋值给 slashClassName,接着在注释 5 处根据 slashClassName 找到 ZygoteInit,找到 ZygoteInit 后,在注释 6 处调用 ZygoteInit.main 方法。最终会在注释 7 处通过 JNI 调用 ZygoteInit.main 方法。这里为什么要用 JNI 呢?因为 ZygoteInit.main 方法是由 Java 语言编写的,当前的运行逻辑在 Native 中,这就需要通过 JNI 来调用 Java。这样,Zygote 就从 Native 层进入了 Java 框架层。
通过 JNI 调用 ZygoteInit.main 方法后,Zygote 就进入了 Java 框架层,此前是没有任何代码进入 Java 框架层的,换句话说是 Zygote 开创了 Java 框架层,ZygoteInit.main 方法代码如下:
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java public static void main(String[] argv) { // ZygoteServer是Zygote进程的Socket通讯服务端的管理类 ZygoteServer zygoteServer = null; ... Runnable caller; try { ... final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); ... // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. if (!enableLazyPreload) { bootTimingsTraceLog.traceBegin("ZygotePreload"); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload(bootTimingsTraceLog); // 1 预加载类和资源 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload } ... zygoteServer = new ZygoteServer(isPrimaryZygote); // 2 创建一个 Server 端的 Socket if (startSystemServer) { // 3 启动 system_server 进程 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); // 4 等待 AMS/ATMS 请求 } catch (Throwable ex) { Log.e(TAG, "System zygote died with fatal exception", ex); throw ex; } finally { if (zygoteServer != null) { zygoteServer.closeServerSocket(); } } // We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } }
注释 1 处预加载类和资源。注释 2 处创建一个 Server 端的 Socket 通道,用于响应 ATMS/AMS 请求 Zygote 来创建新的应用程序进程的请求。注释 3 处启动 system_server 进程,这样系统的服务也会由 system_server 进程启动起来。注释 4 处调用 ZygoteServer.runSelectLoop 方法来等待 ATMS/AMS 创建新进程的请求。
由以上可知,ZygoteInit.main 方法中主要做了 4 件事情:
对于创建 Server 端的 Socket 通信,代码如下所示:
// /frameworks/base/core/java/com/android/internal/os/ZygoteServer.java ZygoteServer(boolean isPrimaryZygote) { mUsapPoolEventFD = Zygote.getUsapPoolEventFD(); if (isPrimaryZygote) { mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME); // 1 mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket( Zygote.USAP_POOL_PRIMARY_SOCKET_NAME); } else { mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME); // 2 mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket( Zygote.USAP_POOL_SECONDARY_SOCKET_NAME); } mUsapPoolSupported = true; fetchUsapPoolPolicyProps(); }
注释 1 和注释 2 处均调用了 Zygote.createManagedSocketFromInitSocket 方法:
// /frameworks/base/core/java/com/android/internal/os/Zygote.java private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"; public static final String PRIMARY_SOCKET_NAME = "zygote"; public static final String SECONDARY_SOCKET_NAME = "zygote_secondary"; static LocalServerSocket createManagedSocketFromInitSocket(String socketName) { int fileDesc; // 拼接 Socket 的名称 final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; // 1 try { // 得到 Socket 的环境变量值 String env = System.getenv(fullSocketName); // 2 // 将 Socket 环境变量的值转换为文件描述符的参数 fileDesc = Integer.parseInt(env); // 3 } catch (RuntimeException ex) { throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex); } try { // 创建文件描述符 FileDescriptor fd = new FileDescriptor(); // 4 fd.setInt$(fileDesc); // 5 // 创建服务器端的 Socket return new LocalServerSocket(fd); // 6 } catch (IOException ex) { throw new RuntimeException( "Error building socket from file descriptor: " + fileDesc, ex); } }
在注释 1 处拼接 Socket 的名称,其中 ANDROID_SOCKET_PREFIX 的值为 “ANDROID_SOCKET_”,socketName 是传进来的值,等于 “zygote” 或者 “zygote_secondary”,因此 fullScoketName 的值为 “ANDROID_SOCKET_zygote” 或者 “ANDROID_SOCKET_zygote_secondary”。在注释 2 处将 fullSocketName 转换为环境变量的值,再在注释 3 出转换为文件描述符的参数。在注释 4 处创建文件描述符,并在注释 5 出传入此前转换的文件操作符参数。在注释 6 处创建 LocalServerSocket,也就是服务端的 Socket,并将这个文件操作符作为参数传进去。在 Zygote 进程将 SystemServer 进程启动后,就会在这个 服务器端的 Socket 上等待 AMS/ATMS 请求 Zygote 进程来创建新的应用程序进程。
对于启动 system_server 进程:
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { ... /* Hardcoded command line to start the system server * 创建 args 数组,这个数组用来保存启动 system_server 的启动参数 */ String[] args = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "com.android.server.SystemServer", }; // 1 ZygoteArguments parsedArgs; int pid; try { ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args); // 2 try { parsedArgs = ZygoteArguments.getInstance(commandBuffer); // 3 } catch (EOFException e) { throw new AssertionError("Unexpected argument error for forking system server", e); } ... /* Request to fork the system server process * 创建一个子进程,也就是 system_server 进程 */ pid = Zygote.forkSystemServer( parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); // 4 } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process 当前代码逻辑运行在子进程中 */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); // 处理 system_server 进程 return handleSystemServerProcess(parsedArgs); // 5 } return null; }
注释 1 处的代码用来创建 args 数组,这个数组用来保存和启动 system_server 的启动参数,其中可以看出 system_server 进程的用户 id 和用户组 id 被设置为 1000,并且拥有用户组 1001~1010、1018、1021、1032、3001~3010 的权限,进程名为 system_server,启动的类名为 com.android.server.SystemServer。在注释 2 出将 args 数组封装成 ZygoteCommandBuffer 对象然后传递给注释 3 处 ZygoteArguments.getInstance 方法封装成 ZygoteArguments 对象供注释 4 处的 Zygote.forkSystemServer 函数调用。
Zygote.forkSystemServer 方法内部会调用 nativeForkSystemServer 这个 Native 方法,nativeForkSystemServer 方法最终会通过 fork 函数在当前进程创建一个子进程,也就是 system_server 进程,如果 forkSystemServer 方法返回的 pid 的值为 0,就表示当前的代码运行在新创建的子进程中。继而执行注释 5 出的 handleSystemServerProcess 来处理 system_server 进程。
// /frameworks/base/core/java/com/android/internal/os/Zygote.java
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
// Set the Java Language thread priority to the default value for new apps.
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
ZygoteHooks.postForkCommon();
return pid;
}
对于 ZygoteServer.runSelectLoop 方法:
// /frameworks/base/core/java/com/android/internal/os/ZygoteServer.java Runnable runSelectLoop(String abiList) { ArrayList<FileDescriptor> socketFDs = new ArrayList<>(); ArrayList<ZygoteConnection> peers = new ArrayList<>(); socketFDs.add(mZygoteSocket.getFileDescriptor()); // 1 peers.add(null); mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; // 无限循环等待 AMS/ATMS 的请求 while (true) { ... int pollIndex = 0; for (FileDescriptor socketFD : socketFDs) { // 2 pollFDs[pollIndex] = new StructPollfd(); pollFDs[pollIndex].fd = socketFD; pollFDs[pollIndex].events = (short) POLLIN; ++pollIndex; } ... int pollReturnValue; try { pollReturnValue = Os.poll(pollFDs, pollTimeoutMs); } 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) { // 3 if ((pollFDs[pollIndex].revents & POLLIN) == 0) { continue; } if (pollIndex == 0) { // Zygote server socket ZygoteConnection newPeer = acceptCommandPeer(abiList); // 4 peers.add(newPeer); socketFDs.add(newPeer.getFileDescriptor()); } else if (pollIndex < usapPoolEventFDIndex) { // Session socket accepted from the Zygote server socket try { ZygoteConnection connection = peers.get(pollIndex); boolean multipleForksOK = !isUsapPoolEnabled() && ZygoteHooks.isIndefiniteThreadSuspensionSafe(); final Runnable command = connection.processCommand(this, multipleForksOK); // TODO (chriswailes): Is this extra check necessary? if (mIsForkChild) { if (command == null) { throw new IllegalStateException("command == null"); } return command; } else { if (command != null) { throw new IllegalStateException("command != null"); } if (connection.isClosedByPeer()) { // 5 connection.closeSocket(); peers.remove(pollIndex); socketFDs.remove(pollIndex); } } } catch (Exception e) { ... } finally { ... } } ... } ... } ... } }
注释 1 处的 mZygoteSocket 就是创建的 服务器端的 Socket,调用 mZygoteSocket.getFileDescriptor() 方法用来获得该 Socket 的 fd 字段的值并添加到 fd 列表 fds 中。接下来无限循环用来等待 ATMS/AMS 来请求 Zygote 进程创建新的应用程序进程。注释 2 处通过遍历将 fds 存储的信息转移到 pollFds 数组中。在注释 3 处对 pollFDs 进行遍历,如 果 pollIndex == 0,说明服务器端 Socket 与客户端连接上了,换句话说就是,当前 Zygote 和 ATMS/AMS 建立了连接。注释 4 处通过 acceptCommandPeer 方法得到 ZygoteConnection 类并添加到 Socket 连接 peers 表中接着将该 ZygoteConnection 的 fd 添加到 fd 列表 fds 中,以便可以接收到 ATMS/AMS 发送过来的请求。如果 pollIndex 不等于 0,则说明 ATMS/AMS 向 Zygote 进程发送了一个创建应用进程的请求,则在注释 5 处调用 ZygoteConnection.isCloseByPeer() 方法来创建一个新的应用程序进程,并在成功创建后将这个连接从 Socket 连接列表 peers 和 fd 列表 fds 中清除。
Zygote 进程启动工作了以下几件事:
fork 函数:
pid_t fork(void)
返回值分为两种情况:
使用 fork 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文(进程执行活动的全过程的静态描述)、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号。子进程所独有的只有它的进程号,计时器等(只有小量信息)。因此,使用 fork 函数的代价是很大的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。