一 目的java
zygote,是Android搞出來的一個東西。網上講這個的也很是多。第一次看到這個名字我就挺鬱悶,想幹嗎這是?Linux下名字都取得挺通俗易懂,深得人心。zygote?不就想模仿Linux下的fork嗎?我的以爲Google取名字挺怪,包括Google自己。linux
無論怎樣,Zygote依然是Android系統的核心,zygote是受精卵的意思,能夠認爲是Android framework你們族的祖先!咱們本節的目的是描述下zygote的前因後果,順便揭露下它的短處,之後你們能夠對症下藥,變異一個更加優良的品種。android
二 Zygotec++
zygote自己是一個應用層的程序,和驅動,內核模塊之類的沒點關係。這下你們放心點了吧?zygote的啓動由linux的祖先init啓動。這個在init分析中提過。這裏就不說了。windows
zygote,ps中看到的進程名叫zygote,其最初的名字是app_process,經過直接調用pctrl把名字給改爲了」zygote」。不過不影響咱們分析。數組
zygote的代碼在framework/base/cmds/app_process/App_main.cpp中。咱們一步步來看。app
既然是應用程序,直接看main咯。函數
[---->main]ui
int main(int argc, const char* const argv[])線程
{
//參數很重要啊,還記得init分析嗎?
//恩,這幾個參數就是:(必定要記住咱們的情景分析方法!)
//zygote /system/bin/app_process
//-Xzygote /system/bin --zygote --start-system-server
// 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;
//AppRuntime是個什麼玩意兒?addVmArguments?好像和虛擬機有點關係喔
int i = runtime.addVmArguments(argc, argv);
[--->AppRuntime]
class AppRuntime : public AndroidRuntime
從AndroidRuntime中派生而來,是和dalvik交互的一個方便類,這裏先不說了。
[---->main]
...
int i = runtime.addVmArguments(argc, argv);
....
if (i < argc) {
arg = argv[i++];
if (0 == strcmp("--zygote", arg)) {
bool startSystemServer = (i < argc) ?
strcmp(argv[i], "--start-system-server") == 0 : false;
//廢話,根據咱們的參數,startSystemServer=true
setArgv0(argv0, "zygote");
//更名字,不知道windows下的怎麼改、linux下的能夠用pctrl系統調用
set_process_name("zygote");
//start?記住咱們的參數
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer);
}
} else {
return 10;
}
FT,app_main仍是很簡單的,可是runtime.start看起來不簡單啊,傳進去的那個參數
「com.android.internal.os.ZygoteInit「挺像java類的命名規則。
好了,代碼進入到runtime.start("com.android.internal.os.ZygoteInit",true)了。source insight直接進去看看。代碼在framework/base/core/jni/AppRuntime.cpp中。
[--->void AndroidRuntime::start()]
void AndroidRuntime::start(const char* className, const bool startSystemServer)
{
LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
char* slashClassName = NULL;
char* cp;
JNIEnv* env;
//linux下signal的處理,沒什麼好說的
blockSigpipe();
//設置環境變量ANDROID_ROOT爲/system
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
setenv("ANDROID_ROOT", rootDir, 1);
}
/*啓動虛擬機*/
if (startVm(&mJavaVM, &env) != 0)
goto bail;
啓動虛擬機,和JAVA有關係了吧?Android最重要的sdk都是java,那虛擬機這部分確定要進去看看的。
[--->int AndroidRuntime::startVm()]
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
//唉,大部分都是設置java虛擬機的啓動參數。不過有幾個參數比較重要。
//checkjni,可能沒使用過jni的一生都不能體會
//說白了,就是咱們在C++層調用jni函數的時候,會對參數或者什麼的進行檢查
//要是不合法的話,直接把虛擬機exit!第一個影響速度,第二個是影響程序。
//這個只做爲開發時候使用。
property_get("dalvik.vm.checkjni", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
checkJni = true;
} else if (strcmp(propBuf, "false") != 0) {
/* property is neither true nor false; fall back on kernel parameter */
property_get("ro.kernel.android.checkjni", propBuf, "");
if (propBuf[0] == '1') {
checkJni = true;
}
}
//設置虛擬機最大heapsize,纔給16M,彷佛有點少,尤爲是在作圖片操做的
//隨便一個幾百兆的圖片就會把虛擬機搞死。
strcpy(heapsizeOptsBuf, "-Xmx");
property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
LOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
/* extended JNI checking */
opt.optionString = "-Xcheck:jni";
mOptions.add(opt);
/* set a cap on JNI global references */
opt.optionString = "-Xjnigreflimit:2000";
mOptions.add(opt);
}
//具體dalvik虛擬機有哪些參數,能夠參考Dalvik的說明
//反正調用了下面這個函數,虛擬機就按您指定的參數啓動了。
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
LOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
result = 0;
bail:
free(stackTraceFile);
return result;
}
OK,虛擬機起來了,看看咱們在runtime.start中還要作什麼
[--->void AndroidRuntime::start()]
if (startVm(&mJavaVM, &env) != 0)
...
//startReg?
if (startReg(env) < 0) {
goto bail;
}
看看去。
[--->int AndroidRuntime::startReg()]
爲什麼不把startReg改爲startRegister()。
int AndroidRuntime::startReg(JNIEnv* env)
{
//這個名字仍是很清楚的,設置建立線程的函數爲javaCreateThreadEtc
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
//JNI知識,本身去查JDK
env->PushLocalFrame(200);
//
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//搞笑,下面的註釋爲什麼不幹掉?
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
[---->static int register_jni_procs()]
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {//啥都沒幹,由傳進來的參數控制..浪費我時間。
return -1;
}
}
return 0;
}
回到以前的調用,
register_jni_procs(gRegJNI, NELEM(gRegJNI), env),它的參數gRegJNI是下面這個結構
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_debug_JNITest),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
...後面還有不少,好像是一些函數
};
隨便挑一個跟進去看看。
[--->int register_android_debug_JNITest]
int register_android_debug_JNITest(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "android/debug/JNITest",
gMethods, NELEM(gMethods));
}
其實就是註冊一些JAVA中native函數在C++層對應的實行函數。
因此說:
若是你能夠在這個地方加上你定製的東西。
好了,startReg完了,回到runtime.start。
[---->void AndroidRuntime::start]
if (startReg(env) < 0) {
goto bail;
}
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring startSystemServerStr;
//下面這些話,都是把c++的字符串轉成JAVA的字符串
//
stringClass = env->FindClass("java/lang/String");
//構造一個String數組,元素個數爲2
strArray = env->NewObjectArray(2, stringClass, NULL);
classNameStr = env->NewStringUTF(className);
env->SetObjectArrayElement(strArray, 0, classNameStr);
startSystemServerStr = env->NewStringUTF(startSystemServer ? "true" : "false");
env->SetObjectArrayElement(strArray, 1, startSystemServerStr);
//java應用程序不也有main函數嗎?上面的就是把C++傳進來的參數,變成java的參數
[
「com.android.internal.os.ZygoteInit」,
「true」
]
jclass startClass;
jmethodID startMeth;
//
startClass = env->FindClass(slashClassName);
// 下面這個JNI調用,就真正進入java層了
startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
//下面調用的就是com.android.internal.os.ZygoteInit類的main函數
//最後一個參數是true
env->CallStaticVoidMethod(startClass, startMeth, strArray);
bail:
free(slashClassName);
}