Android Zygote 進(jìn)程的啟動(dòng)
? ? ? ? Zygote意為“受精卵”,即所有的Android進(jìn)程都是由其“發(fā)育”而來(lái)的意思。本人試著把啃代碼學(xué)到的內(nèi)容整理出來(lái),希望會(huì)對(duì)自己以后有用。
Init
? ? ? ? Init進(jìn)程是Linux系統(tǒng)上的第一個(gè)用戶進(jìn)程,用戶為root,擁有系統(tǒng)中最高的權(quán)限。它會(huì)實(shí)現(xiàn)掛載文件系統(tǒng),并啟動(dòng)ServiceManager/Zygote兩大進(jìn)程,正式這兩大進(jìn)程構(gòu)成了Android系統(tǒng)的基礎(chǔ)。
? ? ? ? 簡(jiǎn)單來(lái)說(shuō),Init進(jìn)程通過(guò)解析init.rc文件,然后執(zhí)行自己的工作,其中,Zygote進(jìn)程相關(guān)的配置如下(system/core/rootdir/init.rc):
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實(shí)際上執(zhí)行的是/system/bin/app_process應(yīng)用程序,參數(shù)中包含了--zygote和--start-system-server。 另外,
????socket?zygote?stream?660?root?system
? ? ?屬性的配置,說(shuō)明Init進(jìn)程在啟動(dòng)zygote進(jìn)程時(shí),會(huì)為zygote進(jìn)程創(chuàng)建一個(gè)stream型的domain socket,并保存到ANDROID_SOCKET_zygote系統(tǒng)變量中。(對(duì)這個(gè)過(guò)程涉及到init進(jìn)程的實(shí)現(xiàn),可以參考代碼system/core/init/init.c)
app_process ? ? ? ? Init進(jìn)程啟動(dòng)Zygote進(jìn)程以后,代碼執(zhí)行到app_process的主入口(frameworks/base/cmds/app_process/app_main.cpp):
int?main(int?argc,?const?char*?const?argv[]) { ????//?These?are?global?variables?in?ProcessState.cpp ????mArgC?=?argc; ????mArgV?=?argv; ????mArgLen?=?0; ????for?(int?i=0;?i<argc;?i++)?{ ????????mArgLen?+=?strlen(argv[i])?+?1; ????} ????mArgLen--; ????AppRuntime?runtime; ????const?char*?argv0?=?argv[0]; ????//?Process?command?line?arguments ????//?ignore?argv[0] ????argc--; ????argv++; ????//?Everything?up?to?'--'?or?first?non?'-'?arg?goes?to?the?vm ????int?i?=?runtime.addVmArguments(argc,?argv); ????//?Parse?runtime?arguments.??Stop?at?first?unrecognized?option. ????bool?zygote?=?false; ????bool?startSystemServer?=?false; ????bool?application?=?false; ????const?char*?parentDir?=?NULL; ????const?char*?niceName?=?NULL; ????const?char*?className?=?NULL; ????while?(i?<?argc)?{ ????????const?char*?arg?=?argv[i++]; ????????if?(!parentDir)?{ ????????????parentDir?=?arg; ????????}?else?if?(strcmp(arg,?"--zygote")?==?0)?{ ????????????zygote?=?true; ????????????niceName?=?"zygote"; ????????}?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?=?arg?+?12; ????????}?else?{ ????????????className?=?arg; ????????????break; ????????} ????} ????if?(niceName?&&?*niceName)?{ ????????setArgv0(argv0,?niceName); ????????set_process_name(niceName); ????} ????runtime.mParentDir?=?parentDir; ????if?(zygote)?{ ????????runtime.start("com.android.internal.os.ZygoteInit", ????????????????startSystemServer???"start-system-server"?:?""); ????}?else?if?(className)?{ ????????//?Remainder?of?args?get?passed?to?startup?class?main() ????????runtime.mClassName?=?className; ????????runtime.mArgC?=?argc?-?i; ????????runtime.mArgV?=?argv?+?i; ????????runtime.start("com.android.internal.os.RuntimeInit", ????????????????application???"application"?:?"tool"); ????}?else?{ ????????fprintf(stderr,?"Error:?no?class?name?or?--zygote?supplied.n"); ????????app_usage(); ????????LOG_ALWAYS_FATAL("app_process:?no?class?name?or?--zygote?supplied."); ????????return?10; ????} }
? ? ? ? ?main函數(shù)首先分析參數(shù),決定下一步要做什么:
??while?(i?<?argc)?{ ????????const?char*?arg?=?argv[i++]; ????????if?(!parentDir)?{ ????????????parentDir?=?arg; ????????}?else?if?(strcmp(arg,?"--zygote")?==?0)?{ ????????????zygote?=?true; ????????????niceName?=?"zygote"; ????????}?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?=?arg?+?12; ????????}?else?{ ????????????className?=?arg; ????????????break; ????????} ????}
? ? ? ? 上一步中,我們知道Init進(jìn)程啟動(dòng)Zygote進(jìn)程的時(shí)候,包含了--zygote參數(shù)和--start-system-server參數(shù),所以,現(xiàn)在zygote和startSystemServer都為true,所以接下來(lái)執(zhí)行:
????if?(zygote)?{ ????????runtime.start("com.android.internal.os.ZygoteInit", ????????????????startSystemServer???"start-system-server"?:?""); ????}?else?if?(className)?{ ?????????...... ????}?else?{ ?????????...... ????}
? ? ? 這次的參數(shù)分別為“com.android.internal.os.ZygoteInit”和“start-system-server”。 AndroidRunTime ? ? ? runtime的類型為AppRunTime,AppRumTime的定義(frameworks/base/cmds/app_process/app_main.cpp):
class?AppRuntime?:?public?AndroidRuntime { public: ????AppRuntime() ????????:?mParentDir(NULL) ????????,?mClassName(NULL) ????????,?mClass(NULL) ????????,?mArgC(0) ????????,?mArgV(NULL) ????{ ????} #if?0 ????//?this?appears?to?be?unused ????const?char*?getParentDir()?const ????{ ????????return?mParentDir; ????} #endif ????const?char*?getClassName()?const ????{ ????????return?mClassName; ????} ????virtual?void?onVmCreated(JNIEnv*?env) ????{ ????????if?(mClassName?==?NULL)?{ ????????????return;?//?Zygote.?Nothing?to?do?here. ????????} ????????/* ?????????*?This?is?a?little?awkward?because?the?JNI?FindClass?call?uses?the ?????????*?class?loader?associated?with?the?native?method?we're?executing?in. ?????????*?If?called?in?onStarted?(from?RuntimeInit.finishInit?because?we're ?????????*?launching?"am",?for?example),?FindClass?would?see?that?we're?calling ?????????*?from?a?boot?class'?native?method,?and?so?wouldn't?look?for?the?class ?????????*?we're?trying?to?look?up?in?CLASSPATH.?Unfortunately?it?needs?to, ?????????*?because?the?"am"?classes?are?not?boot?classes. ?????????* ?????????*?The?easiest?fix?is?to?call?FindClass?here,?early?on?before?we?start ?????????*?executing?boot?class?Java?code?and?thereby?deny?ourselves?access?to ?????????*?non-boot?classes. ?????????*/ ????????char*?slashClassName?=?toSlashClassName(mClassName); ????????mClass?=?env->FindClass(slashClassName); ????????if?(mClass?==?NULL)?{ ????????????ALOGE("ERROR:?could?not?find?class?'%s'n",?mClassName); ????????} ????????free(slashClassName); ????????mClass?=?reinterpret_cast(env->NewGlobalRef(mClass)); ????} ????virtual?void?onStarted() ????{ ????????spproc?=?ProcessState::self(); ????????ALOGV("App?process:?starting?thread?pool.n"); ????????proc->startThreadPool(); ????????AndroidRuntime*?ar?=?AndroidRuntime::getRuntime(); ????????ar->callMain(mClassName,?mClass,?mArgC,?mArgV); ????????IPCThreadState::self()->stopProcess(); ????} ????virtual?void?onZygoteInit() ????{ ????????spproc?=?ProcessState::self(); ????????ALOGV("App?process:?starting?thread?pool.n"); ????????proc->startThreadPool(); ????} ????virtual?void?onExit(int?code) ????{ ????????if?(mClassName?==?NULL)?{ ????????????//?if?zygote ????????????IPCThreadState::self()->stopProcess(); ????????} ????????AndroidRuntime::onExit(code); ????} ????const?char*?mParentDir; ????const?char*?mClassName; ????jclass?mClass; ????int?mArgC; ????const?char*?const*?mArgV; }; }
? ? ? ? 可以看到,AppRuntime并沒(méi)有重載start函數(shù),所以,目前會(huì)執(zhí)行其父類AndroidRuntime的start函數(shù)(frameworks/base/core/jni/AndroidRunTime.cpp):
/* ?*?Start?the?Android?runtime.??This?involves?starting?the?virtual?machine ?*?and?calling?the?"static?void?main(String[]?args)"?method?in?the?class ?*?named?by?"className". ?* ?*?Passes?the?main?function?two?arguments,?the?class?name?and?the?specified ?*?options?string. ?*/ void?AndroidRuntime::start(const?char*?className,?const?char*?options) { ????ALOGD("n>>>>>>?AndroidRuntime?START?%s?<<<<<<n", ????????????className?!=?NULL???className?:?"(unknown)"); ????blockSigpipe(); ????/* ?????*?'startSystemServer?==?true'?means?runtime?is?obsolete?and?not?run?from ?????*?init.rc?anymore,?so?we?print?out?the?boot?start?event?here. ?????*/ ????if?(strcmp(options,?"start-system-server")?==?0)?{ ????????/*?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))); ????} ????const?char*?rootDir?=?getenv("ANDROID_ROOT"); ????if?(rootDir?==?NULL)?{ ????????rootDir?=?"/system"; ????????if?(!hasDir("/system"))?{ ????????????LOG_FATAL("No?root?directory?specified,?and?/android?does?not?exist."); ????????????return; ????????} ????????setenv("ANDROID_ROOT",?rootDir,?1); ????} ????//const?char*?kernelHack?=?getenv("LD_ASSUME_KERNEL"); ????//ALOGD("Found?LD_ASSUME_KERNEL='%s'n",?kernelHack); ????/*?start?the?virtual?machine?*/ ????JNIEnv*?env; ????if?(startVm(&mJavaVM,?&env)?!=?0)?{ ????????return; ????} ????onVmCreated(env); ????/* ?????*?Register?android?functions. ?????*/ ????if?(startReg(env)?<?0)?{ ????????ALOGE("Unable?to?register?all?android?nativesn"); ????????return; ????} ????/* ?????*?We?want?to?call?main()?with?a?String?array?with?arguments?in?it. ?????*?At?present?we?have?two?arguments,?the?class?name?and?an?option?string. ?????*?Create?an?array?to?hold?them. ?????*/ ????jclass?stringClass; ????jobjectArray?strArray; ????jstring?classNameStr; ????jstring?optionsStr; ????stringClass?=?env->FindClass("java/lang/String"); ????assert(stringClass?!=?NULL); ????strArray?=?env->NewObjectArray(2,?stringClass,?NULL); ????assert(strArray?!=?NULL); ????classNameStr?=?env->NewStringUTF(className); ????assert(classNameStr?!=?NULL); ????env->SetObjectArrayElement(strArray,?0,?classNameStr); ????optionsStr?=?env->NewStringUTF(options); ????env->SetObjectArrayElement(strArray,?1,?optionsStr); ????/* ?????*?Start?VM.??This?thread?becomes?the?main?thread?of?the?VM,?and?will ?????*?not?return?until?the?VM?exits. ?????*/ ????char*?slashClassName?=?toSlashClassName(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"); ????????if?(startMeth?==?NULL)?{ ????????????ALOGE("JavaVM?unable?to?find?main()?in?'%s'n",?className); ????????????/*?keep?going?*/ ????????}?else?{ ????????????env->CallStaticVoidMethod(startClass,?startMeth,?strArray); #if?0 ????????????if?(env->ExceptionCheck()) ????????????????threadExitUncaughtException(env); #endif ????????} ????} ????free(slashClassName); ????ALOGD("Shutting?down?VMn"); ????if?(mJavaVM->DetachCurrentThread()?!=?JNI_OK) ????????ALOGW("Warning:?unable?to?detach?main?threadn"); ????if?(mJavaVM->DestroyJavaVM()?!=?0) ????????ALOGW("Warning:?VM?did?not?shut?down?cleanlyn"); }
? ? ? ? AndroidRumTime.start主要做了三項(xiàng)工作: startVM啟動(dòng)Android虛擬機(jī),并呼叫onVMCreate函數(shù)。前面,我們有看到AppRuntime有重載onVMCreated函數(shù)(不過(guò),對(duì)于app_process作為Zygote進(jìn)程啟動(dòng)的情況,不做任何處理就返回)startReg注冊(cè)需要的Native函數(shù),基本Android的每個(gè)模塊都有一些native實(shí)現(xiàn)需要和Java代碼關(guān)聯(lián)起來(lái),事先注冊(cè)能夠提高性能,(另一種方案是第一次調(diào)用的時(shí)候查找實(shí)現(xiàn)函數(shù)并完成注冊(cè))查找className指定的class的main函數(shù),并以options為參數(shù),調(diào)用main函數(shù)。這里不對(duì)代碼做解釋,用java寫(xiě)過(guò)反射調(diào)用的人應(yīng)該基本能看懂。 ? ? ? ?runtime.start最后會(huì)調(diào)用ZygoteIni的.main函數(shù),參數(shù)為--start-system-server。 ? ? ???因?yàn)橐呀?jīng)啟動(dòng)了java虛擬機(jī),接下來(lái)可以執(zhí)行Java代碼了,所以,我們將進(jìn)入下一個(gè)世界。 ZygoteInit ? ? ? ?ZygoteInit從類名看,從現(xiàn)在開(kāi)始是真正的“Zygote”(frameworks/base/core/java/com/android/internal/os/ZygoteInit.java):
????public?static?void?main(String?argv[])?{ ????????try?{ ????????????//?Start?profiling?the?zygote?initialization. ????????????SamplingProfilerIntegration.start(); ????????????registerZygoteSocket(); ????????????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(); ????????????//?If?requested,?start?system?server?directly?from?Zygote ????????????if?(argv.length?!=?2)?{ ????????????????throw?new?RuntimeException(argv[0]?+?USAGE_STRING); ????????????} ????????????if?(argv[1].equals("start-system-server"))?{ ????????????????startSystemServer(); ????????????}?else?if?(!argv[1].equals(""))?{ ????????????????throw?new?RuntimeException(argv[0]?+?USAGE_STRING); ????????????} ????????????Log.i(TAG,?"Accepting?command?socket?connections"); ????????????if?(ZYGOTE_FORK_MODE)?{ ????????????????runForkMode(); ????????????}?else?{ ????????????????runSelectLoopMode(); ????????????} ????????????closeServerSocket(); ????????}?catch?(MethodAndArgsCaller?caller)?{ ????????????caller.run(); ????????}?catch?(RuntimeException?ex)?{ ????????????Log.e(TAG,?"Zygote?died?with?exception",?ex); ????????????closeServerSocket(); ????????????throw?ex; ????????} ????}
? ? ? ? 從代碼看,main函數(shù)完成了四項(xiàng)工作: registerZygoteSocketpreloadstartSystemServer,因?yàn)橹癆ndroidRuntime是以“start-system-server”為參數(shù)調(diào)用main函數(shù)的,所以這里會(huì)執(zhí)行startSystemServerrunSelectLoopMode,ZYGOTE_FORK_MODE常量恒定為false,所以會(huì)執(zhí)行runSelectLoopMode ? ? ? ? 再繼續(xù)分析前,先要做點(diǎn)鋪墊。Zygote進(jìn)程的作用是為了fork出新的Android進(jìn)程,那Zygote是如何得知它需要fork一個(gè)進(jìn)程的呢? ? ? ? ? 先看一段“客戶端“的代碼(frameworks/base/core/java/android/os/Process.java):
????public?static?final?ProcessStartResult?start(final?String?processClass, ??????????????????????????????????final?String?niceName, ??????????????????????????????????int?uid,?int?gid,?int[]?gids, ??????????????????????????????????int?debugFlags,?int?mountExternal, ??????????????????????????????????int?targetSdkVersion, ??????????????????????????????????String?seInfo, ??????????????????????????????????String[]?zygoteArgs)?{ ????????try?{ ????????????return?startViaZygote(processClass,?niceName,?uid,?gid,?gids, ????????????????????debugFlags,?mountExternal,?targetSdkVersion,?seInfo,?zygoteArgs); ????????}?catch?(ZygoteStartFailedEx?ex)?{ ????????????Log.e(LOG_TAG, ????????????????????"Starting?VM?process?through?Zygote?failed"); ????????????throw?new?RuntimeException( ????????????????????"Starting?VM?process?through?Zygote?failed",?ex); ????????} ????} ????private?static?void?openZygoteSocketIfNeeded()? ????????????throws?ZygoteStartFailedEx?{ ????????int?retryCount; ????????if?(sPreviousZygoteOpenFailed)?{ ????????????/* ?????????????*?If?we've?failed?before,?expect?that?we'll?fail?again?and ?????????????*?don't?pause?for?retries. ?????????????*/ ????????????retryCount?=?0; ????????}?else?{ ????????????retryCount?=?10;???????????? ????????} ????????/* ?????????*?See?bug?#811181:?Sometimes?runtime?can?make?it?up?before?zygote. ?????????*?Really,?we'd?like?to?do?something?better?to?avoid?this?condition, ?????????*?but?for?now?just?wait?a?bit... ?????????*/ ????????for?(int?retry?=?0 ????????????????;?(sZygoteSocket?==?null)?&&?(retry?<?(retryCount?+?1)) ????????????????;?retry++?)?{ ????????????if?(retry?>?0)?{ ????????????????try?{ ????????????????????Log.i("Zygote",?"Zygote?not?up?yet,?sleeping..."); ????????????????????Thread.sleep(ZYGOTE_RETRY_MILLIS); ????????????????}?catch?(InterruptedException?ex)?{ ????????????????????//?should?never?happen ????????????????} ????????????} ????????????try?{ ????????????????sZygoteSocket?=?new?LocalSocket(); ????????????????sZygoteSocket.connect(new?LocalSocketAddress(ZYGOTE_SOCKET,? ????????????????????????LocalSocketAddress.Namespace.RESERVED)); ????????????????sZygoteInputStream ????????????????????????=?new?DataInputStream(sZygoteSocket.getInputStream()); ????????????????sZygoteWriter?= ????????????????????new?BufferedWriter( ????????????????????????????new?OutputStreamWriter( ????????????????????????????????????sZygoteSocket.getOutputStream()), ????????????????????????????256); ????????????????Log.i("Zygote",?"Process:?zygote?socket?opened"); ????????????????sPreviousZygoteOpenFailed?=?false; ????????????????break; ????????????}?catch?(IOException?ex)?{ ????????????????if?(sZygoteSocket?!=?null)?{ ????????????????????try?{ ????????????????????????sZygoteSocket.close(); ????????????????????}?catch?(IOException?ex2)?{ ????????????????????????Log.e(LOG_TAG,"I/O?exception?on?close?after?exception", ????????????????????????????????ex2); ????????????????????} ????????????????} ????????????????sZygoteSocket?=?null; ????????????} ????????} ????????if?(sZygoteSocket?==?null)?{ ????????????sPreviousZygoteOpenFailed?=?true; ????????????throw?new?ZygoteStartFailedEx("connect?failed");????????????????? ????????} ????} ????private?static?ProcessStartResult?zygoteSendArgsAndGetResult(ArrayListargs) ????????????throws?ZygoteStartFailedEx?{ ????????openZygoteSocketIfNeeded(); ????????try?{ ????????????sZygoteWriter.write(Integer.toString(args.size())); ????????????sZygoteWriter.newLine(); ????????????int?sz?=?args.size(); ????????????for?(int?i?=?0;?i?<?sz;?i++)?{ ????????????????String?arg?=?args.get(i); ????????????????if?(arg.indexOf('n')?>=?0)?{ ????????????????????throw?new?ZygoteStartFailedEx( ????????????????????????????"embedded?newlines?not?allowed"); ????????????????} ????????????????sZygoteWriter.write(arg); ????????????????sZygoteWriter.newLine(); ????????????} ????????????sZygoteWriter.flush(); ????????????//?Should?there?be?a?timeout?on?this? ????????????ProcessStartResult?result?=?new?ProcessStartResult(); ????????????result.pid?=?sZygoteInputStream.readInt(); ????????????if?(result.pid?<?0)?{ ????????????????throw?new?ZygoteStartFailedEx("fork()?failed"); ????????????} ????????????result.usingWrapper?=?sZygoteInputStream.readBoolean(); ????????????return?result; ????????}?catch?(IOException?ex)?{ ????????????try?{ ????????????????if?(sZygoteSocket?!=?null)?{ ????????????????????sZygoteSocket.close(); ????????????????} ????????????}?catch?(IOException?ex2)?{ ????????????????//?we're?going?to?fail?anyway ????????????????Log.e(LOG_TAG,"I/O?exception?on?routine?close",?ex2); ????????????} ????????????sZygoteSocket?=?null; ????????????throw?new?ZygoteStartFailedEx(ex); ????????} ????}
? ? ? ? 這段代碼是framework層通知Zygote進(jìn)程進(jìn)行fork用的,代碼略長(zhǎng),也沒(méi)有必要仔細(xì)分析,只要看明白一點(diǎn)即可: ? ? ? ? framework層會(huì)通過(guò)Unix domain socket連接到Zygote進(jìn)程,并發(fā)送字符串型的參數(shù)。 registerZygoteSocket ? ? ? ? ?剛才有看到Process會(huì)通過(guò)domain socket連接到Zygote進(jìn)程,那Zygote進(jìn)程理所當(dāng)然的要監(jiān)聽(tīng)這個(gè)socket端口了,這就是registerZygoteSocket函數(shù)要做的(或者說(shuō)它做了一半):
?/** ?????*?Registers?a?server?socket?for?zygote?command?connections ?????* ?????*?@throws?RuntimeException?when?open?fails ?????*/ ????private?static?void?registerZygoteSocket()?{ ????????if?(sServerSocket?==?null)?{ ????????????int?fileDesc; ????????????try?{ ????????????????String?env?=?System.getenv(ANDROID_SOCKET_ENV); ????????????????fileDesc?=?Integer.parseInt(env); ????????????}?catch?(RuntimeException?ex)?{ ????????????????throw?new?RuntimeException( ????????????????????????ANDROID_SOCKET_ENV?+?"?unset?or?invalid",?ex); ????????????} ????????????try?{ ????????????????sServerSocket?=?new?LocalServerSocket( ????????????????????????createFileDescriptor(fileDesc)); ????????????}?catch?(IOException?ex)?{ ????????????????throw?new?RuntimeException( ????????????????????????"Error?binding?to?local?socket?'"?+?fileDesc?+?"'",?ex); ????????????} ????????} ????}
? ? ? ? registerZygoteSocket函數(shù)中,先從
private?static?final?String?ANDROID_SOCKET_ENV?=?"ANDROID_SOCKET_zygote";
? ? ? ?環(huán)境變量中,讀取一個(gè)int值作為文件描述父,創(chuàng)建文件描述符,為什么呢? ? ? ? ?如果還記得init.rc的配置到話,一切就可以解釋了:
????socket?zygote?stream?660?root?system
? ? ? ?init進(jìn)程在處理這一行屬性時(shí),會(huì)先在dev/socket下創(chuàng)建一個(gè)名為zygote的設(shè)備文件,然后打開(kāi)這個(gè)文件,并把文件描述符保存到環(huán)境變量中。環(huán)境變量名的規(guī)則為"ANDROID_SOCKET_"+第一參數(shù)(這里為zygote)。所以,app_main就可以通過(guò)指定的環(huán)境變量來(lái)獲取這個(gè)文件描述符,并由此創(chuàng)建LocalServerSocket。
preload
? ? ? ? 因?yàn)樗械腁ndroid進(jìn)程都是從Zygote進(jìn)程fork出來(lái)的,而子進(jìn)程會(huì)繼承Zygote的資源。換言之,如果Zygote進(jìn)程持有了資源,所有android進(jìn)程就都有了。所以,Zygote會(huì)預(yù)加載一些系統(tǒng)資源,以加速子進(jìn)程的啟動(dòng)速度(子進(jìn)程以寫(xiě)時(shí)復(fù)制的機(jī)制進(jìn)行資源共享,所以不必?fù)?dān)心內(nèi)存占用問(wèn)題。另外Android系統(tǒng)的啟動(dòng)時(shí)間可能有大概40%的時(shí)間耗費(fèi)在這個(gè)preload函數(shù)上,但是從整體上來(lái)說(shuō),這是利大于弊的)。
????static?void?preload()?{ ????????preloadClasses();//加載java類 ????????preloadResources();//加載icon,字串等資源 ????}
startSystemServer ? ? ? Zygote進(jìn)程啟動(dòng)以后,會(huì)由Zygote進(jìn)程fork出SystemServer,繼續(xù)啟動(dòng)系統(tǒng):
????/** ?????*?Prepare?the?arguments?and?fork?for?the?system?server?process. ?????*/ ????private?static?boolean?startSystemServer() ????????????throws?MethodAndArgsCaller,?RuntimeException?{ ????????/*?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,3001,3002,3003,3006,3007", ????????????"--capabilities=130104352,130104352", ????????????"--runtime-init", ????????????"--nice-name=system_server", ????????????"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)?{ ????????????handleSystemServerProcess(parsedArgs); ????????} ????????return?true; ????}
? ? ? ? ?首先,確定SystemServer的啟動(dòng)參數(shù),然后,調(diào)用Zygote.forkSysetmServer函數(shù),開(kāi)始執(zhí)行fork操作。這一塊和SystemServer的啟動(dòng)過(guò)程比較相關(guān),留待后面的文章分析。暫時(shí)只需要記住SystemServer是在這個(gè)位置啟動(dòng)的就好,其他的可以暫時(shí)忽略。
runSelectLoopMode
? ? ? ? 前面,我們已經(jīng)得到LocalServerLocket了,現(xiàn)在需要開(kāi)始監(jiān)聽(tīng)LocalServerScoket了:
????/** ?????*?Runs?the?zygote?process's?select?loop.?Accepts?new?connections?as ?????*?they?happen,?and?reads?commands?from?connections?one?spawn-request's ?????*?worth?at?a?time. ?????* ?????*?@throws?MethodAndArgsCaller?in?a?child?process?when?a?main()?should ?????*?be?executed. ?????*/ ????private?static?void?runSelectLoopMode()?throws?MethodAndArgsCaller?{ ????????ArrayListfds?=?new?ArrayList(); ????????ArrayListpeers?=?new?ArrayList(); ????????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)?{//index=0?為監(jiān)聽(tīng)端口 ????????????????ZygoteConnection?newPeer?=?acceptCommandPeer(); ????????????????peers.add(newPeer); ????????????????fds.add(newPeer.getFileDesciptor()); ????????????}?else?{ ????????????????boolean?done; ????????????????done?=?peers.get(index).runOnce(); ????????????????if?(done)?{ ????????????????????peers.remove(index); ????????????????????fds.remove(index); ????????????????} ????????????} ????????} ????}
? ? ? ? 其中,selectReadable函數(shù)為native函數(shù),實(shí)現(xiàn)了一個(gè)多連接的等待功能:
static?jint?com_android_internal_os_ZygoteInit_selectReadable?( ????????JNIEnv?*env,?jobject?clazz,?jobjectArray?fds) { ????if?(fds?==?NULL)?{ ????????jniThrowNullPointerException(env,?"fds?==?null"); ????????return?-1; ????} ????jsize?length?=?env->GetArrayLength(fds); ????fd_set?fdset;//fdset為連接集合 ????if?(env->ExceptionOccurred()?!=?NULL)?{ ????????return?-1; ????} ????FD_ZERO(&fdset);//清空f(shuō)dset ????int?nfds?=?0; ????for?(jsize?i?=?0;?i?<?length;?i++)?{//把所有的連接保存到fdset中 ????????jobject?fdObj?=?env->GetObjectArrayElement(fds,?i); ????????if??(env->ExceptionOccurred()?!=?NULL)?{ ????????????return?-1; ????????} ????????if?(fdObj?==?NULL)?{ ????????????continue; ????????} ????????int?fd?=?jniGetFDFromFileDescriptor(env,?fdObj); ????????if??(env->ExceptionOccurred()?!=?NULL)?{ ????????????return?-1; ????????} ????????FD_SET(fd,?&fdset);//保存fd到fdset中 ????????if?(fd?>=?nfds)?{ ????????????nfds?=?fd?+?1; ????????} ????} ????int?err; ????do?{ ????????err?=?select?(nfds,?&fdset,?NULL,?NULL,?NULL);//fdset中任何一個(gè)連接有數(shù)據(jù)可讀,則返回該連接在fdset的序號(hào),否則等待 ????}?while?(err?<?0?&&?errno?==?EINTR); ????if?(err?<?0)?{ ????????jniThrowIOException(env,?errno); ????????return?-1; ????} ????for?(jsize?i?=?0;?i?<?length;?i++)?{ ????????jobject?fdObj?=?env->GetObjectArrayElement(fds,?i); ????????if??(env->ExceptionOccurred()?!=?NULL)?{ ????????????return?-1; ????????} ????????if?(fdObj?==?NULL)?{ ????????????continue; ????????} ????????int?fd?=?jniGetFDFromFileDescriptor(env,?fdObj); ????????if??(env->ExceptionOccurred()?!=?NULL)?{ ????????????return?-1; ????????} ????????if?(FD_ISSET(fd,?&fdset))?{ ????????????return?(jint)i;//返回有數(shù)據(jù)可讀到連接的序號(hào) ????????} ????} ????return?-1; }
? ? ? ? 有數(shù)據(jù)可讀的連接的序號(hào)為0,則為監(jiān)聽(tīng)端口,應(yīng)該accept這個(gè)連接:
????/** ?????*?Waits?for?and?accepts?a?single?command?connection.?Throws ?????*?RuntimeException?on?failure. ?????*/ ????private?static?ZygoteConnection?acceptCommandPeer()?{ ????????try?{ ????????????return?new?ZygoteConnection(sServerSocket.accept()); ????????}?catch?(IOException?ex)?{ ????????????throw?new?RuntimeException( ????????????????????"IOException?during?accept()",?ex); ????????} ????}
? ? ? ? 有數(shù)據(jù)可讀的連接的序號(hào)不為0,則說(shuō)明有fork指令過(guò)來(lái),執(zhí)行ZygoteConnection.runOnce(),并視需要移除這個(gè)連接。這個(gè)過(guò)程和App進(jìn)程的啟動(dòng)相關(guān),之后的文章會(huì)做進(jìn)一步分析。 總結(jié) Zygote進(jìn)程由Init進(jìn)程啟動(dòng)Zygote進(jìn)程的實(shí)體為app_processZygote初始化Android虛擬機(jī)以后,開(kāi)始執(zhí)行Java類ZygoteInitZygoteInit會(huì)啟動(dòng)SystemServerZygoteInit會(huì)監(jiān)聽(tīng)domain socket “dev/socket/zygote”,以執(zhí)行framework層指定的fork操作