从源码角度看Android系统Zygote进程启动过程
在Android系統(tǒng)中,DVM、ART、應用程序進程和SystemServer進程都是由Zygote進程創(chuàng)建的,因此Zygote又稱為“孵化器”。它是通過fork的形式來創(chuàng)建應用程序進程和SystemServer進程,由于Zygote進程在啟動時會創(chuàng)建一個DVM或者ART,因此通過fork而創(chuàng)建的應用程序進程和SystemServer進程可以在內(nèi)部獲取一個DVM或ART的實例副本。
備注:本文將結(jié)合Android8.0的源碼看Zygote進程的啟動過程以及Zygote進程做了哪些重要工作。
1. Zygote進程啟動腳本
在init.rc中采用的是import類型語句來引入Zygote啟動腳本,這些啟動腳本都是由Android初始化語言來寫的:
import /init.${ro.zygote}.rc可以看出:init.rc中不會直接引入一個固定的文件,而是根據(jù)屬性ro.zygote的內(nèi)容來引入不同的文件。
從Android5.0開始,Android開始支持64位程序,Zygote就有了32位和64位的區(qū)別。所以這里就用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位程序,內(nèi)容如下所示:
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根據(jù)Service類型語句的格式可知:
-
Zygote進程名稱為zygote
-
執(zhí)行程序是app_process
-
classname為main
-
如果audioserver、cameraserver、media、netd、wificond等進程終止時,Zygote進程會重啟。
1.2 init.zygote32_64.rc
表示既支持32位程序也支持64位程序,內(nèi)容如下所示:
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可以發(fā)現(xiàn),腳本中有兩個Service類型語句,說明會啟動兩個Zygote進程:
-
一個進程名為:zygote;執(zhí)行程序為:app_process32,作為主模式
-
另一個進程名為:zygote_secondary;執(zhí)行程序為:app_process64,作為輔模式
2. Zygote進程啟動過程
在《從源碼角度看Android系統(tǒng)init進程啟動過程》一文中可知:init啟動Zygote調(diào)用的是app_main.cpp的main函數(shù)中AppRuntime的start方法來啟動Zygote進程。
代碼路徑:frameworks/base/cmds/app_process/app_main.cpp
main函數(shù)如下:
int main(int argc, char* const argv[]) {...省略...//傳到的參數(shù)argv是“-Xzygote /system/bin --zygote --start-system-server”AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//忽略第一個參數(shù) argc--;argv++;...省略...// 參數(shù)解析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模式,創(chuàng)建 /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]));}}//設(shè)置進程名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處判斷參數(shù)arg中是否包含了“–zygote”,如果包含了則說明main函數(shù)是運行在Zygote進程中。將參數(shù)zygote設(shè)置為true;并給niceName賦值,64位系統(tǒng)nice_name為zygote64、32位系統(tǒng)nice_name為zygote
-
注釋2處判斷參數(shù)arg中是否包含了“–start-system-server”,如果包含了則說明main函數(shù)是運行在SystemServer進程中。將參數(shù)startSystemServer設(shè)置為true。
-
注釋3出判斷zygote是否為 true,如果為true,就說明運行在Zygote進程中,然后就調(diào)用AppRuntime中的start函數(shù)
深入到AppRuntime中的start函數(shù)中:
代碼路徑:frameworks/base/core/jni/AndroidRuntime.cpp
start函數(shù)如下:
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函數(shù)中可以傳過來的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轉(zhuǎn)換為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調(diào)用ZygoteInit的main方法env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0if (env->ExceptionCheck())threadExitUncaughtException(env); #endif}}free(slashClassName);...省略... }從上面的注釋可以看出,start函數(shù)做了如下工作:
-
調(diào)用startVm函數(shù)來創(chuàng)建Java虛擬機
-
調(diào)用startReg函數(shù)為Java虛擬機注冊JNI方法
-
將傳進來的參數(shù)com.android.internal.os.ZygoteInit轉(zhuǎn)換為com/android/internal/os/ZygoteInit,并賦值給slashClassName
-
通過slashClassName找到ZygoteInit
-
通過JNI調(diào)用ZygoteInit的main方法
在通過JNI調(diào)用ZygoteInit的main方法后,Zygote就進入了Java框架層。
深入到ZygoteInit方法中:
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
main函數(shù)如下:
public static void main(String argv[]) {ZygoteServer zygoteServer = new ZygoteServer();...省略...try {...省略...//創(chuàng)建一個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方法來創(chuàng)建一個Server端的Socket,這個name為zygote的Socket用于等待ActivityManagerService請求Zygote創(chuàng)建新的應用程序進程
-
注釋2預加載類和資源
-
注釋3啟動SystemServer進程
-
注釋4處調(diào)用ZygoteServer的runSelectLoop方法來等待AMS請求創(chuàng)建新的應用程序進程
綜上所述:ZygoteInit的main方法主要做了4件事:
創(chuàng)建一個Server端的Socket
預加載類和資源
啟動SystemServer進程
等待AMS請求創(chuàng)建新的應用程序進程
下面分別對這四件事跟蹤源碼分析下。
2.1 registerServerSocket
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
深入到registerServerSocket函數(shù)中:
void registerServerSocket(String socketName) {if (mServerSocket == null) {int fileDesc;//拼接Socket的名稱final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; //注釋1try {//得到Socket的環(huán)境變量的值String env = System.getenv(fullSocketName); //注釋2//將Socket環(huán)境變量的值轉(zhuǎn)換為文件描述符的參數(shù)fileDesc = Integer.parseInt(env); //注釋3} catch (RuntimeException ex) {throw new RuntimeException(fullSocketName + " unset or invalid", ex);}try {//創(chuàng)建文件描述符FileDescriptor fd = new FileDescriptor();fd.setInt$(fileDesc);//創(chuàng)建服務器端的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轉(zhuǎn)換為環(huán)境變量的值
-
注釋3將環(huán)境變量的值轉(zhuǎn)換為文件描述符參數(shù)
-
注釋4創(chuàng)建LocalServerSocket,也就是服務器端的Socket
在Zygote進程將SystemServer進程啟動后,就會在這個服務器端的Socket上等待AMS請求Zygote進程來創(chuàng)建新的應用程序進程。
2.2 preload
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
深入到preload函數(shù)中:
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進程,用于內(nèi)存共享的進程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加載到內(nèi)存中的。
zygote進程內(nèi)加載了preload()方法中的所有資源,當需要fork新進程時,采用copy on write技術(shù),如下圖所示:
從上圖可以看出在創(chuàng)建新進程時,會共享父進程Zygote地址空間。
2.3 startSystemServer
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
深入到startSystemServer函數(shù)中:
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)throws Zygote.MethodAndArgsCaller, RuntimeException {...省略...//參數(shù)準備,args數(shù)組中保存啟動SystemServer的啟動參數(shù)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 {//用于解析參數(shù),生成目標格式parsedArgs = new ZygoteConnection.Arguments(args); //注釋2ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);//fork子進程,也是創(chuàng)建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);}//關(guān)閉zygote原有的socketzygoteServer.closeServerSocket();//處理SystemServer進程handleSystemServerProcess(parsedArgs); //注釋4}return true; }注釋解析:
- 注釋1創(chuàng)建args數(shù)組,主要用來保存啟動SystemServer的啟動參數(shù)。
其中:
可以看出SystemServer進程的的用戶id和用戶組id都被設(shè)置為了1000,并且擁有用戶組1001-1010、1018、1021、1032、3001-3010的權(quán)限。
進程名為:system_server
啟動的類名為:com.android.server.SystemServer
-
注釋2處將args數(shù)組封裝成Arguments對象,并給注釋3出的forkSystemServer函數(shù)調(diào)用
-
注釋3處調(diào)用Zygote的forkSystemServer方法,其內(nèi)部會調(diào)用nativeForkSystemServer這個Native方法,nativeForkSystemServer會通過fork函數(shù)在當前進程創(chuàng)建一個子進程,即SystemServer進程。
-
注釋4處理SystemServer進程
2.4 runSelectLoop
在啟動SystemServer進程后,會執(zhí)行ZygoteServer的runSelectLoop方法。
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
深入到runSelectLoop函數(shù)中:
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);//無限循環(huán)等待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 {//處理輪詢狀態(tài),當pollFds有事件到來則往下執(zhí)行,否則阻塞在這里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多路復用機制,當接收到客戶端發(fā)出連接請求或者數(shù)據(jù)處理請求時,則往下執(zhí)行;//否則進入continue,跳出本次循環(huán)if ((pollFds[i].revents & POLLIN) == 0) {continue;}if (i == 0) {//即fds[0],代表的是sServerSocket,則意味著有客戶端連接請求;//則創(chuàng)建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函數(shù)中創(chuàng)建的服務端的Socket,調(diào)用getFileDescriptor()方法獲取該Socket的fd字段的值,并添加到fd列表fds中。
-
注釋2處通過遍歷將fds存儲的信息轉(zhuǎn)移到pollFds中
-
注釋3處對pollFds進行遍歷,如果i==0,說明服務端Socket與客戶端連接上了,即:當前Zygote進程與AMS建立了連接
-
注釋4處通過acceptCommandPeer方法得到ZygoteConnection類并添加到Socket連接列表peers中,然后將ZygoteConnection的fd添加到fd列表fds中,以便接收到AMS發(fā)送過來的請求
-
如果i不等于0,則說明AMS向Zygote進程發(fā)送了一個創(chuàng)建應用進程的請求,然后調(diào)用注釋5處ZygoteConnection的runOnce函數(shù)來創(chuàng)建一個新的應用程序進程,并在成功創(chuàng)建后,將這個連接從Socket連接列表peers和fds中移除。
3. 總結(jié)
3.1 Zygote啟動過程調(diào)用流程圖
3.2 Zygote進程啟動總結(jié)
Zygote進程啟動主要做了如下工作:
-
解析init.${ro.zygote}.rc中的參數(shù),創(chuàng)建AppRuntime并調(diào)用它的start方法
-
調(diào)用AndroidRuntime的startVM()方法創(chuàng)建虛擬機,再調(diào)用startReg()注冊JNI函數(shù)
-
通過JNI調(diào)用ZygoteInit的main函數(shù),進入Zygote的Java框架層
-
通過registerZygoteSocket方法建立Socket通道,zygote作為通信的服務端,用于響應客戶端請求
-
preload()預加載通用類、drawable和color資源、openGL以及共享庫以及WebView,用于提高app啟動效率
-
啟動SystemServer進程
-
調(diào)用runSelectLoop(),隨時待命,當接收到請求創(chuàng)建新進程時,立即喚醒Zygote并執(zhí)行相應工作
非常感謝您的耐心閱讀,希望我的文章對您有幫助。歡迎點評、轉(zhuǎn)發(fā)或分享給您的朋友或技術(shù)群。
總結(jié)
以上是生活随笔為你收集整理的从源码角度看Android系统Zygote进程启动过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从源码角度看Android系统init进
- 下一篇: 从源码角度看Android系统Syste