本文主要是介绍Android系统启动系列3 zygote进程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一 概述
上一篇文章分析了 init 进程的整个启动流程。init 进程启动后,会解析 rc 文件,然后启动很多进程,其中很重要的一个进程就是 zygote 进程,zygote 进程又称受精卵进程, 所对应的可执行程序为 app_process,所对应的源文件是 app_main.cpp,进程名为 zygote,zygote 是 Android 系统创建的第一个 java 进程,它是所有 java 进程的父进程,zygote 进程最大意义是作为一个 Socket 的 Server 端,接收着来自四面八方的其它进程发出的进程创建请求,Android 中所有的应用进程的创建都是由一个应用进程通过 Binder 发送请求给 SystemServer 进程,SystemServer 进程再发送 Socket 消息给 zygote 进程,统一由 zygote 进程创建出来的。典型的 C/S 架构.下图为 zygote 进程在系统中的地位,其中图中红色标注为 Binder 通信方式,蓝色标注为 Socket 通信方式.
话说为什么 Android 系统采用这种架构呢,为什么所有进程的创建都是由 zygote 来做呢?原因有如下两点:
- zygote 进程在启动的时候会创建一个虚拟机实例,因此通过 zygote 这个父进程,创建的子进程都会继承这个虚拟机实例,app 中的 java 代码可以得到翻译执行。
- 进程与进程之间需要跨进程通信,由 zygote 进程作为父进程还可以获得一个 Binder 线程池,这样进程之间就可以使用 Binder 进行跨进程通信了。
基于以上两点,可以理解 zygote 进程为什么是所有应用进程的父进程的原因.
涉及到的源码路徑
/system/core/rootdir/init.rc
/system/core/init/main.cpp
/system/core/init/init.cpp
/system/core/rootdir/init.zygote64_32.rc
/frameworks/base/cmds/app_process/app_main.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp
/libnativehelper/JniInvocation.cpp
/frameworks/base/core/java/com/android/internal/os/Zygote.java
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
/frameworks/base/core/java/android/net/LocalServerSocket.java
/system/core/libutils/Threads.cpp
二 zygote是如何被启动的
我们知道 init 进程启动后,会解析 init.rc 文件,然后创建和加载 service 字段指定的进程。zygote 进程就是以这种方式,被 init 进程加载并启动的。在 /system/core/rootdir/init.rc 中,通过如下引用来 load zygote 的 rc:
import /init.${ro.zygote}.rc
其中 ${ro.zygote} 由各个厂家使用,现在的主流厂家基本使用 zygote64_32,因此,我们的 rc 文件为 init.zygote64_32.rc,我们来看这个文件:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygoteclass mainpriority -20user rootgroup root readprocsocket zygote stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasksservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preloadclass mainpriority -20user rootgroup root readprocsocket zygote_secondary stream 660 root systemonrestart restart zygotewritepid /dev/cpuset/foreground/tasks
从这个 rc 文件中可以看到启动了二个进程,分别为 zygote 和 zygote_secondary,启动路徑为 /system/bin/app_process64 和 /system/bin/app_process32,对应的代码入口为:frameworks/base/cmds/app_process/app_main.cpp
三 zygote启动流程
3.1 zygote启动时序图
- init 进程通过解析 init.zygote64_32.rc 来启动位于 /system/bin/app_process64 的 zygote 进程,入口为 app_main.cpp
- 调用 AndroidRuntime 的 startVM() 方法创建虚拟机,再调用 startReg() 注册 JNI 函数
- 通过 JNI 方式调用 ZygoteInit.main(),第一次进入 Java 世界
- registerZygoteSocket() 建立 socket 通道,zygote 作为通信的服务端,用于响应客户端请求
- preload() 预加载通用类、drawable 和 color 资源、openGL 以及共享库以及 WebView,用于提高 app 启动效率
- zygote 完成大部分工作,接下来再通过 startSystemServer(),fork system_server 进程,它同时也是上层 framework 框架的运行载体
- zygote 任务完成,调用 runSelectLoop(),随时待命,当接收到创建新进程的请求时,立即唤醒并执行相应工作
3.2 zygote入口函数main
先来一张 zygote 在 native C 世界的代码调用图,如下:
frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{//zygote传入的参数argv为“-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote”//zygote_secondary传入的参数argv为“-Xzygote /system/bin --zygote --socket-name=zygote_secondary”AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));........while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) {zygote = true;//对于64位系统nice_name为zygote64; 32位系统为zygoteniceName = ZYGOTE_NICE_NAME;} else if (strcmp(arg, "--start-system-server") == 0) {//是否需要启动system serverstartSystemServer = true;} else if (strcmp(arg, "--application") == 0) {//启动进入独立的程序模式application = true;} else if (strncmp(arg, "--nice-name=", 12) == 0) {//niceName 为当前进程别名,区别abi型号niceName.setTo(arg + 12);} else if (strncmp(arg, "--", 2) != 0) {className.setTo(arg);break;} else {--i;break;}}........if (!className.isEmpty()) { //className不为空,说明是application启动模式........} else {//进入zygote模式,新建Dalvik的缓存目录:/data/dalvik-cachemaybeCreateDalvikCache();if (startSystemServer) { //加入start-system-server参数args.add(String8("start-system-server"));}String8 abiFlag("--abi-list=");abiFlag.append(prop);args.add(abiFlag); //加入--abi-list=参数// In zygote mode, pass all remaining arguments to the zygote// main() method.for (; i < argc; ++i) { //将剩下的参数加入argsargs.add(String8(argv[i]));}}........if (!niceName.isEmpty()) {//设置一个“好听的昵称” zygote\zygote64,之前的名称是app_processruntime.setArgv0(niceName.string(), true /* setProcName */);}if (zygote) {//如果是zygote启动模式,则加载ZygoteInitruntime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {//如果是application启动模式,则加载RuntimeInitruntime.start("com.android.internal.os.RuntimeInit", args, zygote);} else {//没有指定类名或zygote,参数错误fprintf(stderr, "Error: no class name or --zygote supplied.\n");app_usage();LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");}
}
zygote 本身是一个 Native 的应用程序,刚开始的进程名称为“app_process”,运行过程中,通过调用 setArgv0 将名字改为 zygote 或者 zygote64 (根据操作系统而来),最后通过 runtime 的 start() 方法来真正的加载虚拟机并进入 java 世界。
3.3 AndroidRuntime.start
frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{ALOGD(">>>>>> START %s uid %d <<<<<<\n",className != NULL ? className : "(unknown)", getuid());........JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;//虚拟机创建,主要是关于虚拟机参数的设置if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {return;}........ // 注册JNI方法if (startReg(env) < 0) {ALOGE("Unable to register all android natives\n");return;} jclass stringClass;jobjectArray strArray;jstring classNameStr; //等价 strArray= new String[options.size() + 1];stringClass = env->FindClass("java/lang/String"); //等价 strArray[0] = "com.android.internal.os.ZygoteInit"strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);classNameStr = env->NewStringUTF(className);env->SetObjectArrayElement(strArray, 0, classNameStr); //strArray[1] = "start-system-server";//strArray[2] = "--abi-list=xxx";//其中xxx为系统响应的cpu架构类型,比如arm64-v8a.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);} //将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"char* slashClassName = toSlashClassName(className != NULL ? className : "");jclass startClass = env->FindClass(slashClassName);//找到Zygoteinit类if (startClass == NULL) {ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);} else {//找到这个类后就继续找成员函数main方法的Mehtod IDjmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");if (startMeth == NULL) {ALOGE("JavaVM unable to find main() in '%s'\n", className);} else {// 通过反射调用ZygoteInit.main()方法env->CallStaticVoidMethod(startClass, startMeth, strArray);}}//释放相应对象的内存空间free(slashClassName);ALOGD("Shutting down VM\n");if (mJavaVM->DetachCurrentThread() != JNI_OK)ALOGW("Warning: unable to detach main thread\n");if (mJavaVM->DestroyJavaVM() != 0)ALOGW("Warning: VM did not shut down cleanly\n");
}
start() 函数主要做了三件事情,一调用 startVm 开启虚拟机,二调用 startReg 注册 JNI 方法,三就是使用 JNI 调用 ZygoteInit 从而进入 java 世界。
相关log:
01-10 11:20:31.369 722 722 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
具体虚拟机的创建和 JNI 方法的注册本篇文章不再详细讨论,感兴趣的同学可以查看具体代码自行研究,接下来我们来分析进入 java世界的 ZygoteInit.
3.4 ZygoteInit.main
上节我们通过 JNI 调用 ZygoteInit 的 main 函数后,zygote 进程便进入了 Java 框架层,此前没有任何代码进入过 Java 框架层,换句换说zygote 开创了 Java 框架层。
frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) {// 1.创建ZygoteServerZygoteServer zygoteServer = null; // 调用native函数,确保当前没有其它线程在运行ZygoteHooks.startZygoteNoThreadCreation(); //设置pid为0,Zygote进入自己的进程组Os.setpgid(0, 0);........Runnable caller;try {........//得到systrace的监控TAGString bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);//通过systradce来追踪 函数ZygoteInit, 可以通过systrace工具来进行分析//traceBegin 和 traceEnd 要成对出现,而且需要使用同一个tagbootTimingsTraceLog.traceBegin("ZygoteInit"); //开启DDMS(Dalvik Debug Monitor Service)功能//注册所有已知的Java VM的处理块的监听器。//线程监听、内存监听、native 堆内存监听、debug模式监听等等RuntimeInit.enableDdms(); boolean startSystemServer = false;String zygoteSocketName = "zygote";String abiList = null;boolean enableLazyPreload = false; //2. 解析app_main.cpp - start()传入的参数for (int i = 1; i < argv.length; i++) {if ("start-system-server".equals(argv[i])) {startSystemServer = true;//启动zygote时,才会传入参数:start-system-server} else if ("--enable-lazy-preload".equals(argv[i])) {enableLazyPreload = true;//启动zygote_secondary时,才会传入参数:enable-lazy-preload} else if (argv[i].startsWith(ABI_LIST_ARG)) { //通过属性ro.product.cpu.abilist64\ro.product.cpu.abilist32 从C空间传来的值abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());//会有两种值:zygote和zygote_secondary} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}} // 根据传入socket name来决定是创建socket还是zygote_secondaryfinal boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); // 在第一次zygote启动时,enableLazyPreload为false,执行preloadif (!enableLazyPreload) {//systrace 追踪 ZygotePreloadbootTimingsTraceLog.traceBegin("ZygotePreload");// 3.加载进程的资源和类,参考[4.2.2]preload(bootTimingsTraceLog);//systrae结束 ZygotePreload的追踪bootTimingsTraceLog.traceEnd(); // ZygotePreload} else {// 延迟预加载, 变更Zygote进程优先级为NORMAL级别,第一次fork时才会preloadZygote.resetNicePriority();} //结束ZygoteInit的systrace追踪bootTimingsTraceLog.traceEnd(); // ZygoteInit//禁用systrace追踪,以便fork的进程不会从zygote继承过时的跟踪标记Trace.setTracingEnabled(false, 0); // 4.调用ZygoteServer 构造函数,创建socket,会根据传入的参数,// 创建两个socket:/dev/socket/zygote 和 /dev/socket/zygote_secondaryzygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) {//5.fork出system serverRunnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 启动SystemServerif (r != null) {r.run();return;}} // 6.zygote进程进入无限循环,处理请求caller = zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, "System zygote died with exception", ex);throw ex;} finally {if (zygoteServer != null) {zygoteServer.closeServerSocket();}} // 7.在子进程中退出了选择循环。继续执行命令if (caller != null) {caller.run();}}
ZygoteInit 的 main 函数主要完成了以下工作:
- 调用 preload() 来预加载类和资源
- 调用 ZygoteServer() 创建了两个 Server 端的 Socket 分别为 /dev/socket/zygote 和 /dev/socket/zygote_secondary,Socket 用来等待 AMS 发送过来的请求,请求 zygote 进程创建新的应用程序进程。
- 调用 forkSystemServer 来启动 SystemServer 进程,这样系统的关键服务也会通过 SystemServer 进程启动起来。
- 最后调用 runSelectLoop 函数来等待客户端请求
下面我们来详细来分析这四件事情。
3.5 ZygoteInit.preload
static void preload(TimingsTraceLog bootTimingsTraceLog) {Log.d(TAG, "begin preload"); beginPreload(); // Pin ICU Data, 获取字符集转换资源等 //预加载类的列表---/system/etc/preloaded-classes//在版本:/frameworks/base/config/preloaded-classes 中,Android10.0中预计有7603左右个类preloadClasses(); preloadResources(); //加载图片、颜色等资源文件//部分定义在 /frameworks/base/core/res/res/values/arrays.xml中......preloadSharedLibraries();// 加载 android、compiler_rt、jnigraphics等librarypreloadTextResources();//用于初始化文字资源 WebViewFactory.prepareWebViewInZygote();//用于初始化webview;endPreload();//预加载完成,可以查看下面的logwarmUpJcaProviders();Log.d(TAG, "end preload"); sPreloadComplete = true;}
什么是预加载?
预加载是指在 zygote 进程启动的时候就加载,这样系统只在 zygote 执行一次加载操作,所有 app 用到该资源不需要再重新加载,减少资源加载时间,加快了应用启动速度,一般情况下,系统中 app 共享的资源会被列为预加载资源。
zygote fork 子进程时,根据 fork 的 copy-on-write 机制可知,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。
预加载的原理
zygote 进程启动后将资源读取出来,保存到 Resources 一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找。
frameworks/base/config/preloaded-classes:
3.6 ZygoteServer
frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
class ZygoteServer {private LocalServerSocket mZygoteSocket;private LocalServerSocket mUsapPoolSocket; private FileDescriptor mUsapPoolEventFD;//创建zygote的socketZygoteServer(boolean isPrimaryZygote) {mUsapPoolEventFD = Zygote.getUsapPoolEventFD(); if (isPrimaryZygote) {//创建socket,并获取socket对象,socketname: zygotemZygoteSocket =Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);//创建socket,并获取socket对象,socketname:usap_pool_primarymUsapPoolSocket =Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);} else {//创建socket,并获取socket对象,socketname: zygote_secondarymZygoteSocket =Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);//创建socket,并获取socket对象,socketname: usap_pool_secondarymUsapPoolSocket =Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);}fetchUsapPoolPolicyProps();mUsapPoolSupported = true;}
frameworks/base/core/java/com/android/internal/os/Zygote.java
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {int fileDesc;// ANDROID_SOCKET_PREFIX为"ANDROID_SOCKET_" //加入传入参数为zygote,则fullSocketName:ANDROID_SOCKET_zygotefinal String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try {//init.zygote64_32.rc启动时,指定了4个socket://分别是zygote、usap_pool_primary、zygote_secondary、usap_pool_secondary// 在进程被创建时,就会创建对应的文件描述符,并加入到环境变量中// 这里取出对应的环境变量String env = System.getenv(fullSocketName);fileDesc = Integer.parseInt(env);} catch (RuntimeException ex) {throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);} try {FileDescriptor fd = new FileDescriptor();fd.setInt$(fileDesc); // 获取zygote socket的文件描述符return new LocalServerSocket(fd); // 创建Socket的本地服务端} catch (IOException ex) {throw new RuntimeException("Error building socket from file descriptor: " + fileDesc, ex);}}
frameworks\base\core\java\android\net\LocalServerSocket.java
public LocalServerSocket(FileDescriptor fd) throws IOException{impl = new LocalSocketImpl(fd);impl.listen(LISTEN_BACKLOG);localAddress = impl.getSockAddress();}
ZygoteServer 构造函数初始化时,根据传入的参数,利用 LocalServerSocket 创建了4个本地服务端的 socket,用来建立连接。分别是:zygote、usap_pool_primary、zygote_secondary、usap_pool_secondary.
3.7 ZygoteInit.forkSystemServer
private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) { long capabilities = posixCapabilitiesAsBits(OsConstants.CAP_IPC_LOCK,OsConstants.CAP_KILL,OsConstants.CAP_NET_ADMIN,OsConstants.CAP_NET_BIND_SERVICE,OsConstants.CAP_NET_BROADCAST,OsConstants.CAP_NET_RAW,OsConstants.CAP_SYS_MODULE,OsConstants.CAP_SYS_NICE,OsConstants.CAP_SYS_PTRACE,OsConstants.CAP_SYS_TIME,OsConstants.CAP_SYS_TTY_CONFIG,OsConstants.CAP_WAKE_ALARM,OsConstants.CAP_BLOCK_SUSPEND);........//参数准备/* Hardcoded command line to start the 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,3006,3007,3009,3010","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","--target-sdk-version=" + VMRuntime.
SDK_VERSION_CUR_DEVELOPMENT,"com.android.server.SystemServer",};ZygoteArguments parsedArgs = null; int pid; try {//将上面准备的参数,按照ZygoteArguments的风格进行封装parsedArgs = new ZygoteArguments(args);Zygote.applyDebuggerSystemProperty(parsedArgs);Zygote.applyInvokeWithSystemProperty(parsedArgs); boolean profileSystemServer = SystemProperties.getBoolean("dalvik.vm.profilesystemserver", false);if (profileSystemServer) {parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;} //通过fork"分裂"出子进程system_server/* Request to fork the system server process */pid = Zygote.forkSystemServer(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids,parsedArgs.mRuntimeFlags,null,parsedArgs.mPermittedCapabilities,parsedArgs.mEffectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);} //进入子进程system_server/* For child process */if (pid == 0) {// 处理32_64和64_32的情况if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);} // fork时会copy socket,system server需要主动关闭zygoteServer.closeServerSocket();// system server进程处理自己的工作return handleSystemServerProcess(parsedArgs);} return null;}
forkSystemServer() 会在新 fork 出的子进程中调用 handleSystemServerProcess(),主要是返回 Runtime.java 中的 MethodAndArgsCaller 方法,然后通过 r.run() 启动 com.android.server.SystemServer 的 main 函数,这个我们会在后面的分析 SystemServer 的章节中进行详细介绍,我们先看下基本调用流程
handleSystemServerProcess代码流程:
handleSystemServerProcess()|[ZygoteInit.java]zygoteInit()|[RuntimeInit.java]applicationInit()|findStaticMain()|MethodAndArgsCaller()
3.8 ZygoteServer.runSelectLoop
frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
Runnable runSelectLoop(String abiList) {ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); // 首先将server socket加入到fdssocketFDs.add(mZygoteSocket.getFileDescriptor());peers.add(null); //无限循环用来等待AMS请求zygote创建新的应用进程while (true) {fetchUsapPoolPolicyPropsWithMinInterval(); int[] usapPipeFDs = null;StructPollfd[] pollFDs = null; // 每次循环,都重新创建需要监听的pollFdsif (mUsapPoolEnabled) {usapPipeFDs = Zygote.getUsapPipeFDs();pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];} else {pollFDs = new StructPollfd[socketFDs.size()];}int pollIndex = 0;for (FileDescriptor socketFD : socketFDs) {// 关注事件到来pollFDs[pollIndex] = new StructPollfd();pollFDs[pollIndex].fd = socketFD;pollFDs[pollIndex].events = (short) POLLIN;++pollIndex;} final int usapPoolEventFDIndex = pollIndex; if (mUsapPoolEnabled) {pollFDs[pollIndex] = new StructPollfd();pollFDs[pollIndex].fd = mUsapPoolEventFD;pollFDs[pollIndex].events = (short) POLLIN;++pollIndex; for (int usapPipeFD : usapPipeFDs) {FileDescriptor managedFd = new FileDescriptor();managedFd.setInt$(usapPipeFD); pollFDs[pollIndex] = new StructPollfd();pollFDs[pollIndex].fd = managedFd;pollFDs[pollIndex].events = (short) POLLIN;++pollIndex;}}try {//查询轮训状态,当pollFdd有事件到来则往下执行,否则阻塞在这里Os.poll(pollFDs, -1);} catch (ErrnoException ex) {throw new RuntimeException("poll failed", ex);} boolean usapPoolFDRead = false; //倒序处理,即优先处理已建立链接的信息,后处理新建链接的请求while (--pollIndex >= 0) {if ((pollFDs[pollIndex].revents & POLLIN) == 0) {continue; } // server socket最先加入fds, 因此这里是server socket收到数据if (pollIndex == 0) {// 收到新的建立通信的请求,调用server socket端的accpet函数建立通信连接// zygote进程与system server进程建立了连接ZygoteConnection newPeer = acceptCommandPeer(abiList);// 加入到peers和fds, 即下一次也开始监听peers.add(newPeer);socketFDs.add(newPeer.getFileDescriptor()); } else if (pollIndex < usapPoolEventFDIndex) {//说明接收到AMS发送过来创建应用程序的请求,调用//processOneCommand来创建新的应用程序进程try {//有socket连接,创建ZygoteConnection对象,并添加到fds。ZygoteConnection connection = peers.get(pollIndex);//处理连接(用于fork新的进程)final Runnable command = connection.processOneCommand(this); // TODO (chriswailes): Is this extra check necessary?if (mIsForkChild) {if (command == null) {throw new IllegalStateException("command == null");} return command;} else {// We're in the server - we should never have any //commands to run.if (command != null) {throw new IllegalStateException("command != null");} if (connection.isClosedByPeer()) {connection.closeSocket();peers.remove(pollIndex);socketFDs.remove(pollIndex);//处理完则从fds中移除该文件描述符}}} catch (Exception e) {......} finally {mIsForkChild = false;}} else {//处理USAP pool的事件 long messagePayload = -1; try {byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {DataInputStream inputStream =new DataInputStream(new ByteArrayInputStream(buffer)); messagePayload = inputStream.readLong();} else {continue;}} catch (Exception ex) {if (pollIndex == usapPoolEventFDIndex) {} else {} continue;} if (pollIndex > usapPoolEventFDIndex) {Zygote.removeUsapTableEntry((int) messagePayload);} usapPoolFDRead = true;}} // Check to see if the USAP pool needs to be refilled.if (usapPoolFDRead) {int[] sessionSocketRawFDs =socketFDs.subList(1, socketFDs.size()).stream().mapToInt(fd -> fd.getInt$()).toArray(); final Runnable command = fillUsapPool(sessionSocketRawFDs);if (command != null) {return command;}}}
}
执行 zygote 进程的循环。当来一个新的连接请求时,则建立连接,并在连接中读取请求的命令,runSelectLoop 主要分为三个部分:
- 监听 socket 事件
在 runSelectLoop 里面利用 while (true) 的死循环, Os.poll(pollFds, -1) 来轮询状态,如果有 pollFdd 事件来,则往下执行,否则便会阻塞在这里 - 接受连接请求
当 pollIndex 的值为 0 时,说明请求连接的事件来了,这时候调用 acceptCommandPeer() 来和客户端建立一个 socket 连接,然后把这个 socket 加入监听的数组中。等待这个 socket 上的命令的到来 - 处理连接请求
如果 pollIndex 小于 usapPoolEventFDIndex,说明是已经连接的 socket 上的命令来了。一旦接收到已和客户端连接的 socket 上传过来的命令,runSelectLoop() 方法会调用 ZygoteConnection 类 processOneCommand() 方法去处理命令。处理完后,就会断开与客户端的连接,并把用于连接的 socket 从监听表中移除。
小结:zygote 采用高效的 I/O 多路复用 epoll 机制,保证没有客户端连接请求或数据处理时休眠,否则响应客户端的请求。总体来说 runSelectLoop 方法的内部还是比较简单的,就是处理客户端的连接和请求,其中客户端在 zygote 进程中使用 ZygoteConnection 对象表示。客户端的请求由 ZygoteConnection 的 processOneCommand 来处理。
3.9 ZygoteConnection.processOneCommand
Runnable processOneCommand(ZygoteServer zygoteServer) {...//fork子进程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.mTargetSdkVersion);if (pid == 0) {//子进程执行zygoteServer.setForkChild();//进入子进程流程return handleChildProc(parsedArgs, descriptors, childPipeFd,parsedArgs.mStartChildZygote);} else {//父进程执行// In the parent. A pid < 0 indicates a failure and will be handled in //handleParentProc.handleParentProc(pid, descriptors, serverPipeFd);return null;}...
}
可以看到在 processOneCommand 中调用了 fork 用来创建一个新的进程,然后进入子进程调用 handleChildProc 函数.
3.10 ZygoteConnection.handleChildProc
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, boolean isZygote) {........if (parsedArgs.mInvokeWith != null) {........throw new IllegalStateException("WrapperInit.execApplication
unexpectedly returned");} else {if (!isZygote) {// App进程将会调用到这里,执行目标类的main()方法return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, null /* classLoader */);} else {return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, null /* classLoader */);}}}
3.11 ZygoteInit.zygoteInit
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {if (RuntimeInit.DEBUG) {Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");RuntimeInit.redirectLogStreams();//日志重定向RuntimeInit.commonInit();//通用的初始化工作ZygoteInit.nativeZygoteInit();//zygote初始化return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);//应用的初始化}
需要重点介绍下 zygoteInit 这个函数,这个函数是在 fork 后的子进程中执行的,我们知道在 fork system server 进程后,会在子进程 system server 中执行 handleSystemServerProcess 这个方法,需要注意的是在这个方法中也会调用 zygoteInit 这个函数,接下来我们来看这个函数中主要做了那些工作,以致于如此重要.其中 redirectLogStreams 是日志的重定向,而 commonInit 是通用的初始化工作,在此不做详细介绍,重点介绍 ZygoteInit.nativeZygoteInit 和 RuntimeInit.applicationInit
3.11.1 ZygoteInit.nativeZygoteInit
private static final native void nativeZygoteInit();
它是一个 native 方法,对应的是 AndroidRuntime.cpp 的 com_android_internal_os_ZygoteInit_nativeZygoteInit,最终调用到 app_main.cpp 的 onZygoteInit 代码如下:
virtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();//创建ProcessStateALOGV("App process: starting thread pool.\n");proc->startThreadPool();//开启线程池}
从第一行代码中可以看到创建了 ProcessState 对象,我们之前分析 Binder 的过程中已经知道,在创建 ProcessState 的过程中会打开 Binder 设备并建立内存映射,第二行代码中调用了 ProcessState 的 startThreadPool 方法创建一个新的 Binder 线程,不断进行 talkWithDriver().这样我们在新的子进程中就建立了 Binder 通信机制了.这一点需要明白.
3.11.2 RuntimeInit.applicationInit
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {//true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用nativeSetExitWithoutCleanup(true);//设置虚拟机的内存利用率参数值为0.75VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);final Arguments args = new Arguments(argv);// The end of of the RuntimeInit event (see #zygoteInit).Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);//调用startClass的static方法 main()return findStaticMain(args.startClass, args.startArgs, classLoader);}
此处 findStaticMain 的参数 args.startClass 为 android.app.ActivityThread"
3.11.3 findStaticMain
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);}return new MethodAndArgsCaller(m, argv);}
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,这是一个 Runnable,在这个 Runnable 中会通过反射调用 ActivityThread 的 main() 方法.这个 Runnable 会一路返回到 ZygoteInit 类的 main() 方法中,代码如下:
public static void main(String argv[]) {........Runnable caller;try {........if (startSystemServer) {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;}}........caller = zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, "System zygote died with 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();//最终执行这个Runnable}}
最终会在子进程中通过 caller.run 来执行这个 Runnable,从而完成 ActivityThread main方法的执行.
四 总结
- 解析 init.zygote64_32.rc,创建 AppRuntime 对象,并且调用其 start 函数.zygote 的核心初始化都在 AppRuntime 中。
- 在 AndroidRuntime 的 start 方法中调用 startVm 创建 Java 虚拟机,然后调用 startReg 来注册 JNI 函数
- 通过 JNI 调用 com.android.internal.os.ZygoteInit 的 main 函数,从此进入了 Java 世界
- 通过 ZygoteServer 创建服务端 Socket,预加载常用的类、资源等
- 调用 forkSystemServer 函数 fork 一个 system_server 进程来为 Java 框架服务
- 调用 runSelectLoop 来让自己无限循环等待,等待 AMS 的进程创建请求
这篇关于Android系统启动系列3 zygote进程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!