當(dāng)前位置:首頁 > 芯聞號 > 充電吧
[導(dǎo)讀]? ? ? ? Zygote意為“受精卵”,即所有的Android進程都是由其“發(fā)育”而來的意思。本人試著把啃代碼學(xué)到的內(nèi)容整理出來,希望會對自己以后有用。Init? ? ? ? Init進程是Lin

? ? ? ? Zygote意為“受精卵”,即所有的Android進程都是由其“發(fā)育”而來的意思。本人試著把啃代碼學(xué)到的內(nèi)容整理出來,希望會對自己以后有用。

Init

? ? ? ? Init進程是Linux系統(tǒng)上的第一個用戶進程,用戶為root,擁有系統(tǒng)中最高的權(quán)限。它會實現(xiàn)掛載文件系統(tǒng),并啟動ServiceManager/Zygote兩大進程,正式這兩大進程構(gòu)成了Android系統(tǒng)的基礎(chǔ)。

? ? ? ? 簡單來說,Init進程通過解析init.rc文件,然后執(zhí)行自己的工作,其中,Zygote進程相關(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實際上執(zhí)行的是/system/bin/app_process應(yīng)用程序,參數(shù)中包含了--zygote和--start-system-server。 另外,



????socket?zygote?stream?660?root?system

? ? ?屬性的配置,說明Init進程在啟動zygote進程時,會為zygote進程創(chuàng)建一個stream型的domain socket,并保存到ANDROID_SOCKET_zygote系統(tǒng)變量中。(對這個過程涉及到init進程的實現(xiàn),可以參考代碼system/core/init/init.c)


app_process ? ? ? ? Init進程啟動Zygote進程以后,代碼執(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進程啟動Zygote進程的時候,包含了--zygote參數(shù)和--start-system-server參數(shù),所以,現(xiàn)在zygote和startSystemServer都為true,所以接下來執(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并沒有重載start函數(shù),所以,目前會執(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主要做了三項工作: startVM啟動Android虛擬機,并呼叫onVMCreate函數(shù)。前面,我們有看到AppRuntime有重載onVMCreated函數(shù)(不過,對于app_process作為Zygote進程啟動的情況,不做任何處理就返回)startReg注冊需要的Native函數(shù),基本Android的每個模塊都有一些native實現(xiàn)需要和Java代碼關(guān)聯(lián)起來,事先注冊能夠提高性能,(另一種方案是第一次調(diào)用的時候查找實現(xiàn)函數(shù)并完成注冊)查找className指定的class的main函數(shù),并以options為參數(shù),調(diào)用main函數(shù)。這里不對代碼做解釋,用java寫過反射調(diào)用的人應(yīng)該基本能看懂。 ? ? ? ?runtime.start最后會調(diào)用ZygoteIni的.main函數(shù),參數(shù)為--start-system-server。 ? ? ???因為已經(jīng)啟動了java虛擬機,接下來可以執(zhí)行Java代碼了,所以,我們將進入下一個世界。 ZygoteInit ? ? ? ?ZygoteInit從類名看,從現(xiàn)在開始是真正的“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ù)完成了四項工作: registerZygoteSocketpreloadstartSystemServer,因為之前AndroidRuntime是以“start-system-server”為參數(shù)調(diào)用main函數(shù)的,所以這里會執(zhí)行startSystemServerrunSelectLoopMode,ZYGOTE_FORK_MODE常量恒定為false,所以會執(zhí)行runSelectLoopMode ? ? ? ? 再繼續(xù)分析前,先要做點鋪墊。Zygote進程的作用是為了fork出新的Android進程,那Zygote是如何得知它需要fork一個進程的呢? ? ? ? ? 先看一段“客戶端“的代碼(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進程進行fork用的,代碼略長,也沒有必要仔細(xì)分析,只要看明白一點即可: ? ? ? ? framework層會通過Unix domain socket連接到Zygote進程,并發(fā)送字符串型的參數(shù)。 registerZygoteSocket ? ? ? ? ?剛才有看到Process會通過domain socket連接到Zygote進程,那Zygote進程理所當(dāng)然的要監(jiān)聽這個socket端口了,這就是registerZygoteSocket函數(shù)要做的(或者說它做了一半):

?/**
?????*?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)境變量中,讀取一個int值作為文件描述父,創(chuàng)建文件描述符,為什么呢? ? ? ? ?如果還記得init.rc的配置到話,一切就可以解釋了:

????socket?zygote?stream?660?root?system

? ? ? ?init進程在處理這一行屬性時,會先在dev/socket下創(chuàng)建一個名為zygote的設(shè)備文件,然后打開這個文件,并把文件描述符保存到環(huán)境變量中。環(huán)境變量名的規(guī)則為"ANDROID_SOCKET_"+第一參數(shù)(這里為zygote)。所以,app_main就可以通過指定的環(huán)境變量來獲取這個文件描述符,并由此創(chuàng)建LocalServerSocket。 preload
? ? ? ? 因為所有的Android進程都是從Zygote進程fork出來的,而子進程會繼承Zygote的資源。換言之,如果Zygote進程持有了資源,所有android進程就都有了。所以,Zygote會預(yù)加載一些系統(tǒng)資源,以加速子進程的啟動速度(子進程以寫時復(fù)制的機制進行資源共享,所以不必?fù)?dān)心內(nèi)存占用問題。另外Android系統(tǒng)的啟動時間可能有大概40%的時間耗費在這個preload函數(shù)上,但是從整體上來說,這是利大于弊的)。

????static?void?preload()?{
????????preloadClasses();//加載java類
????????preloadResources();//加載icon,字串等資源
????}

startSystemServer ? ? ? Zygote進程啟動以后,會由Zygote進程fork出SystemServer,繼續(xù)啟動系統(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的啟動參數(shù),然后,調(diào)用Zygote.forkSysetmServer函數(shù),開始執(zhí)行fork操作。這一塊和SystemServer的啟動過程比較相關(guān),留待后面的文章分析。暫時只需要記住SystemServer是在這個位置啟動的就好,其他的可以暫時忽略。
runSelectLoopMode ? ? ? ? 前面,我們已經(jīng)得到LocalServerLocket了,現(xiàn)在需要開始監(jiān)聽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)聽端口
????????????????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ù),實現(xiàn)了一個多連接的等待功能:

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);//清空fdset

????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中任何一個連接有數(shù)據(jù)可讀,則返回該連接在fdset的序號,否則等待
????}?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ù)可讀到連接的序號
????????}
????}
????return?-1;
}

? ? ? ? 有數(shù)據(jù)可讀的連接的序號為0,則為監(jiān)聽端口,應(yīng)該accept這個連接:

????/**
?????*?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ù)可讀的連接的序號不為0,則說明有fork指令過來,執(zhí)行ZygoteConnection.runOnce(),并視需要移除這個連接。這個過程和App進程的啟動相關(guān),之后的文章會做進一步分析。 總結(jié) Zygote進程由Init進程啟動Zygote進程的實體為app_processZygote初始化Android虛擬機以后,開始執(zhí)行Java類ZygoteInitZygoteInit會啟動SystemServerZygoteInit會監(jiān)聽domain socket “dev/socket/zygote”,以執(zhí)行framework層指定的fork操作

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉