Android Zygote啟動構(gòu)造流程及進程創(chuàng)建詳解
一、前言
本文主要講解內(nèi)容
1、系統(tǒng)啟動zygote、zygote的構(gòu)造流程、主要做了什么
2、如何創(chuàng)建一個新的進程
3、systemserver的ams創(chuàng)建應(yīng)用如何建立socket聯(lián)系,以及如何收發(fā)消息
先簡單提一下開機流程
init.rc -> zygote.rc -> app_main.cpp -> AndroidRuntime.cpp (啟動虛擬機,注冊jni,啟動zygote) -> ZygoteInit.java -> SystemServer進程
其中init是我們系統(tǒng)啟動的第一個進程,正是它通過linux的forck方法,創(chuàng)建我們系統(tǒng)的最重要的進程之一zygote.
zygote的啟動過程以及作用:啟動dalvik虛擬機,加載系統(tǒng)必須的一些資源,啟動framework的systemserver進程。最后等待app請求創(chuàng)建應(yīng)用進程
zygote在fork一個新的進程時會克隆出和之前zygote幾乎一樣的進程包含zygote的資源,新進程不需要進行初始化操作,只會修改一些必要參數(shù)
由于源碼過多,本文的代碼都會精簡要點,最好結(jié)合源碼閱讀,源碼基于androidR,各安卓版本代碼可能有小區(qū)別但整體不會變化很大
二、啟動流程
2.1、init.rc啟動的地方
關(guān)于zygote的rc文件有幾個地方:
./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分別對應(yīng)兩個啟動的地方app_process32和app_process64
例如:zygote64_32.rc,那么它以app_process64為主,app_process32為輔,它兩都會啟動,也就是有兩個zygote進程
./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
上面就是開始啟動zygote的地方,不管是啟動32/64,都比較類似,執(zhí)行手機里的/system/bin/app_process它對應(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ù)就成了入口,它主要做了如下幾個事情:
//1、構(gòu)建runtime AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); //2、解析運行參數(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只是一個調(diào)用,實現(xiàn)在
AndroidRuntime.cpp frameworks\base\core\jni
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { //這句日志實際輸出02-21 11:29:59.487 496 496 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<< //達標(biāo)className = com.android.internal.os.ZygoteInit ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); //打印關(guān)鍵日志boot_progress_start 表示開機過程上層開始 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、啟動虛擬機 /* 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、注冊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、加載進程的資源和類(這里可以多線程加載class文件優(yōu)化開機速度) preload(bootTimingsTraceLog); 2、創(chuàng)建zygoteServer zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { 3、把sokeckname傳進去systemserver中,并開始運行systemserver Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); if (r != null) { r.run(); return; } 4、最后開啟loop等待消息 caller = zygoteServer.runSelectLoop(abiList); }
看一下forkSystemServer中關(guān)鍵的兩個地方
private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { 1、zygote調(diào)用forkSystemServer這個native方法創(chuàng)建出系統(tǒng)進程 pid = Zygote.forkSystemServer( parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); 2、給應(yīng)用創(chuàng)建新的進程,走h(yuǎn)andleSystemServerProcess邏輯 /* For child process */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); return handleSystemServerProcess(parsedArgs); } }
這里下一步就開始啟動我們熟悉的systemserver服務(wù)。關(guān)于Systemserver就不過多闡述了,它主要啟動了我們整個android系統(tǒng)的各種service
三、zygote創(chuàng)建子進程流程
3.1、調(diào)用流程
創(chuàng)建一個應(yīng)用流程這里就不詳述了,都大同小異,這里直接跟蹤到關(guān)鍵點,當(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īng)在運行,會跟蹤改到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)鍵點,這里連接上了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了一個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會執(zhí)行
Runnable runSelectLoop(String abiList) { while(true) { try { ZygoteConnection connection = peers.get(pollIndex); // while循環(huán)到這句話會執(zhí)行forck操作,進行新的進程的創(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)建子進程
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);
子進程的初始化操作就不詳述了大概說下調(diào)用棧
handleChildProc - ZygoteInit.zygoteInit - RuntimeInit.applicationInit - RuntimeInit.findStaticMain
四、寫在最后
本文意在分析zygote的構(gòu)建,以及如何通過socke構(gòu)建新的進程。下面說兩個比較常規(guī)的問題
為啥系統(tǒng)其它進程都用binder而這里采用socket呢?
首先binder是多線程的,zygote的fork函數(shù)是不允許多線程的,不然容易造成死鎖(copy on write)
為啥運行app不新建一個進程而采用zygote fork?
因為應(yīng)用是獨立運行在dalvik中,他們的進程空間是分開的。如果每個應(yīng)用都是新建進程,那么zygote加載的系統(tǒng)資源就會重復(fù)創(chuàng)建添加浪費系統(tǒng)資源。且zygote孵化也可節(jié)約創(chuàng)建的時間。
以上就是Android Zygote啟動構(gòu)造流程及進程創(chuàng)建詳解的詳細(xì)內(nèi)容,更多關(guān)于Android Zygote啟動的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android開發(fā)之拖動條/滑動條控件、星級評分控件功能的實例代碼
這篇文章主要介紹了Android開發(fā)之拖動條/滑動條控件、星級評分控件功能的實例代碼,需要的朋友可以參考下2019-05-05Android?通過productFlavors實現(xiàn)多渠道打包方法示例
這篇文章主要為大家介紹了Android?通過productFlavors實現(xiàn)多渠道打包方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02Android入門之利用OKHttp實現(xiàn)斷點續(xù)傳功能
這篇文章主要為大家詳細(xì)介紹了Android如何使用OKHttp多線程制作像迅雷一樣的斷點續(xù)傳功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-01-01Android?SeekBar充當(dāng)Progress實現(xiàn)兔兔進度條Plus
這篇文章主要為大家介紹了Android?SeekBar充當(dāng)Progress實現(xiàn)兔兔進度條Plus示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02Android開發(fā)Jetpack組件Lifecycle使用篇
這一篇文章來介紹Android?Jetpack架構(gòu)組件的Lifecycle;?Lifecycle用于幫助開發(fā)者管理Activity和Fragment?的生命周期,?由于Lifecycle是LiveData和ViewModel的基礎(chǔ);所以需要先學(xué)習(xí)它2022-08-08