Android深入淺出之Zygote[1]

Android深入淺出之Zygote

一 目的

zygote,是Android搞出來的一個東西。網上講這個的也非常多。第一次看到這個名字我就挺鬱悶,想幹嘛這是?Linux下名字都取得挺通俗易懂,深得人心。zygote?不就想模仿Linux下的fork嗎?個人覺得Google取名字挺怪,包括Google本身。

不管怎樣,Zygote依然是Android系統的核心,zygote是受精卵的意思,可以認爲是Android framework大家族的祖先!我們本節的目的是描述下zygote的來龍去脈,順便揭露下它的短處,以後大家可以對症下藥,變異一個更加優良的品種。

二 Zygote

zygote本身是一個應用層的程序,和驅動,內核模塊之類的沒點關係。這下大家放心點了吧?zygote的啓動由linux的祖先init啓動。這個在init分析中提過。這裏就不說了。

zygote,ps中看到的進程名叫zygote,其最初的名字是app_process,通過直接調用pctrl把名字給改成了”zygote”。不過不影響我們分析。

zygote的代碼在framework/base/cmds/app_process/App_main.cpp中。我們一步步來看。

既然是應用程序,直接看main咯。

[---->main]

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類的命名規則。

2.1 AppRuntime

好了,代碼進入到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);

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章