Android Zygote啟動(dòng)構(gòu)造流程及進(jìn)程創(chuàng)建詳解
一、前言
本文主要講解內(nèi)容
1、系統(tǒng)啟動(dòng)zygote、zygote的構(gòu)造流程、主要做了什么
2、如何創(chuàng)建一個(gè)新的進(jìn)程
3、systemserver的ams創(chuàng)建應(yīng)用如何建立socket聯(lián)系,以及如何收發(fā)消息
先簡(jiǎn)單提一下開機(jī)流程
init.rc -> zygote.rc -> app_main.cpp -> AndroidRuntime.cpp (啟動(dòng)虛擬機(jī),注冊(cè)jni,啟動(dòng)zygote) -> ZygoteInit.java -> SystemServer進(jìn)程
其中init是我們系統(tǒng)啟動(dòng)的第一個(gè)進(jìn)程,正是它通過linux的forck方法,創(chuàng)建我們系統(tǒng)的最重要的進(jìn)程之一zygote.
zygote的啟動(dòng)過程以及作用:?jiǎn)?dòng)dalvik虛擬機(jī),加載系統(tǒng)必須的一些資源,啟動(dòng)framework的systemserver進(jìn)程。最后等待app請(qǐng)求創(chuàng)建應(yīng)用進(jìn)程
zygote在fork一個(gè)新的進(jìn)程時(shí)會(huì)克隆出和之前zygote幾乎一樣的進(jìn)程包含zygote的資源,新進(jìn)程不需要進(jìn)行初始化操作,只會(huì)修改一些必要參數(shù)
由于源碼過多,本文的代碼都會(huì)精簡(jiǎn)要點(diǎn),最好結(jié)合源碼閱讀,源碼基于androidR,各安卓版本代碼可能有小區(qū)別但整體不會(huì)變化很大
二、啟動(dòng)流程
2.1、init.rc啟動(dòng)的地方
關(guān)于zygote的rc文件有幾個(gè)地方:
./system/core/rootdir/init.zygote32_64.rc ./system/core/rootdir/init.zygote32.rc ./system/core/rootdir/init.zygote64_32.rc ./system/core/rootdir/init.zygote64.rc
他們的32和64分別對(duì)應(yīng)兩個(gè)啟動(dòng)的地方app_process32和app_process64
例如:zygote64_32.rc,那么它以app_process64為主,app_process32為輔,它兩都會(huì)啟動(dòng),也就是有兩個(gè)zygote進(jìn)程
./system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse 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/tasks
上面就是開始啟動(dòng)zygote的地方,不管是啟動(dòng)32/64,都比較類似,執(zhí)行手機(jī)里的/system/bin/app_process它對(duì)應(yīng)的地方
2.2、app_main init主入口
app_main.cpp frameworks\base\cmds\app_process 11671 2022/2/23 241
app_main.cpp的main函數(shù)就成了入口,它主要做了如下幾個(gè)事情:
//1、構(gòu)建runtime AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); //2、解析運(yùn)行參數(shù) while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; 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; } } //3、runtime start zygoteinit if (zygote) { runtime.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."); }
這里的runtime只是一個(gè)調(diào)用,實(shí)現(xiàn)在
AndroidRuntime.cpp frameworks\base\core\jni
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { //這句日志實(shí)際輸出02-21 11:29:59.487 496 496 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<< //達(dá)標(biāo)className = com.android.internal.os.ZygoteInit ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); //打印關(guān)鍵日志boot_progress_start 表示開機(jī)過程上層開始 for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { primary_zygote = true; /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } } 1、啟動(dòng)虛擬機(jī) /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { return; } onVmCreated(env); 2、注冊(cè)JNI /* * Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } 3、調(diào)用ZygoteInit的main函數(shù) //這就是上面?zhèn)渥⒌腸lassName = ZygoteIni char* slashClassName = toSlashClassName(className != NULL ? className : ""); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
2.3、ZygoteInit.java#main zygote入口
public static void main(String argv[]) { 1、加載進(jìn)程的資源和類(這里可以多線程加載class文件優(yōu)化開機(jī)速度) preload(bootTimingsTraceLog); 2、創(chuàng)建zygoteServer zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { 3、把sokeckname傳進(jìn)去systemserver中,并開始運(yùn)行systemserver Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); if (r != null) { r.run(); return; } 4、最后開啟loop等待消息 caller = zygoteServer.runSelectLoop(abiList); }
看一下forkSystemServer中關(guān)鍵的兩個(gè)地方
private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { 1、zygote調(diào)用forkSystemServer這個(gè)native方法創(chuàng)建出系統(tǒng)進(jìn)程 pid = Zygote.forkSystemServer( parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); 2、給應(yīng)用創(chuàng)建新的進(jìn)程,走h(yuǎn)andleSystemServerProcess邏輯 /* For child process */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); return handleSystemServerProcess(parsedArgs); } }
這里下一步就開始啟動(dòng)我們熟悉的systemserver服務(wù)。關(guān)于Systemserver就不過多闡述了,它主要啟動(dòng)了我們整個(gè)android系統(tǒng)的各種service
三、zygote創(chuàng)建子進(jìn)程流程
3.1、調(diào)用流程
創(chuàng)建一個(gè)應(yīng)用流程這里就不詳述了,都大同小異,這里直接跟蹤到關(guān)鍵點(diǎn),當(dāng)我們跟蹤啟動(dòng)流程跟蹤到
ActivityStack.java frameworks\base\services\core\java\com\android\server\wm
ActivityStack#resumeTopActivityInnerLocked
mStackSupervisor.startSpecificActivity(next, true, false);
startSpecificActivity主要判斷當(dāng)前應(yīng)用是否進(jìn)程已經(jīng)在運(yùn)行,會(huì)跟蹤改到ActivityTaskManager#startProcessAsync方法
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess, mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead, isTop, hostingType, activity.intent.getComponent());即來到ActivityManagerServie#startProcess
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName) { startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */, new HostingRecord(hostingType, hostingName, isTop), ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */, false /* isolated */, true /* keepIfLarge */);
即來到ActivityManagerServie#startProcessLocked - ProcessList#startProcessLocked -
ProcessList.java frameworks\base\services\core\java\com\android\server\am
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { Process.ProcessStartResult startResult; if (hostingRecord.usesWebviewZygote()) { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); // We can't isolate app data and storage data as parent zygote already did that. startResult = appZygote.getProcess().start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap, false, false, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else { //modify for prefork blank process begin PreForkArgs preforkArgs = new PreForkArgs(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); startResult = mService.handlePreForkStartProcess(preforkArgs); if (startResult == null) { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } //modify for prefork blank process end } }
其中主要是appZygote.getProcess().start這一句,調(diào)用棧
ZygoteProcess中start - startViaZygote -
ygoteProces - zygoteSendArgsAndGetResult - attemptZygoteSendArgsAndGetResult
3.2、連接socket發(fā)送數(shù)據(jù)
1、sokeck建立的地方
startViaZygote - openZygoteSocketIfNeeded - attemptConnectionToPrimaryZygote @GuardedBy("mLock") private void attemptConnectionToPrimaryZygote() throws IOException { primaryZygoteState = ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress); //構(gòu)建好消息這里發(fā)送 maybeSetApiBlacklistExemptions(primaryZygoteState, false); } static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress, @Nullable LocalSocketAddress usapSocketAddress) { DataInputStream zygoteInputStream; BufferedWriter zygoteOutputWriter; final LocalSocket zygoteSessionSocket = new LocalSocket(); if (zygoteSocketAddress == null) { throw new IllegalArgumentException("zygoteSocketAddress can't be null"); } try { //關(guān)鍵點(diǎn),這里連接上了zygote的socket zygoteSessionSocket.connect(zygoteSocketAddress); zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream()); zygoteOutputWriter = new BufferedWriter( new OutputStreamWriter(zygoteSessionSocket.getOutputStream()), Zygote.SOCKET_BUFFER_SIZE); }
2、通過zygoteState的BufferedWriter,用socket發(fā)消息給zygote
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult( ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx { try { final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter; final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream; zygoteWriter.write(msgStr); zygoteWriter.flush(); // Always read the entire result from the input stream to avoid leaving // bytes in the stream for future process starts to accidentally stumble // upon. Process.ProcessStartResult result = new Process.ProcessStartResult(); result.pid = zygoteInputStream.readInt(); result.usingWrapper = zygoteInputStream.readBoolean(); if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); }
上面這段代碼,通過zygoteWriter把消息發(fā)給zygote,即發(fā)送流程
3.3、接收流程
接著上面的第二部分的ZygoteInit#main函數(shù)中,new了一個(gè)ZygoteServer
3.3.1 創(chuàng)建socket
ZygoteServer(boolean isPrimaryZygote) { mUsapPoolEventFD = Zygote.getUsapPoolEventFD(); if (isPrimaryZygote) { mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME); static LocalServerSocket createManagedSocketFromInitSocket(String socketName) { int fileDesc; // fullSocketName = “ANDROID_SOCKET_” + “zygote"; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { 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); return new LocalServerSocket(fd); } catch (IOException ex) { throw new RuntimeException( "Error building socket from file descriptor: " + fileDesc, ex); } }
3.3.2 sokeck創(chuàng)建后消息發(fā)送到了哪里
這里又接著上面的第二部分的ZygoteInit#main函數(shù)中第四步zygoteServer.runSelectLoop(abiList);
ZygoteServer創(chuàng)建了socket,runSelectLoop會(huì)執(zhí)行
Runnable runSelectLoop(String abiList) { while(true) { try { ZygoteConnection connection = peers.get(pollIndex); // while循環(huán)到這句話會(huì)執(zhí)行forck操作,進(jìn)行新的進(jìn)程的創(chuàng)建 final Runnable command = connection.processOneCommand(this); // TODO (chriswailes): Is this extra check necessary? if (mIsForkChild) { // We're in the child. We should always have a command to run at // this stage if processOneCommand hasn't called "exec". if (command == null) { throw new IllegalStateException("command == null"); } return command; } } }
3.4 創(chuàng)建子進(jìn)程
ZygoteConnection#processOneCommand Runnable processOneCommand(ZygoteServer zygoteServer) { 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.mIsTopApp, parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs); //穿件完后給ams回復(fù) return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote); } //Zygote#forkAndSpecialize static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { ZygoteHooks.preFork(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs);
子進(jìn)程的初始化操作就不詳述了大概說下調(diào)用棧
handleChildProc - ZygoteInit.zygoteInit - RuntimeInit.applicationInit - RuntimeInit.findStaticMain
四、寫在最后
本文意在分析zygote的構(gòu)建,以及如何通過socke構(gòu)建新的進(jìn)程。下面說兩個(gè)比較常規(guī)的問題
為啥系統(tǒng)其它進(jìn)程都用binder而這里采用socket呢?
首先binder是多線程的,zygote的fork函數(shù)是不允許多線程的,不然容易造成死鎖(copy on write)
為啥運(yùn)行app不新建一個(gè)進(jìn)程而采用zygote fork?
因?yàn)閼?yīng)用是獨(dú)立運(yùn)行在dalvik中,他們的進(jìn)程空間是分開的。如果每個(gè)應(yīng)用都是新建進(jìn)程,那么zygote加載的系統(tǒng)資源就會(huì)重復(fù)創(chuàng)建添加浪費(fèi)系統(tǒng)資源。且zygote孵化也可節(jié)約創(chuàng)建的時(shí)間。
以上就是Android Zygote啟動(dòng)構(gòu)造流程及進(jìn)程創(chuàng)建詳解的詳細(xì)內(nèi)容,更多關(guān)于Android Zygote啟動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android開發(fā)之拖動(dòng)條/滑動(dòng)條控件、星級(jí)評(píng)分控件功能的實(shí)例代碼
這篇文章主要介紹了Android開發(fā)之拖動(dòng)條/滑動(dòng)條控件、星級(jí)評(píng)分控件功能的實(shí)例代碼,需要的朋友可以參考下2019-05-05Android中webView加載H5綁定cookie實(shí)例
這篇文章主要介紹了Android中webView加載H5綁定cookie實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android?通過productFlavors實(shí)現(xiàn)多渠道打包方法示例
這篇文章主要為大家介紹了Android?通過productFlavors實(shí)現(xiàn)多渠道打包方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Android入門之利用OKHttp實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能
這篇文章主要為大家詳細(xì)介紹了Android如何使用OKHttp多線程制作像迅雷一樣的斷點(diǎn)續(xù)傳功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-01-01Android?SeekBar充當(dāng)Progress實(shí)現(xiàn)兔兔進(jìn)度條Plus
這篇文章主要為大家介紹了Android?SeekBar充當(dāng)Progress實(shí)現(xiàn)兔兔進(jìn)度條Plus示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Android開發(fā)Jetpack組件Lifecycle使用篇
這一篇文章來介紹Android?Jetpack架構(gòu)組件的Lifecycle;?Lifecycle用于幫助開發(fā)者管理Activity和Fragment?的生命周期,?由于Lifecycle是LiveData和ViewModel的基礎(chǔ);所以需要先學(xué)習(xí)它2022-08-08