Android 8.1 源码_启动篇(二) -- 深入研究 zygote (5)

我们回到AndroidRuntime的start函数。初始化JVM后,接下来就会调用startReg函数。

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... ... /* 01. 创建Java虚拟机*/ /* * Register android functions. */ if (startReg(env) < 0) { // 注册JNI函数 ALOGE("Unable to register all android natives\n"); return; } ... ... }

startReg首先是设置了Android创建线程的处理函数,然后创建了一个200容量的局部引用作用域,用于确保不会出现OutOfMemoryException,最后就是调用register_jni_procs进行JNI注册。

我们跟进startReg():

/* * Register android native functions with the VM. */ /*static*/ int AndroidRuntime::startReg(JNIEnv* env) { ATRACE_NAME("RegisterAndroidNatives"); /* * This hook causes all future threads created in this process to be * attached to the JavaVM. (This needs to go away in favor of JNI * Attach calls.) */ // 定义Android创建线程的func:javaCreateThreadEtc,这个函数内部是通过Linux的clone来创建线程的 androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); ALOGV("--- registering native functions ---\n"); /* * Every "register" function calls one or more things that return * a local reference (e.g. FindClass). Because we haven't really * started the VM yet, they're all getting stored in the base frame * and never released. Use Push/Pop to manage the storage. */ env->PushLocalFrame(200); // 创建一个200容量的局部引用作用域,这个局部引用其实就是局部变量 if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { // 注册JNI函数 env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); // 释放局部引用作用域 //createJavaThread("fubar", quickTest, (void*) "hello"); return 0; }

从上述代码可以看出,startReg函数中主要是通过register_jni_procs来注册JNI函数。其中,gRegJNI是一个全局数组,该数组的定义如下:

static const RegJNIRec gRegJNI[] = { // 里面就是一堆的函数指针 REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit), REG_JNI(register_android_os_SystemClock), REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), ... ... };

我们挑一个register_com_android_internal_os_ZygoteInit_nativeZygoteInit,这实际上是自定义JNI函数并进行动态注册的标准写法,
内部是调用JNI的RegisterNatives,这样注册后,Java类ZygoteInit的native方法nativeZygoteInit就会调用com_android_internal_os_ZygoteInit_nativeZygoteInit函数。

int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env) { const JNINativeMethod methods[] = { { "nativeZygoteInit", "()V", (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit }, }; return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit", methods, NELEM(methods)); }

REG_JNI对应的宏定义及RegJNIRec结构体的定义为:

#ifdef NDEBUG #define REG_JNI(name) { name } struct RegJNIRec { int (*mProc)(JNIEnv*); }; #else #define REG_JNI(name) { name, #name } struct RegJNIRec { int (*mProc)(JNIEnv*); const char* mName; }; #endif

根据宏定义可以看出,宏REG_JNI将得到函数名;定义RegJNIRec数组时,函数名被赋值给RegJNIRec结构体,于是每个函数名被强行转换为函数指针。
因此,register_jni_procs的参数就是一个函数指针数组,数组的大小和JNIEnv。

我们来跟进一下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) { // 调用mProc #ifndef NDEBUG ALOGD("----------!!! %s failed to load\n", array[i].mName); #endif return -1; } } return 0; }

结合前面的分析,容易知道register_jni_procs函数,实际上就是调用函数指针(mProc)对应的函数,以进行实际的JNI函数注册。

反射启动ZygoteInit

继续分析AndroidRuntime.cpp的start函数:

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... ... /* 01. 创建Java虚拟机*/ /* 02. 注册JNI函数 */ /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ // 替换string为实际路径 // 例如:将 "com.android.internal.os.ZygoteInit" 替换为 "com/android/internal/os/ZygoteInit" char* slashClassName = toSlashClassName(className != NULL ? className : ""); jclass startClass = env->FindClass(slashClassName); // 找到class文件 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"); // 通过反射找到ZygoteInit的main函数 if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); // 调用ZygoteInit的main函数 ... ... } } 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"); }

可以看到,在AndroidRuntime的最后,将通过反射调用ZygoteInit的main函数。至此,zygote进程进入了java世界

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygdyw.html