之前講到,init進(jìn)程會(huì)啟動(dòng)zygote進(jìn)程,那么zygote進(jìn)程會(huì)做些什么?而且目前為止仍然是運(yùn)行在C/C++層的程序,那么什么時(shí)候會(huì)進(jìn)入Java層呢?
源碼參考Android4.1.1,涉及文件有 App_main.cpp,AndroidRuntime.h,AndroidRuntime.cpp (framework文件夾下)
zygote是受精卵的意思。Android這樣起名字很明顯,說明zygote會(huì)分裂產(chǎn)生新的系統(tǒng)服務(wù)進(jìn)程,當(dāng)然和開發(fā)者最貼近的,是zygote會(huì)分裂產(chǎn)生應(yīng)用進(jìn)程,每一個(gè)APP要啟動(dòng),都要通知zygote,讓他分裂一個(gè)進(jìn)程給上層。所以在應(yīng)用開發(fā)的時(shí)候,如果出現(xiàn)某些錯(cuò)誤,也可能會(huì)定位到zygote這一層,說明分裂不成功(當(dāng)然,往往是因?yàn)樽约旱囊恍┛罩羔樖裁吹模?br> App_main.cpp的main函數(shù)(部分)
while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg;
} else if (strcmp(arg, "--zygote") == 0) {//判斷是否為zygote
zygote = true;
niceName = "zygote";//下行:若有參數(shù)"--start-system-server"
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {//若是應(yīng)用程序
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);//設(shè)置參數(shù)中指定的進(jìn)程名稱
}
runtime.mParentDir = parentDir;
if (zygote) {//若是zygote進(jìn)程
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
}
- 在while循環(huán)中,可以看到一個(gè)有意思的現(xiàn)象,就是zygote進(jìn)程的名字原本不叫zygote,是在這個(gè)時(shí)候改了名字。
- 關(guān)于argv數(shù)組,其實(shí)可以直接參考上一篇文章中給出的init.rc中的zygote配置信息:“--zygote --start-system-server”
- 在最后我們果然看到了一個(gè)runtime.start()函數(shù),一言不合就start。當(dāng)然可以看到它嘗試去開啟SystemServer
SystemServer是個(gè)了不起的系統(tǒng)進(jìn)程,它的責(zé)任就是管理其他的關(guān)鍵系統(tǒng)服務(wù),比如AMS
但是首先我們需要了解runtime,它源自一個(gè)AppRuntime類,而這個(gè)類的父類是AndroidRuntime(這個(gè)類定義在AndroidRuntime頭文件中).
繼承結(jié)構(gòu)圖如下:
- 從上面可以看到,其實(shí)runtime雖然是AppRuntime類型,但是其實(shí)調(diào)用的start函數(shù)是父類的函數(shù)。
AndroidRuntime.start():
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) { //大家快看啊,它創(chuàng)建了虛擬機(jī)
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) { //它在注冊jni函數(shù)
ALOGE("Unable to register all android natives\n");
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;
//熟悉JNI開發(fā)的同學(xué)估計(jì)很熟悉這些env->XXX()的函數(shù)調(diào)用
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);
//上面這一段的意思大概是,創(chuàng)建Java層的String數(shù)組對象,然后做一些賦值工作。
//比如數(shù)組第一個(gè)賦值為“com.android.internal.os.ZygoteInit”。
/*
* 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 {
//這是一個(gè)至關(guān)重要的步驟,因?yàn)樗@取了了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 {
//這是更加關(guān)鍵的一步,從c層調(diào)用調(diào)用Java層的方法。
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
總結(jié)一下:
- 創(chuàng)建VM-----startVm()
- 注冊JNI函數(shù)------startReg()
- 在C層做一些向Java層的賦值工作
- 獲取Java層的ZygoteInit.main方法id
- 調(diào)用main方法,進(jìn)入Java世界。
至此,Android如何從C層到Java層已經(jīng)講完了,其實(shí)就是通過JIN調(diào)用了Java層的main函數(shù)。但是需要注意的是,目前zygote還是沒有啟動(dòng)那個(gè)吊炸天的SystemSever進(jìn)程,雖然前面嚷嚷了半天要啟動(dòng)它,但是,顯然還沒有