Android深入浅出之Zygote

本文详细介绍了Android系统中Zygote进程的启动过程及其核心作用。从Zygote的命名含义到其实现原理,包括虚拟机初始化、JNI注册等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 目的

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;

   //linuxsignal 的处理,没什么好说的

    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));

}

其实就是注册一些 JAVAnative 函数在 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);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值