Android系统启动系列3 zygote进程
发布日期:2021-05-06 20:19:10 浏览次数:30 分类:原创文章

本文共 34789 字,大约阅读时间需要 115 分钟。

一 概述

上一篇文章分析了 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=zygote    class main    priority -20    user root    group root readproc    socket zygote stream 660 root system    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart audioserver    onrestart restart cameraserver    onrestart restart media    onrestart restart netd    onrestart restart wificond    writepid /dev/cpuset/foreground/tasksservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload    class main    priority -20    user root    group root readproc    socket zygote_secondary stream 660 root system    onrestart restart zygote    writepid /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启动时序图

在这里插入图片描述

  1. init 进程通过解析 init.zygote64_32.rc 来启动位于 /system/bin/app_process64 的 zygote 进程,入口为 app_main.cpp
  2. 调用 AndroidRuntime 的 startVM() 方法创建虚拟机,再调用 startReg() 注册 JNI 函数
  3. 通过 JNI 方式调用 ZygoteInit.main(),第一次进入 Java 世界
  4. registerZygoteSocket() 建立 socket 通道,zygote 作为通信的服务端,用于响应客户端请求
  5. preload() 预加载通用类、drawable 和 color 资源、openGL 以及共享库以及 WebView,用于提高 app 启动效率
  6. zygote 完成大部分工作,接下来再通过 startSystemServer(),fork system_server 进程,它同时也是上层 framework 框架的运行载体
  7. 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位系统为zygote            niceName = ZYGOTE_NICE_NAME;        } else if (strcmp(arg, "--start-system-server") == 0) {   			 //是否需要启动system server            startSystemServer = 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-cache        maybeCreateDalvikCache();		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) {   	//将剩下的参数加入args			args.add(String8(argv[i]));		}	}	........    if (!niceName.isEmpty()) {           //设置一个“好听的昵称” zygote\zygote64,之前的名称是app_process        runtime.setArgv0(niceName.string(), true /* setProcName */);    }    if (zygote) {   //如果是zygote启动模式,则加载ZygoteInit        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);    } else if (className) {   //如果是application启动模式,则加载RuntimeInit        runtime.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 ID        jmethodID 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.创建ZygoteServer        ZygoteServer zygoteServer = null;         // 调用native函数,确保当前没有其它线程在运行        ZygoteHooks.startZygoteNoThreadCreation();                //设置pid为0,Zygote进入自己的进程组        Os.setpgid(0, 0);        ........        Runnable caller;        try {               ........            //得到systrace的监控TAG            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,                    Trace.TRACE_TAG_DALVIK);            //通过systradce来追踪 函数ZygoteInit, 可以通过systrace工具来进行分析            //traceBegin 和 traceEnd 要成对出现,而且需要使用同一个tag            bootTimingsTraceLog.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_secondary  final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);             // 在第一次zygote启动时,enableLazyPreload为false,执行preload            if (!enableLazyPreload) {                   //systrace 追踪 ZygotePreload                bootTimingsTraceLog.traceBegin("ZygotePreload");                // 3.加载进程的资源和类,参考[4.2.2]                preload(bootTimingsTraceLog);                //systrae结束 ZygotePreload的追踪                bootTimingsTraceLog.traceEnd(); // ZygotePreload            } else {                   // 延迟预加载, 变更Zygote进程优先级为NORMAL级别,第一次fork时才会preload                Zygote.resetNicePriority();            }             //结束ZygoteInit的systrace追踪            bootTimingsTraceLog.traceEnd(); // ZygoteInit            //禁用systrace追踪,以便fork的进程不会从zygote继承过时的跟踪标记            Trace.setTracingEnabled(false, 0);                        // 4.调用ZygoteServer 构造函数,创建socket,会根据传入的参数,            // 创建两个socket:/dev/socket/zygote 和 /dev/socket/zygote_secondary            zygoteServer = new ZygoteServer(isPrimaryZygote);             if (startSystemServer) {                   //5.fork出system server                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);                 // 启动SystemServer                if (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等library        preloadTextResources();//用于初始化文字资源         WebViewFactory.prepareWebViewInZygote();//用于初始化webview;        endPreload();//预加载完成,可以查看下面的log        warmUpJcaProviders();        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的socket    ZygoteServer(boolean isPrimaryZygote) {           mUsapPoolEventFD = Zygote.getUsapPoolEventFD();         if (isPrimaryZygote) {               //创建socket,并获取socket对象,socketname: zygote            mZygoteSocket =                    Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);            //创建socket,并获取socket对象,socketname:usap_pool_primary            mUsapPoolSocket =                    Zygote.createManagedSocketFromInitSocket(                            Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);        } else {               //创建socket,并获取socket对象,socketname: zygote_secondary            mZygoteSocket =                    Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);            //创建socket,并获取socket对象,socketname: usap_pool_secondary            mUsapPoolSocket =                    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_zygote        final 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加入到fds        socketFDs.add(mZygoteSocket.getFileDescriptor());        peers.add(null);         //无限循环用来等待AMS请求zygote创建新的应用进程        while (true) {               fetchUsapPoolPolicyPropsWithMinInterval();             int[] usapPipeFDs = null;            StructPollfd[] pollFDs = null;             // 每次循环,都重新创建需要监听的pollFds            if (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();//创建ProcessState        ALOGV("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.75        VMRuntime.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系统启动系列4 SystemServer进程上
下一篇:Android系统启动系列2 init进程

发表评论

最新留言

很好
[***.229.124.182]2025年03月29日 09时29分51秒