在Android系统中,DVM、ART、应用程序进程和SystemServer进程都是由Zygote进程创建的,因此Zygote又称为“孵化器”。它是通过fork的形式来创建应用程序进程和SystemServer进程,由于Zygote进程在启动时会创建一个DVM或者ART,因此通过fork而创建的应用程序进程和SystemServer进程可以在内部获取一个DVM或ART的实例副本。

备注:本文将结合Android8.0的源码看Zygote进程的启动过程以及Zygote进程做了哪些重要工作。

1. Zygote进程启动脚本

在init.rc中采用的是import类型语句来引入Zygote启动脚本,这些启动脚本都是由Android初始化语言来写的:

import /init.${ro.zygote}.rc

可以看出:init.rc中不会直接引入一个固定的文件,而是根据属性ro.zygote的内容来引入不同的文件。

从Android5.0开始,Android开始支持64位程序,Zygote就有了32位和64位的区别。所以这里就用ro.zygote属性来控制使用不同的Zygote启动脚本,从而就启动不同版本的Zygote进程。

ro.zygote属性的值有如下四种:

  • init.zygote32.rc

  • init.zygote32_64.rc

  • init.zygote64.rc

  • init.zygote64_32.rc

这些Zygote启动脚本都是放在system/core/rootdir/目录下。

1.1 init.zygote32.rc

表示支持纯32位程序,内容如下所示:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-serverclass 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/tasks

根据Service类型语句的格式可知:

  • Zygote进程名称为zygote

  • 执行程序是app_process

  • classname为main

  • 如果audioserver、cameraserver、media、netd、wificond等进程终止时,Zygote进程会重启。

1.2 init.zygote32_64.rc

表示既支持32位程序也支持64位程序,内容如下所示:

service zygote /system/bin/app_process32 -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_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondaryclass mainpriority -20user rootgroup root readprocsocket zygote_secondary stream 660 root systemonrestart restart zygotewritepid /dev/cpuset/foreground/tasks

可以发现,脚本中有两个Service类型语句,说明会启动两个Zygote进程:

  • 一个进程名为:zygote;执行程序为:app_process32,作为主模式

  • 另一个进程名为:zygote_secondary;执行程序为:app_process64,作为辅模式

2. Zygote进程启动过程

在《从源码角度看Android系统init进程启动过程》一文中可知:init启动Zygote调用的是app_main.cpp的main函数中AppRuntime的start方法来启动Zygote进程。

代码路径:frameworks/base/cmds/app_process/app_main.cpp

main函数如下:

int main(int argc, char* const argv[])
{...省略...//传到的参数argv是“-Xzygote /system/bin --zygote --start-system-server”AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//忽略第一个参数 argc--;argv++;...省略...// 参数解析bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;++i;while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) { //注释1zygote = true;niceName = ZYGOTE_NICE_NAME;} else if (strcmp(arg, "--start-system-server") == 0) { //注释2startSystemServer = true;} else if (strcmp(arg, "--application") == 0) {application = true;} else if (strncmp(arg, "--nice-name=", 12) == 0) {niceName.setTo(arg + 12);} else if (strncmp(arg, "--", 2) != 0) {className.setTo(arg);break;} else {--i;break;}}Vector<String8> args;if (!className.isEmpty()) {// 运行application或tool程序args.add(application ? String8("application") : String8("tool"));runtime.setClassNameAndArgs(className, argc - i, argv + i);...省略...} else {//进入zygote模式,创建 /data/dalvik-cache路径maybeCreateDalvikCache();if (startSystemServer) {args.add(String8("start-system-server"));}char prop[PROP_VALUE_MAX];if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",ABI_LIST_PROPERTY);return 11;}String8 abiFlag("--abi-list=");abiFlag.append(prop);args.add(abiFlag);for (; i < argc; ++i) {args.add(String8(argv[i]));}}//设置进程名if (!niceName.isEmpty()) {runtime.setArgv0(niceName.string(), true /* setProcName */);}if (zygote) { //注释3runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} 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.");}
}

注释解析:

  • 注释1处判断参数arg中是否包含了“–zygote”,如果包含了则说明main函数是运行在Zygote进程中。将参数zygote设置为true;并给niceName赋值,64位系统nice_name为zygote64、32位系统nice_name为zygote

  • 注释2处判断参数arg中是否包含了“–start-system-server”,如果包含了则说明main函数是运行在SystemServer进程中。将参数startSystemServer设置为true。

  • 注释3出判断zygote是否为 true,如果为true,就说明运行在Zygote进程中,然后就调用AppRuntime中的start函数

深入到AppRuntime中的start函数中:

代码路径:frameworks/base/core/jni/AndroidRuntime.cpp

start函数如下:

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{...省略...JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;//启动java虚拟机if (startVm(&mJavaVM, &env, zygote) != 0) {return;}onVmCreated(env);//为java虚拟机注册JNI方法if (startReg(env) < 0) {ALOGE("Unable to register all android natives\n");return;}...省略...//从app_main的main函数中可以传过来的className是com.android.internal.os.ZygoteInitclassNameStr = env->NewStringUTF(className);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);}//将com.android.internal.os.ZygoteInit转换为com/android/internal/os/ZygoteInitchar* slashClassName = toSlashClassName(className);//找到ZygoteInitjclass startClass = env->FindClass(slashClassName);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");if (startMeth == NULL) {ALOGE("JavaVM unable to find main() in '%s'\n", className);/* keep going */} else {//通过JNI调用ZygoteInit的main方法env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0if (env->ExceptionCheck())threadExitUncaughtException(env);
#endif}}free(slashClassName);...省略...
}

从上面的注释可以看出,start函数做了如下工作:

  • 调用startVm函数来创建Java虚拟机

  • 调用startReg函数为Java虚拟机注册JNI方法

  • 将传进来的参数com.android.internal.os.ZygoteInit转换为com/android/internal/os/ZygoteInit,并赋值给slashClassName

  • 通过slashClassName找到ZygoteInit

  • 通过JNI调用ZygoteInit的main方法

在通过JNI调用ZygoteInit的main方法后,Zygote就进入了Java框架层。

深入到ZygoteInit方法中:

代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

main函数如下:

public static void main(String argv[]) {ZygoteServer zygoteServer = new ZygoteServer();...省略...try {...省略...//创建一个Server端的Socket,socketName的值为“zygote”zygoteServer.registerServerSocket(socketName); //注释1// 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); //注释2EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd(); // ZygotePreload} else {Zygote.resetNicePriority();}...省略...//启动SystemServer进程if (startSystemServer) {startSystemServer(abiList, socketName, zygoteServer); //注释3}Log.i(TAG, "Accepting command socket connections");//等待AMS请求zygoteServer.runSelectLoop(abiList); //注释4zygoteServer.closeServerSocket();} catch (Zygote.MethodAndArgsCaller caller) {caller.run();} catch (Throwable ex) {Log.e(TAG, "System zygote died with exception", ex);zygoteServer.closeServerSocket();throw ex;}
}

注释解析:

  • 注释1处通过registerServerSocket方法来创建一个Server端的Socket,这个name为zygote的Socket用于等待ActivityManagerService请求Zygote创建新的应用程序进程

  • 注释2预加载类和资源

  • 注释3启动SystemServer进程

  • 注释4处调用ZygoteServer的runSelectLoop方法来等待AMS请求创建新的应用程序进程

综上所述:ZygoteInit的main方法主要做了4件事:

  1. 创建一个Server端的Socket

  2. 预加载类和资源

  3. 启动SystemServer进程

  4. 等待AMS请求创建新的应用程序进程

下面分别对这四件事跟踪源码分析下。

2.1 registerServerSocket

代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

深入到registerServerSocket函数中:

void registerServerSocket(String socketName) {if (mServerSocket == null) {int fileDesc;//拼接Socket的名称final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; //注释1try {//得到Socket的环境变量的值String env = System.getenv(fullSocketName); //注释2//将Socket环境变量的值转换为文件描述符的参数fileDesc = Integer.parseInt(env); //注释3} catch (RuntimeException ex) {throw new RuntimeException(fullSocketName + " unset or invalid", ex);}try {//创建文件描述符FileDescriptor fd = new FileDescriptor();fd.setInt$(fileDesc);//创建服务器端的SocketmServerSocket = new LocalServerSocket(fd); //注释4} catch (IOException ex) {throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);}}
}

注释解析:

  • 注释1拼接Socket的名称,其中ANDROID_SOCKET_PREFIX的值为“ANDROID_SOCKET_”,socketName的值是传进来的“zygote”,因此fullSocketName的值为“ANDROID_SOCKET_zygote”

  • 注释2处将fullSocketName转换为环境变量的值

  • 注释3将环境变量的值转换为文件描述符参数

  • 注释4创建LocalServerSocket,也就是服务器端的Socket

在Zygote进程将SystemServer进程启动后,就会在这个服务器端的Socket上等待AMS请求Zygote进程来创建新的应用程序进程。

2.2 preload

代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

深入到preload函数中:

static void preload(BootTimingsTraceLog bootTimingsTraceLog) {Log.d(TAG, "begin preload");bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");beginIcuCachePinning();bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinningbootTimingsTraceLog.traceBegin("PreloadClasses");//预加载位于/system/etc/preloaded-classes文件中的类preloadClasses();bootTimingsTraceLog.traceEnd(); // PreloadClassesbootTimingsTraceLog.traceBegin("PreloadResources");预加载资源,包含drawable和color资源preloadResources();bootTimingsTraceLog.traceEnd(); // PreloadResourcesTrace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");//预加载OpenGLpreloadOpenGL();Trace.traceEnd(Trace.TRACE_TAG_DALVIK);//通过System.loadLibrary()方法,//预加载"android","compiler_rt","jnigraphics"这3个共享库preloadSharedLibraries();//预加载 文本连接符资源preloadTextResources();//仅用于zygote进程,用于内存共享的进程WebViewFactory.prepareWebViewInZygote();endIcuCachePinning();warmUpJcaProviders();Log.d(TAG, "end preload");sPreloadComplete = true;
}
  • 类加载,采用的是反射机制Class.forName()方法来加载。

  • 加载的资源主要是com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以com.android.internal.R.xxx开头的资源,就是在此时由Zygote加载到内存中的。

zygote进程内加载了preload()方法中的所有资源,当需要fork新进程时,采用copy on write技术,如下图所示:

从上图可以看出在创建新进程时,会共享父进程Zygote地址空间。

2.3 startSystemServer

代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

深入到startSystemServer函数中:

private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)throws Zygote.MethodAndArgsCaller, RuntimeException {...省略...//参数准备,args数组中保存启动SystemServer的启动参数String args[] = { //注释1"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","com.android.server.SystemServer",};ZygoteConnection.Arguments parsedArgs = null;int pid;try {//用于解析参数,生成目标格式parsedArgs = new ZygoteConnection.Arguments(args); //注释2ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);//fork子进程,也是创建SystemServer进程pid = Zygote.forkSystemServer( //注释3parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,parsedArgs.debugFlags,null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}//运行在子进程中if (pid == 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}//关闭zygote原有的socketzygoteServer.closeServerSocket();//处理SystemServer进程handleSystemServerProcess(parsedArgs); //注释4}return true;
}

注释解析:

  • 注释1创建args数组,主要用来保存启动SystemServer的启动参数。

其中:

可以看出SystemServer进程的的用户id和用户组id都被设置为了1000,并且拥有用户组1001-1010、1018、1021、1032、3001-3010的权限。

进程名为:system_server

启动的类名为:com.android.server.SystemServer

  • 注释2处将args数组封装成Arguments对象,并给注释3出的forkSystemServer函数调用

  • 注释3处调用Zygote的forkSystemServer方法,其内部会调用nativeForkSystemServer这个Native方法,nativeForkSystemServer会通过fork函数在当前进程创建一个子进程,即SystemServer进程。

  • 注释4处理SystemServer进程

2.4 runSelectLoop

在启动SystemServer进程后,会执行ZygoteServer的runSelectLoop方法。

代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

深入到runSelectLoop函数中:

void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();//sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]fds.add(mServerSocket.getFileDescriptor()); //注释1peers.add(null);//无限循环等待AMS的请求while (true) {StructPollfd[] pollFds = new StructPollfd[fds.size()];for (int i = 0; i < pollFds.length; ++i) { //注释2pollFds[i] = new StructPollfd();pollFds[i].fd = fds.get(i);pollFds[i].events = (short) POLLIN;}try {//处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里Os.poll(pollFds, -1);} catch (ErrnoException ex) {throw new RuntimeException("poll failed", ex);}for (int i = pollFds.length - 1; i >= 0; --i) { //注释3//采用I/O多路复用机制,当接收到客户端发出连接请求或者数据处理请求时,则往下执行;//否则进入continue,跳出本次循环if ((pollFds[i].revents & POLLIN) == 0) {continue;}if (i == 0) {//即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;//则创建ZygoteConnection对象,并添加到fdsZygoteConnection newPeer = acceptCommandPeer(abiList); //注释4peers.add(newPeer);fds.add(newPeer.getFileDesciptor());} else {boolean done = peers.get(i).runOnce(this); //注释5if (done) {peers.remove(i);fds.remove(i);}}}}
}

注释解析:

  • 注释1:处的mServerSocket就是在registerZygoteSocket函数中创建的服务端的Socket,调用getFileDescriptor()方法获取该Socket的fd字段的值,并添加到fd列表fds中。

  • 注释2处通过遍历将fds存储的信息转移到pollFds中

  • 注释3处对pollFds进行遍历,如果i==0,说明服务端Socket与客户端连接上了,即:当前Zygote进程与AMS建立了连接

  • 注释4处通过acceptCommandPeer方法得到ZygoteConnection类并添加到Socket连接列表peers中,然后将ZygoteConnection的fd添加到fd列表fds中,以便接收到AMS发送过来的请求

  • 如果i不等于0,则说明AMS向Zygote进程发送了一个创建应用进程的请求,然后调用注释5处ZygoteConnection的runOnce函数来创建一个新的应用程序进程,并在成功创建后,将这个连接从Socket连接列表peers和fds中移除。

3. 总结

3.1 Zygote启动过程调用流程图
3.2 Zygote进程启动总结

Zygote进程启动主要做了如下工作:

  • 解析init.${ro.zygote}.rc中的参数,创建AppRuntime并调用它的start方法

  • 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数

  • 通过JNI调用ZygoteInit的main函数,进入Zygote的Java框架层

  • 通过registerZygoteSocket方法建立Socket通道,zygote作为通信的服务端,用于响应客户端请求

  • preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率

  • 启动SystemServer进程

  • 调用runSelectLoop(),随时待命,当接收到请求创建新进程时,立即唤醒Zygote并执行相应工作

非常感谢您的耐心阅读,希望我的文章对您有帮助。欢迎点评、转发或分享给您的朋友或技术群。

从源码角度看Android系统Zygote进程启动过程相关推荐

  1. 从源码角度看Android系统SystemServer进程启动过程

    SystemServer进程是由Zygote进程fork生成,进程名为system_server,主要用于创建系统服务. 备注:本文将结合Android8.0的源码看SystemServer进程的启动 ...

  2. 从源码角度看Android系统init进程启动过程

    init进程是Linux系统中用户空间的第一个进程,进程号为1.Kernel启动后,在用户空间启动init进程,并调用/system/core/init.cpp中的main方法执行一些重要的工作. 备 ...

  3. 从源码角度看Android系统Launcher在开机时的启动过程

    Launcher是Android所有应用的入口,用来显示系统中已经安装的应用程序图标. Launcher本身也是一个App,一个提供桌面显示的App,但它与普通App有如下不同: Launcher是所 ...

  4. android 多线程创建texture,从源码角度剖析Android系统EGL及GL线程

    本文转载自天天P图攻城狮微信公众号,作者:天天P图Android工程师kenneyqin(覃华峥),原文链接https://mp.weixin.qq.com/s/j_N5_C7iQUPWENdRYfj ...

  5. 【Android源码分析】Android系统关键服务启动简析

    一.关于Android系统重要的进程 (1).init进程:init进程是Linux内核启动完成之后,启动的第一个用户进程,Android系统就是在这个进程的基础上启动起来的,进程pid为1.init ...

  6. 从源码角度分析Android系统的异常捕获机制是如何运行的

    我们在开发的时候经常会遇到各种异常,当程序遇到异常,便会将异常信息抛到LogCat中,那这个过程是怎么实现的呢? 我们以一个例子开始: import android.app.Activity; imp ...

  7. 从源码角度解析Android中APK安装过程

    从源码角度解析Android中APK的安装过程 1. Android中APK简介 Android应用Apk的安装有如下四种方式: 1.1 系统应用安装 没有安装界面,在开机时自动完成 1.2 网络下载 ...

  8. 从源码角度看CPU相关日志

    简介 (本文原地址在我的博客CheapTalks, 欢迎大家来看看~) 安卓系统中,普通开发者常常遇到的是ANR(Application Not Responding)问题,即应用主线程没有相应.根本 ...

  9. 从JDK源码角度看Long

    概况 Java的Long类主要的作用就是对基本类型long进行封装,提供了一些处理long类型的方法,比如long到String类型的转换方法或String类型到long类型的转换方法,当然也包含与其 ...

最新文章

  1. 程序单一实例实现 z
  2. BJUI验证后弹窗不显示
  3. 实战:搭建CA认证中心,使用CA证书搭建HTTPS
  4. sql limit 的用法
  5. DHCP_SNOOPING_ DAI_IPSG实验
  6. 什么原因导致芯片短路_华为为什么突然大量用起了联发科芯片,或是这三个产品策略原因...
  7. bootstrap-按钮的创建
  8. MikroTik RouterOS电子克隆盘原理收集
  9. cmd无法运行python_为什么CMD无法运行python程序
  10. centos7 设备 mariadb-10
  11. arduino 部分有用的函数
  12. 创建Java源代码文件----开始编写代码
  13. python随机抽取样本1500个_python 随机抽取数据
  14. easyar 实现模型的旋转和缩放
  15. PowerDesigner16.5 逆向生成物理模型
  16. unity文字转语音插件(中文版)教程
  17. CFileDialog的使用(MFC-C++)
  18. 如何制定学习计划 - 褪墨
  19. java 日历计算农历和节假日的工具类
  20. 也来分析BloomFilter

热门文章

  1. 推荐系统中多值特征的八大处理技巧
  2. 聊聊前端日志库在 SaaS 产品中的应用与设计
  3. 互联网1分钟 | 0328 阿里巴巴收购企业协作软件Teambition;完美世界:与谷歌达成战略合作,积极探索VR等新游戏类型...
  4. 前海理想金融联手云信,共促互联网金融领域变革
  5. layui 实现图片上传和预览
  6. Swift-Tips之重复字符串
  7. 千万级、百万级数据删除优化
  8. python_目录结构
  9. 【张其中】中本聪,我们究竟需要怎样的加密货币?
  10. String与Date转换