本文转载自Gityuan的博客,原文地址为:http://gityuan.com/2016/02/13/android-zygote/
转载请注明作者及原文链接。

基于Android 6.0的源码剖析, 分析Android启动过程的Zygote进程

/frameworks/base/cmds/app_process/App_main.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp/frameworks/base/core/java/com/android/internal/os/- ZygoteInit.java- Zygote.java- ZygoteConnection.java/frameworks/base/core/java/android/net/LocalServerSocket.java
/system/core/libutils/Threads.cpp

一. 概述

Zygote是由init进程通过解析init.zygote.rc文件而创建的,zygote所对应的可执行程序app_process,所对应的源文件是App_main.cpp,进程名为zygote。

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-serverclass mainsocket zygote stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart mediaonrestart restart netd

Zygote进程能够重启的地方:

  • servicemanager进程被杀; (onresart)
  • surfaceflinger进程被杀; (onresart)
  • Zygote进程自己被杀; (oneshot=false)
  • system_server进程被杀; (waitpid)

从App_main()开始,Zygote启动过程的函数调用类大致流程如下:

二、Zygote启动过程

2.1 App_main.main

[-> App_main.cpp]

int main(int argc, char* const argv[])
{//传到的参数argv为“-Xzygote /system/bin --zygote --start-system-server”AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));argc--; argv++; //忽略第一个参数int i;for (i = 0; i < argc; i++) {if (argv[i][0] != '-') {break;}if (argv[i][1] == '-' && argv[i][2] == 0) {++i;break;}runtime.addOption(strdup(argv[i]));}//参数解析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) {zygote = true;//对于64位系统nice_name为zygote64; 32位系统为zygoteniceName = ZYGOTE_NICE_NAME;} else if (strcmp(arg, "--start-system-server") == 0) {startSystemServer = 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) {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());set_process_name(niceName.string());}if (zygote) {// 启动AppRuntime 【见小节2.2】runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {runtime.start("com.android.internal.os.RuntimeInit", args, zygote);} else {//没有指定类名或zygote,参数错误return 10;}
}

2.2 start

[-> AndroidRuntime.cpp]

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{static const String8 startSystemServer("start-system-server");for (size_t i = 0; i < options.size(); ++i) {if (options[i] == startSystemServer) {const int LOG_BOOT_PROGRESS_START = 3000;}}const char* rootDir = getenv("ANDROID_ROOT");if (rootDir == NULL) {rootDir = "/system";if (!hasDir("/system")) {return;}setenv("ANDROID_ROOT", rootDir, 1);}JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;// 虚拟机创建【见小节2.3】if (startVm(&mJavaVM, &env, zygote) != 0) {return;}onVmCreated(env);// JNI方法注册【见小节2.4】if (startReg(env) < 0) {return;}jclass stringClass;jobjectArray strArray;jstring classNameStr;//等价 strArray= new String[options.size() + 1];stringClass = env->FindClass("java/lang/String");strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);//等价 strArray[0] = "com.android.internal.os.ZygoteInit"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());env->SetObjectArrayElement(strArray, i + 1, optionsStr);}//将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"char* slashClassName = toSlashClassName(className);jclass startClass = env->FindClass(slashClassName);if (startClass == NULL) {...} else {jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");// 调用ZygoteInit.main()方法【见小节3.1】env->CallStaticVoidMethod(startClass, startMeth, strArray);}//释放相应对象的内存空间free(slashClassName);mJavaVM->DetachCurrentThread();mJavaVM->DestroyJavaVM();
}

2.3 startVm

[–> AndroidRuntime.cpp]

创建Java虚拟机方法的主要篇幅是关于虚拟机参数的设置,下面只列举部分在调试优化过程中常用参数。

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{// JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。bool checkJni = false;property_get("dalvik.vm.checkjni", propBuf, "");if (strcmp(propBuf, "true") == 0) {checkJni = true;} else if (strcmp(propBuf, "false") != 0) {property_get("ro.kernel.android.checkjni", propBuf, "");if (propBuf[0] == '1') {checkJni = true;}}if (checkJni) {addOption("-Xcheck:jni");}//虚拟机产生的trace文件,主要用于分析系统问题,路径默认为/data/anr/traces.txtparseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");//对于不同的软硬件环境,这些参数往往需要调整、优化,从而使系统达到最佳性能parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");parseRuntimeOption("dalvik.vm.heaptargetutilization",heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");...//preloaded-classes文件内容是由WritePreloadedClassFile.java生成的,//在ZygoteInit类中会预加载工作将其中的classes提前加载到内存,以提高系统性能if (!hasFile("/system/etc/preloaded-classes")) {return -1;}//初始化虚拟机if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {ALOGE("JNI_CreateJavaVM failedn");return -1;}
}

2.4 startReg

[–> AndroidRuntime.cpp]

int AndroidRuntime::startReg(JNIEnv* env)
{//设置线程创建方法为javaCreateThreadEtc 【见小节2.4.1】androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);env->PushLocalFrame(200);//进程NI方法的注册【见小节2.4.2】if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {env->PopLocalFrame(NULL);return -1;}env->PopLocalFrame(NULL);return 0;
}

2.4.1 androidSetCreateThreadFunc

[-> Threads.cpp]

void androidSetCreateThreadFunc(android_create_thread_fn func) {gCreateThreadFn = func;
}

虚拟机启动后startReg()过程,会设置线程创建函数指针gCreateThreadFn指向javaCreateThreadEtc.

2.4.2 register_jni_procs

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env) {for (size_t i = 0; i < count; i++) {//【见小节2.4.3】if (array[i].mProc(env) < 0) {return -1;}}return 0;
}

2.4.3 gRegJNI.mProc

static const RegJNIRec gRegJNI[] = {REG_JNI(register_com_android_internal_os_RuntimeInit),REG_JNI(register_android_os_Binder),...
};

array[i]是指gRegJNI数组, 该数组有100多个成员。其中每一项成员都是通过REG_JNI宏定义的:

#define REG_JNI(name) { name }
struct RegJNIRec {int (*mProc)(JNIEnv*);
};

可见,调用mProc,就等价于调用其参数名所指向的函数。 例如REG_JNI(register_com_android_internal_os_RuntimeInit).mProc也就是指进入register_com_android_internal_os_RuntimeInit方法,接下来就继续以此为例来说明:

int register_com_android_internal_os_RuntimeInit(JNIEnv* env) {return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",gMethods, NELEM(gMethods));
}//gMethods:java层方法名与jni层的方法的一一映射关系
static JNINativeMethod gMethods[] = {{ "nativeFinishInit", "()V",(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },{ "nativeZygoteInit", "()V",(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },{ "nativeSetExitWithoutCleanup", "(Z)V",(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};

三. 进入Java层

前面[小节2.2]AndroidRuntime.start()执行到最后通过反射调用到ZygoteInit.main(),见下文:

3.1 ZygoteInit.main

[–>ZygoteInit.java]

public static void main(String argv[]) {try {RuntimeInit.enableDdms(); //开启DDMS功能SamplingProfilerIntegration.start();boolean startSystemServer = false;String socketName = "zygote";String abiList = null;for (int i = 1; i < argv.length; i++) {if ("start-system-server".equals(argv[i])) {startSystemServer = true;} else if (argv[i].startsWith(ABI_LIST_ARG)) {abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {socketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}...registerZygoteSocket(socketName); //为Zygote注册socket【见小节3.2】preload(); // 预加载类和资源【见小节3.3】SamplingProfilerIntegration.writeZygoteSnapshot();gcAndFinalize(); //GC操作if (startSystemServer) {startSystemServer(abiList, socketName);//启动system_server【见小节3.4】}runSelectLoop(abiList); //进入循环模式【见小节3.5】closeServerSocket();} catch (MethodAndArgsCaller caller) {caller.run(); //启动system_server中会讲到。} catch (RuntimeException ex) {closeServerSocket();throw ex;}
}

在异常捕获后调用的方法caller.run(),会在后续的system_server文章会讲到。

3.2 registerZygoteSocket

[–>ZygoteInit.java]

private static void registerZygoteSocket(String socketName) {if (sServerSocket == null) {int fileDesc;final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;try {String env = System.getenv(fullSocketName);fileDesc = Integer.parseInt(env);} catch (RuntimeException ex) {...}try {FileDescriptor fd = new FileDescriptor();fd.setInt$(fileDesc); //设置文件描述符sServerSocket = new LocalServerSocket(fd); //创建Socket的本地服务端} catch (IOException ex) {...}}
}

3.3 preload

[–>ZygoteInit.java]

static void preload() {//预加载位于/system/etc/preloaded-classes文件中的类preloadClasses();//预加载资源,包含drawable和color资源preloadResources();//预加载OpenGLpreloadOpenGL();//通过System.loadLibrary()方法,//预加载"android","compiler_rt","jnigraphics"这3个共享库preloadSharedLibraries();//预加载 文本连接符资源preloadTextResources();//仅用于zygote进程,用于内存共享的进程WebViewFactory.prepareWebViewInZygote();
}

执行Zygote进程的初始化,对于类加载,采用反射机制Class.forName()方法来加载。对于资源加载,主要是 com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以http://com.android.internal.R.xxx开头的资源,便是此时由Zygote加载到内存的。

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

3.4 startSystemServer

[–>ZygoteInit.java]

private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {long capabilities = posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND,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_RESOURCE,OsConstants.CAP_SYS_TIME,OsConstants.CAP_SYS_TTY_CONFIG);//参数准备String args[] = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007","--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);ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);// fork子进程,用于运行system_serverpid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,parsedArgs.debugFlags,null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}//进入子进程system_serverif (pid == 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}// 完成system_server进程剩余的工作handleSystemServerProcess(parsedArgs);}return true;
}

准备参数并fork新进程,从上面可以看出system server进程参数信息为uid=1000,gid=1000,进程名为sytem_server,从zygote进程fork新进程后,需要关闭zygote原有的socket。另外,对于有两个zygote进程情况,需等待第2个zygote创建完成。更多详情见Android系统启动-systemServer上篇。

3.5 runSelectLoop

[–>ZygoteInit.java]

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();//sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]fds.add(sServerSocket.getFileDescriptor());peers.add(null);while (true) {StructPollfd[] pollFds = new StructPollfd[fds.size()];for (int i = 0; i < pollFds.length; ++i) {pollFds[i] = new StructPollfd();pollFds[i].fd = fds.get(i);pollFds[i].events = (short) POLLIN;}try {//处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里Os.poll(pollFds, -1);} catch (ErrnoException ex) {...}for (int i = pollFds.length - 1; i >= 0; --i) {//采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;// 否则进入continue,跳出本次循环。if ((pollFds[i].revents & POLLIN) == 0) {continue;}if (i == 0) {//即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;// 则创建ZygoteConnection对象,并添加到fds。ZygoteConnection newPeer = acceptCommandPeer(abiList);peers.add(newPeer);fds.add(newPeer.getFileDesciptor()); //添加到fds.} else {//i>0,则代表通过socket接收来自对端的数据,并执行相应操作【见小节3.6】boolean done = peers.get(i).runOnce();if (done) {peers.remove(i);fds.remove(i); //处理完则从fds中移除该文件描述符}}}}
}

Zygote采用高效的I/O多路复用机制,保证在没有客户端连接请求或数据处理时休眠,否则响应客户端的请求。

3.6 runOnce

[-> ZygoteConnection.java]

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {String args[];Arguments parsedArgs = null;FileDescriptor[] descriptors;try {//读取socket客户端发送过来的参数列表args = readArgumentList();descriptors = mSocket.getAncillaryFileDescriptors();} catch (IOException ex) {...return true;}...try {//将binder客户端传递过来的参数,解析成Arguments对象格式parsedArgs = new Arguments(args);...//【见小节7】pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);} catch (Exception e) {...}try {if (pid == 0) {//子进程执行IoUtils.closeQuietly(serverPipeFd);serverPipeFd = null;//进入子进程流程handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);return true;} else {//父进程执行IoUtils.closeQuietly(childPipeFd);childPipeFd = null;return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}
}

更多内容,见理解Android进程创建流程

四、总结

Zygote启动过程的调用流程图:

  1. 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法;
  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(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

最后,介绍给通过cmd命令,来fork新进程来执行类中main方法的方式:(启动后进入RuntimeInit.main)

app_process [可选参数] 命令所在路径 启动的类名 [可选参数]

android 重启app_[Boot]Android系统启动-zygote篇相关推荐

  1. Android系统启动-zygote篇

    基于Android 6.0的源码剖析, 分析Android启动过程的Zygote进程 /frameworks/base/cmds/app_process/App_main.cpp (内含AppRunt ...

  2. qt android 重启,一种Android系统支持QT APP的实现方法专利_专利查询 - 天眼查

    1.一种Android系统支持QT APP的实现方法,其特征在于:所述实现方法首先使 Ministro服务能作为Android系统的系统应用程序运行,其次将QT程序依赖的QT库以及其 他文件部署到An ...

  3. Android 7.1.2(Android N) Android系统启动流程

    Android 7.1.2(Android N) Android系统启动流程 源码: system/core/rootdir/ init.rc init.zygote64.rc system/core ...

  4. Android系统启动-init篇

    基于Android 6.0的源码剖析, 分析Android启动过程进程号为1的init进程的工作内容 /system/core/init/Init.h /system/core/init/Init.c ...

  5. Android 8.1 源码_启动篇(一) -- 深入研究 init(转 Android 9.0 分析)

    前言 init进程,它是一个由内核启动的用户级进程,当Linux内核启动之后,运行的第一个进程是init,这个进程是一个守护进程,确切的说,它是Linux系统中用户控件的第一个进程,所以它的进程号是1 ...

  6. 【Android 系统开发】 Android 系统启动流程简介

    作者 : 万境绝尘 (octopus_truth@163.com) 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/3889548 ...

  7. Android 系统(74)--Android重启原因分析

    Android重启原因分析 重启原因分类 1.上层造成重启 system_server被杀 watchdog重启 重要线程阻塞 2.kernel造成重启 空指针 非法地址 3.kernel watch ...

  8. imx6q android nfs normal boot log

    ---------------------------------------- imx6q android nfs  normal boot log 用nfs 启动, --------------- ...

  9. Android重启原因分析

    重启原因分类 1.上层造成重启 system_server被杀 watchdog重启 重要线程阻塞 2.kernel造成重启 空指针 非法地址 3.kernel watchdog造成重启,原因不确定 ...

最新文章

  1. 李飞飞对话顶级神经科学家纽瑟姆:大脑也做「微积分」,最高效GPU依然很浪费...
  2. 完美解决opencv-python中文路径解析问题
  3. QQ会员亿级Web系统的容错性建设实践--转
  4. .Net开源工作流Roadflow的使用与集成
  5. [转]阿里开源低代码引擎LowCodeEngine
  6. 数据库设计规范 zhuan
  7. Linux 命令(84)—— id 命令
  8. Pytorch的可视化工具tensorboardX
  9. redis安装部署(1)
  10. windows 控制台cmd乱码(及永久修改编码)的解决办法
  11. 论坛E-R图的思路及绘图,软件程序开发流程
  12. 《观音心经》领悟后的空寂感,如何与现实世界有机结合
  13. python requests ssl 证书问题
  14. u盘数据恢复的原理_U盘格式化了怎么恢复数据?恢复原理和方法你了解吗
  15. 二手书籍交易管理系统,二手书交易系统,二手书交易网站毕业设计
  16. centos7 nuxeo platform 集成 onlyoffice,搭建企业级内容管理系统
  17. 读书笔记:《SEO教程:搜索引擎优化入门与进阶》(4)——代码优化
  18. ipv6服务器搭建网站,IPV6地址访问web项目网站配置
  19. matlab amd负优化,AMD 篇三:AMD真的翻身了?—— AMDINTEL CPU 计算性能测试
  20. Wise Owl Says… by Brian O'Kane

热门文章

  1. phpquery类php,一个基于phpQuery的php通用采集类分享
  2. C语言学习之输入一个大于三的值判断是否为素数
  3. EditText: 自定义EditText 触摸时无法获取焦点
  4. 让你觉得破坏了封装性的扩展方法
  5. Silverlight, B/S or C/S?
  6. [Python人工智能] 十五.无监督学习Autoencoder原理及聚类可视化案例详解
  7. 【数据结构与算法】之深入解析“路径总和II”的求解思路与算法示例
  8. iOS之深入解析如何构建静态库
  9. Python执行脚本文件将输出既能显示控制台又能重定向到日志
  10. 2014\Province_C_C++_A\2 切面条