非淡泊无以明志,非宁静无以致远。这篇文章主要讲述Android Zygote进程启动分析相关的知识,希望能为你提供帮助。
dvm,app进程,linux进程三者关系DVM指 dalivk 的虚拟机。每一个 android 应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik 虚拟机实例。而每一个 DVM 都是在 Linux 中的一个进程,所以说可以认为是同一个概念
Zygote进程与app进程关系Zygote是java层的进程即它也拥有一个独立的Dalvik 虚拟机实例,它是被linux层的第一个用户空间Init进程所启动的,它的主要作用就是用来孵化app进程和系统进程
fork一个app进程,是通过ActivityManagerService类向Zygote发出fork命令,ActivityManagerService是在系统进程,但是Zygote处于自己的进程中,它们之间的通信没有采用binder机制,而是采用了socket机制,因此我们可以把Zygote称为一个孵化server,ActivityMamagerService称为一个client
下面的图描述了上面的过程
文章图片
涉及到的类我们先来梳理这个过程中使用到的类,并且这些类是做什么的
文章图片
以server和client2个维度来归纳这些类
Zygote进程启动分析大家都知道android系统的Zygote进程是所有的android进程的父进程,包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。Zygote(孵化)进程相当于是android系统的根进程,后面所有的进程都是通过这个进程fork出来的,而Zygote进程则是通过linux系统的init进程启动的,也就是说,android系统中各种进程的启动方式
init进程 –> Zygote进程 –> SystemServer进程 –> 各种应用进程
【Android Zygote进程启动分析】init进程:linux的根进程,android系统是基于linux系统的,因此可以算作是整个android操作系统的第一个进程;
Zygote进程:android系统的根进程,主要作用:可以作用Zygote进程fork出SystemServer进程和各种应用进程;
SystemService进程:主要是在这个进程中启动系统的各项服务,比如ActivityManagerService,PackageManagerService,WindowManagerService服务等等;
各种应用进程:启动自己编写的客户端应用时,一般都是重新启动一个应用进程,有自己的虚拟机与运行环境;
Zygote就是进程init启动起来的。Android中所有应用程序进程,以及运行系统关键服务的System进程都是由Zygote创建的。它通过复制自身的形式创建其它进程。Zygote在启动时会在内部创建一个虚拟机实例,因此,通过复制Zygote得到的其它应用程序进程和System进程都可以快速地在内部获得一个虚拟机地拷贝。Zygote启动完成后就立即将System进程启动,以便各种关键服务被启动运行
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netd
写到zygote是由init进程解析init.rc(以init.zygote32.rc为例)文件启动的,启动的过程传入了四个参数。分别是
-Xzygote
,/system/bin
,--zygote
,--start-system-server
- 虚拟机参数以"-"开头,上边的"-Xzygote"即为虚拟机参数,在启动虚拟机时传递给虚拟机
- 运行目录即app_process可执行程序所在的目录,一般是在/system/bin
- 参数以"--"开头,"--zygote"表示启动zygote进程,"-start-system-server-"表示启动system server"--application"表示以普通进程方式执行java代码。
- java类,将要执行的java类,必须有一个静态方法。但是如果参数中有"--zygote"时将会忽略该参数,固定的执行zygoteInit类。
- servicemanager进程被杀; (onresart)
- surfaceflinger进程被杀; (onresart)
- Zygote进程自己被杀; (oneshot=false)
- system_server进程被杀; (waitpid)
前边分析中可以知道zygote要执行的程序是
system/bin/app_process
,它的源代码位于frameworks/base/cmds/app_process/App_main.cpp
文件中从App_main()开始,Zygote启动过程的函数调用类大致流程如下:
文章图片
App_main.mainhttp://androidxref.com/6.0.1_r10/xref/frameworks/base/cmds/app_process/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位系统为zygote niceName = 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 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; } }
AndroidRuntime.starthttp://androidxref.com/6.0.1_r10/xref/frameworks/base/core/jni/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); //主要是用来完成环境变量ANDROID_ROOT的设置,调用了getenv()方法和setenv()方法。 //通过这段代码,环境变量ANDROID_ROOT的值被设置成了/system } JniInvocation jni_invocation; jni_invocation.Init(NULL); //通过jni_invocation.Init(NULL)完成jni接口的初始化 JNIEnv* env; //调用startVm启动虚拟机,在startVm方法中,定义了虚拟机的一系列参数 //通过property_get()方法来进行参数的设置。 if (startVm(& mJavaVM, & env, zygote) != 0) { return; } onVmCreated(env); // JNI方法注册 if (startReg(env) < 0) { return; } //定义了三个变量,定义参数的目的是将AndroidRuntime::start的两个参数传入到ZygoteInit的main方法 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()方法 env-> CallStaticVoidMethod(startClass, startMeth, strArray); } //释放相应对象的内存空间 free(slashClassName); mJavaVM-> DetachCurrentThread(); mJavaVM-> DestroyJavaVM(); }
start()是通过JNI回调java层的方法,它主要的目的是执行"com/android/internal/os/ZygoteInit"中main()方法,即frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中的main()函数。
创建虚拟机进程内创建一个虚拟机实例,并注册一系列JNI方法。
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/jni/AndroidRuntime.cpp
/* start the virtual machine. */ startVM(& mJavaVM, & env); /* Register android functions. */ startReg(env);
创建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.txt parseRuntimeOption("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 failed\\n"); return -1; } }
在startVm方法中,定义了虚拟机的一系列参数。通过
property_get()
方法来进行参数的设置。startReg
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startReg(JNIEnv* env) { //设置线程创建方法为javaCreateThreadEt androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); env-> PushLocalFrame(200); //进程NI方法的注册 if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env-> PopLocalFrame(NULL); return -1; } env-> PopLocalFrame(NULL); return 0; }
startReg注册JNI的代码
androidSetCreateThreadFunc虚拟机启动后startReg()过程,会设置线程创建函数指针
gCreateThreadFn
指向javaCreateThreadEtc
.ZygoteInit.main
接下来执行“com.android.internal.os.ZygoteInit”Java类的main方法继续执行启动。
Zygote进程启动后,ZygoteInit类的
main
方法会被执行http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) { try { // Start profiling the zygote initialization. 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]); } }if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } /*启动servier socket*/ registerZygoteSocket(socketName); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); //预加载资源,预加载耗时的类 preload(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gc(); // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); if (startSystemServer) { /*启动系统服务*/ startSystemServer(abiList, socketName); }Log.i(TAG, "Accepting command socket connections"); runSelectLoop(abiList); closeServerSocket(); } catch (MethodAndArgsCaller caller) { //这行代码很重要 caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
上面代码主要做了下面的事情:
registerZygoteSocket(socketName)
启动一个ServerSocketpreload()
预加载资源,预加载耗时的类startSystemServer(abiList, socketName)
启动系统服务,并且fork系统进程runSelectLoop(abiList)
监听client socket的连接
registerZygoteSocket(socketName)
方法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) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); }try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc)); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket \'" + fileDesc + "\'", ex); } } }
代码很简单,再来看下
preload()
方法static void preload() { Log.d(TAG, "begin preload"); preloadClasses(); preloadResources(); preloadOpenGL(); preloadSharedLibraries(); // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); Log.d(TAG, "end preload"); }
这其中:
preloadClasses()用于初始化Zygote中需要的class类;
preloadResources()用于初始化系统资源;
preloadOpenGL()用于初始化OpenGL;
preloadSharedLibraries()用于初始化系统libraries;
preloadTextResources()用于初始化文字资源;
prepareWebViewInZygote()用于初始化webview;
我们简单看下
preloadClasses()
和preloadResources()
所做的事情private static void preloadClasses() { //.......省略代码 is = new FileInputStream(PRELOADED_CLASSES); // ......省略代码 BufferedReader br = new BufferedReader(new InputStreamReader(is), 256); int count = 0; String line; while ((line = br.readLine()) != null) { // Skip comments and blank lines. line = line.trim(); if (line.startsWith("#") || line.equals("")) { continue; }try { if (false) { Log.v(TAG, "Preloading " + line + "..."); } Class.forName(line); if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) { if (false) { Log.v(TAG, " GC at " + Debug.getGlobalAllocSize()); } System.gc(); runtime.runFinalizationSync(); Debug.resetGlobalAllocSize(); } count++; //......省略代码}//......省略代码 }private static void preloadResources() { final VMRuntime runtime = VMRuntime.getRuntime(); Debug.startAllocCounting(); try { System.gc(); runtime.runFinalizationSync(); mResources = Resources.getSystem(); mResources.startPreloading(); if (PRELOAD_RESOURCES) { Log.i(TAG, "Preloading resources..."); long startTime = SystemClock.uptimeMillis(); TypedArray ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); int N = preloadDrawables(runtime, ar); ar.recycle(); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); startTime = SystemClock.uptimeMillis(); ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_color_state_lists); N = preloadColorStateLists(runtime, ar); ar.recycle(); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); } mResources.finishPreloading(); } catch (RuntimeException e) { Log.w(TAG, "Failure preloading resources", e); } finally { Debug.stopAllocCounting(); } }
preloadClasses
方法所做的事情是从"/system/etc/preloaded-classes"文件种把预加载的类加载到虚拟机中然后调用startSystemServer(abiList, socket)
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 ); /* 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,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); /* Request to fork the system server process */ pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); }/* For child process */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); }handleSystemServerProcess(parsedArgs); }return true; }
可以看到这段逻辑的执行逻辑就是通过Zygote fork出SystemServer进程。
在来看
runSelectLoop
方法private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList< FileDescriptor> fds = new ArrayList< FileDescriptor> (); ArrayList< ZygoteConnection> peers = new ArrayList< ZygoteConnection> (); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor()); peers.add(null); int loopCount = GC_LOOP_COUNT; while (true) { int index; /* * Call gc() before we block in select(). * It\'s work that has to be done anyway, and it\'s better * to avoid making every child do it.It will also * madvise() any free memory as a side-effect. * * Don\'t call it every time, because walking the entire * heap is a lot of overhead to free a few hundred bytes. */ if (loopCount < = 0) { gc(); loopCount = GC_LOOP_COUNT; } else { loopCount--; }try { fdArray = fds.toArray(fdArray); index = selectReadable(fdArray); } catch (IOException ex) { throw new RuntimeException("Error in select()", ex); }if (index < 0) { throw new RuntimeException("Error in select()"); } else if (index == 0) { ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); fds.add(newPeer.getFileDescriptor()); } else { boolean done; /*开始读取client发出的命令*/ done = peers.get(index).runOnce(); if (done) { peers.remove(index); fds.remove(index); } } } }
它所做的事情是:
- 监听client的socket连接
- 发现有连接则建立一个
ZygoteConnection
对象- client发送命令,则找到相应的
ZygoteConnection
对象,并且调用该对象的runOnce
方法,来处理client发送的命令-
ZygoteConnection
对象处理完毕,则从列表中移除总结:
Zygote进程mian方法主要执行逻辑:
初始化DDMS;
注册Zygote进程的socket通讯;
初始化Zygote中的各种类,资源文件,OpenGL,类库,Text资源等等;
初始化完成之后fork出SystemServer进程;fork出SystemServer进程之后,关闭socket连接;
推荐阅读
- Robolectric结合Android Studio的使用
- android双向数据绑定data-binding使用include时的使用方法
- fiddler抓包1-app应用抓包
- 2019/2/15安卓应用——记账本,开发记录
- Flutter - 本地化启动列表中App名字
- Tensorflow中循环神经网络及其Wrappers
- Android 自定义倾斜字体
- APP前端易用性和UI测试
- Android添加百分比布局库时显示Failed to resolve: com.android.support.percent:问题