• 安卓高手之路之ClassLoader(二)


    因为ClassLoader一定与虚拟机的启动有关系,那么必须从Zygote的启动开始看代码。下面就分析一下这些代码,行数不多:

    Cpp代码  收藏代码
    1. int main(int argc, const char* const argv[])  
    2. {  
    3.     // These are global variables in ProcessState.cpp  
    4.     //ProcessState.cpp中可能要用到一些main函数。  
    5.     mArgC = argc;  
    6.     mArgV = argv;  
    7.   
    8.     mArgLen = 0;  
    9.     for (int i=0; i<argc; i++) {  
    10.         mArgLen += strlen(argv[i]) + 1;  
    11.     }  
    12.     mArgLen--;  
    13.   
    14.     AppRuntime runtime;  
    15.     const char* argv0 = argv[0];  
    16.   
    17.     // Process command line arguments  
    18.     // ignore argv[0]  
    19.     argc--;  
    20.     argv++;  
    21.   
    22.     // Everything up to '--' or first non '-' arg goes to the vm  
    23.   
    24.     int i = runtime.addVmArguments(argc, argv);  
    25.   
    26.     // Parse runtime arguments.  Stop at first unrecognized option.  
    27.     bool zygote = false;  
    28.     bool startSystemServer = false;  
    29.     bool application = false;  
    30.     const char* parentDir = NULL;  
    31.     const char* niceName = NULL;  
    32.     const char* className = NULL;  
    33.     while (i < argc) {  
    34.         const char* arg = argv[i++];  
    35.         if (!parentDir) {  
    36.             parentDir = arg;  
    37.         } else if (strcmp(arg, "--zygote") == 0) {  
    38.             zygote = true;  
    39.             niceName = "zygote";  
    40.         } else if (strcmp(arg, "--start-system-server") == 0) {  
    41.             startSystemServer = true;  
    42.         } else if (strcmp(arg, "--application") == 0) {  
    43.             application = true;  
    44.         } else if (strncmp(arg, "--nice-name=", 12) == 0) {  
    45.             niceName = arg + 12;  
    46.         } else {  
    47.             className = arg;  
    48.             break;  
    49.         }  
    50.     }  
    51.   
    52.     if (niceName && *niceName) {  
    53.         setArgv0(argv0, niceName);  
    54.         set_process_name(niceName);  
    55.     }  
    56.   
    57.     runtime.mParentDir = parentDir;  
    58.   
    59.     if (zygote) {  
    60.         runtime.start("com.android.internal.os.ZygoteInit",  
    61.                 startSystemServer ? "start-system-server" : "");  
    62.     } else if (className) {  
    63.         // Remainder of args get passed to startup class main()  
    64.         runtime.mClassName = className;  
    65.         runtime.mArgC = argc - i;  
    66.         runtime.mArgV = argv + i;  
    67.         runtime.start("com.android.internal.os.RuntimeInit",  
    68.                 application ? "application" : "tool");  
    69.     } else {  
    70.         fprintf(stderr, "Error: no class name or --zygote supplied. ");  
    71.         app_usage();  
    72.         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");  
    73.         return 10;  
    74.     }  
    75. }  

     分析完之后发现如下参数规律:

        1. argv[0]:用这个修改了进程名称。

        2. 虚拟机参数:前面的选项参数都是以“-”打头。被放入了runtime。这些参数被称为是虚拟机参数。

        3.“--”打头的参数是zygote参数。有如下几种,排列顺序如下:

              -runtimearg[0]

             -runtimearg[1]

             。。。。

              parentDir //这个也是runtime使用的,也就是VM使用的。

              className//这个也是runtime使用的,也就是VM使用的。

              --zygote

              --start-system-server

              --application

              --nice-name=

    然后,如果是zygote,那么进入下面这句话

        

    C代码  收藏代码
    1. runtime.start("com.android.internal.os.ZygoteInit",  
    2.              startSystemServer ? "start-system-server" : "");  

    如果有类名,那么进入下面这句话:

       

    C代码  收藏代码
    1. runtime.mClassName = className;  
    2.    runtime.mArgC = argc - i; //className,包括className以后的参数个数。  
    3.  runtime.mArgV = argv + i; //截止到className的参数个数  
    4. runtime.start("com.android.internal.os.RuntimeInit",  
    5.               application ? "application" : "tool");  

    第一部分:那么开机第一次启动的就一定是,

      

    Java代码  收藏代码
    1. runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");  

     其中startSystemServer 由init.rc指定,在目录android40systemcore ootdir中的init.rc.

       service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        class main
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart media
        onrestart restart netd

    第二部分:从ActivityManagerService可以看出,--application并没有指定,这句话也就相当于:

    C代码  收藏代码
    1. runtime.start("com.android.internal.os.RuntimeInit", "tool");  

     现在代码分成了两部分。

    那么先分析第一部分。

    那么zygote启动到底配置了那些参数呢,我们就看一看:

       service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

    根据上面说的参数序列图,可以看出。

       runtime.mParentDir  为/system/bin

       runtime的一个arg为-Xzygote

    那么这个这个start函数就变成:

    C代码  收藏代码
    1. runtime.start("com.android.internal.os.ZygoteInit",  "start-system-server");  

    代码进入到base/core/jni目录的AndroidRuntime.cpp里面。这个函数还不算长,就直接贴出来看一下,注意注释,由此可以看出这个就是启动虚拟机的代码所在啊。那么既然Zygote进程也是这么启动的,那么我们就有理由断定Zygote也是个Dalvik虚拟机!事情是不是这样呢?那么就带着这个疑问去分析一下:

    Cpp代码  收藏代码
    1. /* 
    2.  * Start the Android runtime.  This involves starting the virtual machine 
    3.  * and calling the "static void main(String[] args)" method in the class 
    4.  * named by "className". 
    5.  * 
    6.  * Passes the main function two arguments, the class name and the specified 
    7.  * options string. 
    8.  */  
    9. void AndroidRuntime::start(const char* className, const char* options)  
    10. {  
    11.     LOGD(" >>>>>> AndroidRuntime START %s <<<<<< ",  
    12.             className != NULL ? className : "(unknown)");  
    13.   
    14.     blockSigpipe();  
    15.   
    16.     /* 
    17.      * 'startSystemServer == true' means runtime is obsolete and not run from 
    18.      * init.rc anymore, so we print out the boot start event here. 
    19.      */  
    20.     if (strcmp(options, "start-system-server") == 0) {  
    21.         /* track our progress through the boot sequence */  
    22.         const int LOG_BOOT_PROGRESS_START = 3000;  
    23.         LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  
    24.                        ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));  
    25.     }  
    26.   
    27.     const char* rootDir = getenv("ANDROID_ROOT");  
    28.     if (rootDir == NULL) {  
    29.         rootDir = "/system";  
    30.         if (!hasDir("/system")) {  
    31.             LOG_FATAL("No root directory specified, and /android does not exist.");  
    32.             return;  
    33.         }  
    34.         setenv("ANDROID_ROOT", rootDir, 1);  
    35.     }  
    36.   
    37.     //const char* kernelHack = getenv("LD_ASSUME_KERNEL");  
    38.     //LOGD("Found LD_ASSUME_KERNEL='%s' ", kernelHack);  
    39.   
    40.     /* start the virtual machine */  
    41.     JNIEnv* env;  
    42.     if (startVm(&mJavaVM, &env) != 0) {  
    43.         return;  
    44.     }  
    45.     onVmCreated(env);  
    46.   
    47.     /* 
    48.      * Register android functions. 
    49.      */  
    50.     if (startReg(env) < 0) {  
    51.         LOGE("Unable to register all android natives ");  
    52.         return;  
    53.     }  
    54.   
    55.     /* 
    56.      * We want to call main() with a String array with arguments in it. 
    57.      * At present we have two arguments, the class name and an option string. 
    58.      * Create an array to hold them. 
    59.      */  
    60.     jclass stringClass;  
    61.     jobjectArray strArray;  
    62.     jstring classNameStr;  
    63.     jstring optionsStr;  
    64.   
    65.     stringClass = env->FindClass("java/lang/String");  
    66.     assert(stringClass != NULL);  
    67.     strArray = env->NewObjectArray(2, stringClass, NULL);  
    68.     assert(strArray != NULL);  
    69.     classNameStr = env->NewStringUTF(className);  
    70.     assert(classNameStr != NULL);  
    71.     env->SetObjectArrayElement(strArray, 0, classNameStr);  
    72.     optionsStr = env->NewStringUTF(options);  
    73.     env->SetObjectArrayElement(strArray, 1, optionsStr);  
    74.   
    75.     /* 
    76.      * Start VM.  This thread becomes the main thread of the VM, and will 
    77.      * not return until the VM exits. 
    78.      */  
    79.     char* slashClassName = toSlashClassName(className);  
    80.     jclass startClass = env->FindClass(slashClassName);  
    81.     if (startClass == NULL) {  
    82.         LOGE("JavaVM unable to locate class '%s' ", slashClassName);  
    83.         /* keep going */  
    84.     } else {  
    85.         jmethodID startMeth = env->GetStaticMethodID(startClass, "main",  
    86.             "([Ljava/lang/String;)V");  
    87.         if (startMeth == NULL) {  
    88.             LOGE("JavaVM unable to find main() in '%s' ", className);  
    89.             /* keep going */  
    90.         } else {  
    91.             env->CallStaticVoidMethod(startClass, startMeth, strArray);  
    92.   
    93. #if 0  
    94.             if (env->ExceptionCheck())  
    95.                 threadExitUncaughtException(env);  
    96. #endif  
    97.         }  
    98.     }  
    99.     free(slashClassName);  
    100.   
    101.     LOGD("Shutting down VM ");  
    102.     if (mJavaVM->DetachCurrentThread() != JNI_OK)  
    103.         LOGW("Warning: unable to detach main thread ");  
    104.     if (mJavaVM->DestroyJavaVM() != 0)  
    105.         LOGW("Warning: VM did not shut down cleanly ");  
    106. }  

    linux的POSIX (Portable Operating System Interface of Unix)我不懂。但是从直观上看,可能是一种禁止打断进程的方法:

    Cpp代码  收藏代码
    1. LOGD(" >>>>>> AndroidRuntime START %s <<<<<< ",  
    2.         className != NULL ? className : "(unknown)");  
    3.   
    4. blockSigpipe();  

     下面这句话毫无意义,就是打印log

      

    Cpp代码  收藏代码
    1. if (strcmp(options, "start-system-server") == 0) {  
    2.         /* track our progress through the boot sequence */  
    3.         const int LOG_BOOT_PROGRESS_START = 3000;  
    4.         LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  
    5.                        ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));  
    6.     }  

     下面这句话定义androidroot的目录

      

    Java代码  收藏代码
    1. const char* rootDir = getenv("ANDROID_ROOT");  
    2.  if (rootDir == NULL) {  
    3.      rootDir = "/system";  
    4.      if (!hasDir("/system")) {  
    5.          LOG_FATAL("No root directory specified, and /android does not exist.");  
    6.          return;  
    7.      }  
    8.      setenv("ANDROID_ROOT", rootDir, 1);  
    9.  }  

     对照init.rc可以知道,就是/system

    Python代码  收藏代码
    1. # setup the global environment  
    2.     export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin  
    3.     export LD_LIBRARY_PATH /vendor/lib:/system/lib  
    4.     export ANDROID_BOOTLOGO 1  
    5.     export ANDROID_ROOT /system  
    6.     export ANDROID_ASSETS /system/app  
    7.     export ANDROID_DATA /data  
    8.     export ASEC_MOUNTPOINT /mnt/asec  
    9.     export LOOP_MOUNTPOINT /mnt/obb  
    10.     export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar  

    主要是下面这两句话

    Java代码  收藏代码
    1. /* start the virtual machine */  
    2.   JNIEnv* env;  
    3.   if (startVm(&mJavaVM, &env) != 0) {  
    4.       return;  
    5.   }  
    6.   onVmCreated(env);  
    7.   
    8.   /* 
    9.    * Register android functions. 
    10.    */  
    11.   if (startReg(env) < 0) {  
    12.       LOGE("Unable to register all android natives ");  
    13.       return;  
    14.   }  

     一个启动虚拟机,一个启动注册安卓本地方法。虚拟机的启动流程,最终调用的是

    JNI_CreateJavaVM 在framework/base/core/jni/AndroidRuntime.cpp下。JNI_CreateJavaVM 调用的是:

     然后调用dalvik/vm/Jni.cpp的JNI_CreateJavaVM 方法:

    Cpp代码  收藏代码
    1. jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {  
    2.     const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;  
    3.     if (args->version < JNI_VERSION_1_2) {  
    4.         return JNI_EVERSION;  
    5.     }  
    6.   
    7.     // TODO: don't allow creation of multiple VMs -- one per customer for now  
    8.   
    9.     /* zero globals; not strictly necessary the first time a VM is started */  
    10.     memset(&gDvm, 0, sizeof(gDvm));  
    11.   
    12.     /* 
    13.      * Set up structures for JNIEnv and VM. 
    14.      */  
    15.     JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));  
    16.     memset(pVM, 0, sizeof(JavaVMExt));  
    17.     pVM->funcTable = &gInvokeInterface;  
    18.     pVM->envList = NULL;  
    19.     dvmInitMutex(&pVM->envListLock);  
    20.   
    21.     UniquePtr<const char*[]> argv(new const char*[args->nOptions]);  
    22.     memset(argv.get(), 0, sizeof(char*) * (args->nOptions));  
    23.   
    24.     /* 
    25.      * Convert JNI args to argv. 
    26.      * 
    27.      * We have to pull out vfprintf/exit/abort, because they use the 
    28.      * "extraInfo" field to pass function pointer "hooks" in.  We also 
    29.      * look for the -Xcheck:jni stuff here. 
    30.      */  
    31.     int argc = 0;  
    32.     for (int i = 0; i < args->nOptions; i++) {  
    33.         const char* optStr = args->options[i].optionString;  
    34.         if (optStr == NULL) {  
    35.             dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL ", i);  
    36.             return JNI_ERR;  
    37.         } else if (strcmp(optStr, "vfprintf") == 0) {  
    38.             gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;  
    39.         } else if (strcmp(optStr, "exit") == 0) {  
    40.             gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;  
    41.         } else if (strcmp(optStr, "abort") == 0) {  
    42.             gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;  
    43.         } else if (strcmp(optStr, "sensitiveThread") == 0) {  
    44.             gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;  
    45.         } else if (strcmp(optStr, "-Xcheck:jni") == 0) {  
    46.             gDvmJni.useCheckJni = true;  
    47.         } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {  
    48.             char* jniOpts = strdup(optStr + 10);  
    49.             size_t jniOptCount = 1;  
    50.             for (char* p = jniOpts; *p != 0; ++p) {  
    51.                 if (*p == ',') {  
    52.                     ++jniOptCount;  
    53.                     *p = 0;  
    54.                 }  
    55.             }  
    56.             char* jniOpt = jniOpts;  
    57.             for (size_t i = 0; i < jniOptCount; ++i) {  
    58.                 if (strcmp(jniOpt, "warnonly") == 0) {  
    59.                     gDvmJni.warnOnly = true;  
    60.                 } else if (strcmp(jniOpt, "forcecopy") == 0) {  
    61.                     gDvmJni.forceCopy = true;  
    62.                 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {  
    63.                     gDvmJni.logThirdPartyJni = true;  
    64.                 } else {  
    65.                     dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s' ",  
    66.                             jniOpt);  
    67.                     return JNI_ERR;  
    68.                 }  
    69.                 jniOpt += strlen(jniOpt) + 1;  
    70.             }  
    71.             free(jniOpts);  
    72.         } else {  
    73.             /* regular option */  
    74.             argv[argc++] = optStr;  
    75.         }  
    76.     }  
    77.   
    78.     if (gDvmJni.useCheckJni) {  
    79.         dvmUseCheckedJniVm(pVM);  
    80.     }  
    81.   
    82.     if (gDvmJni.jniVm != NULL) {  
    83.         dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process ");  
    84.         return JNI_ERR;  
    85.     }  
    86.     gDvmJni.jniVm = (JavaVM*) pVM;  
    87.   
    88.     /* 
    89.      * Create a JNIEnv for the main thread.  We need to have something set up 
    90.      * here because some of the class initialization we do when starting 
    91.      * up the VM will call into native code. 
    92.      */  
    93.     JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);  
    94.   
    95.     /* Initialize VM. */  
    96.     gDvm.initializing = true;  
    97.     std::string status =  
    98.             dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);  
    99.     gDvm.initializing = false;  
    100.   
    101.     if (!status.empty()) {  
    102.         free(pEnv);  
    103.         free(pVM);  
    104.         LOGW("CreateJavaVM failed: %s", status.c_str());  
    105.         return JNI_ERR;  
    106.     }  
    107.   
    108.     /* 
    109.      * Success!  Return stuff to caller. 
    110.      */  
    111.     dvmChangeStatus(NULL, THREAD_NATIVE);  
    112.     *p_env = (JNIEnv*) pEnv;  
    113.     *p_vm = (JavaVM*) pVM;  
    114.     LOGV("CreateJavaVM succeeded");  
    115.     return JNI_OK;  
    116. }  

      然后调用Jni.cpp中的

    Java代码  收藏代码
    1. /* 
    2.  * Create a new JNIEnv struct and add it to the VM's list. 
    3.  * 
    4.  * "self" will be NULL for the main thread, since the VM hasn't started 
    5.  * yet; the value will be filled in later. 
    6.  */  
    7. JNIEnv* dvmCreateJNIEnv(Thread* self) {  
    8.     JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;  
    9.   
    10.     //if (self != NULL)  
    11.     //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);  
    12.   
    13.     assert(vm != NULL);  
    14.   
    15.     JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));  
    16.     newEnv->funcTable = &gNativeInterface;  
    17.     if (self != NULL) {  
    18.         dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);  
    19.         assert(newEnv->envThreadId != 0);  
    20.     } else {  
    21.         /* make it obvious if we fail to initialize these later */  
    22.         newEnv->envThreadId = 0x77777775;  
    23.         newEnv->self = (Thread*) 0x77777779;  
    24.     }  
    25.     if (gDvmJni.useCheckJni) {  
    26.         dvmUseCheckedJniEnv(newEnv);  
    27.     }  
    28.   
    29.     ScopedPthreadMutexLock lock(&vm->envListLock);  
    30.   
    31.     /* insert at head of list */  
    32.     newEnv->next = vm->envList;  
    33.     assert(newEnv->prev == NULL);  
    34.     if (vm->envList == NULL) {  
    35.         // rare, but possible  
    36.         vm->envList = newEnv;  
    37.     } else {  
    38.         vm->envList->prev = newEnv;  
    39.     }  
    40.     vm->envList = newEnv;  
    41.   
    42.     //if (self != NULL)  
    43.     //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);  
    44.     return (JNIEnv*) newEnv;  
    45. }  

       好吧,这些全是些乱七八糟的东西。真正启动的是这句话,Jni.cpp中:

      

    Java代码  收藏代码
    1. std::string status =  
    2.            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);  

     在Dalvik/vm/Init.cpp中

    Cpp代码  收藏代码
    1. *  
    2.  * VM initialization.  Pass in any options provided on the command line.  
    3.  * Do not pass in the class name or the options for the class.  
    4.  *  
    5.  * Returns 0 on success.  
    6.  */  
    7. std::string dvmStartup(int argc, const char* const argv[],  
    8.         bool ignoreUnrecognized, JNIEnv* pEnv)  
    9. {  
    10.     ScopedShutdown scopedShutdown;  
    11.   
    12.     assert(gDvm.initializing);  
    13.   
    14.     LOGV("VM init args (%d):", argc);  
    15.     for (int i = 0; i < argc; i++) {  
    16.         LOGV("  %d: '%s'", i, argv[i]);  
    17.     }  
    18.     setCommandLineDefaults();  
    19.   
    20.     /* 
    21.      * Process the option flags (if any). 
    22.      */  
    23.     int cc = processOptions(argc, argv, ignoreUnrecognized);  
    24.     if (cc != 0) {  
    25.         if (cc < 0) {  
    26.             dvmFprintf(stderr, " ");  
    27.             usage("dalvikvm");  
    28.         }  
    29.         return "syntax error";  
    30.     }  
    31.   
    32. #if WITH_EXTRA_GC_CHECKS > 1  
    33.     /* only "portable" interp has the extra goodies */  
    34.     if (gDvm.executionMode != kExecutionModeInterpPortable) {  
    35.         LOGI("Switching to 'portable' interpreter for GC checks");  
    36.         gDvm.executionMode = kExecutionModeInterpPortable;  
    37.     }  
    38. #endif  
    39.   
    40.     /* Configure group scheduling capabilities */  
    41.     if (!access("/dev/cpuctl/tasks", F_OK)) {  
    42.         LOGV("Using kernel group scheduling");  
    43.         gDvm.kernelGroupScheduling = 1;  
    44.     } else {  
    45.         LOGV("Using kernel scheduler policies");  
    46.     }  
    47.   
    48.     /* configure signal handling */  
    49.     if (!gDvm.reduceSignals)  
    50.         blockSignals();  
    51.   
    52.     /* verify system page size */  
    53.     if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) {  
    54.         return StringPrintf("expected page size %d, got %d",  
    55.                 SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE));  
    56.     }  
    57.   
    58.     /* mterp setup */  
    59.     LOGV("Using executionMode %d", gDvm.executionMode);  
    60.     dvmCheckAsmConstants();  
    61.   
    62.     /* 
    63.      * Initialize components. 
    64.      */  
    65.     dvmQuasiAtomicsStartup();  
    66.     if (!dvmAllocTrackerStartup()) {  
    67.         return "dvmAllocTrackerStartup failed";  
    68.     }  
    69.     if (!dvmGcStartup()) {  
    70.         return "dvmGcStartup failed";  
    71.     }  
    72.     if (!dvmThreadStartup()) {  
    73.         return "dvmThreadStartup failed";  
    74.     }  
    75.     if (!dvmInlineNativeStartup()) {  
    76.         return "dvmInlineNativeStartup";  
    77.     }  
    78.     if (!dvmRegisterMapStartup()) {  
    79.         return "dvmRegisterMapStartup failed";  
    80.     }  
    81.     if (!dvmInstanceofStartup()) {  
    82.         return "dvmInstanceofStartup failed";  
    83.     }  
    84.     if (!dvmClassStartup()) {  
    85.         return "dvmClassStartup failed";  
    86.     }  
    87.   
    88.     /* 
    89.      * At this point, the system is guaranteed to be sufficiently 
    90.      * initialized that we can look up classes and class members. This 
    91.      * call populates the gDvm instance with all the class and member 
    92.      * references that the VM wants to use directly. 
    93.      */  
    94.     if (!dvmFindRequiredClassesAndMembers()) {  
    95.         return "dvmFindRequiredClassesAndMembers failed";  
    96.     }  
    97.   
    98.     if (!dvmStringInternStartup()) {  
    99.         return "dvmStringInternStartup failed";  
    100.     }  
    101.     if (!dvmNativeStartup()) {  
    102.         return "dvmNativeStartup failed";  
    103.     }  
    104.     if (!dvmInternalNativeStartup()) {  
    105.         return "dvmInternalNativeStartup failed";  
    106.     }  
    107.     if (!dvmJniStartup()) {  
    108.         return "dvmJniStartup failed";  
    109.     }  
    110.     if (!dvmProfilingStartup()) {  
    111.         return "dvmProfilingStartup failed";  
    112.     }  
    113.   
    114.     /* 
    115.      * Create a table of methods for which we will substitute an "inline" 
    116.      * version for performance. 
    117.      */  
    118.     if (!dvmCreateInlineSubsTable()) {  
    119.         return "dvmCreateInlineSubsTable failed";  
    120.     }  
    121.   
    122.     /* 
    123.      * Miscellaneous class library validation. 
    124.      */  
    125.     if (!dvmValidateBoxClasses()) {  
    126.         return "dvmValidateBoxClasses failed";  
    127.     }  
    128.   
    129.     /* 
    130.      * Do the last bits of Thread struct initialization we need to allow 
    131.      * JNI calls to work. 
    132.      */  
    133.     if (!dvmPrepMainForJni(pEnv)) {  
    134.         return "dvmPrepMainForJni failed";  
    135.     }  
    136.   
    137.     /* 
    138.      * Explicitly initialize java.lang.Class.  This doesn't happen 
    139.      * automatically because it's allocated specially (it's an instance 
    140.      * of itself).  Must happen before registration of system natives, 
    141.      * which make some calls that throw assertions if the classes they 
    142.      * operate on aren't initialized. 
    143.      */  
    144.     if (!dvmInitClass(gDvm.classJavaLangClass)) {  
    145.         return "couldn't initialized java.lang.Class";  
    146.     }  
    147.   
    148.     /* 
    149.      * Register the system native methods, which are registered through JNI. 
    150.      */  
    151.     if (!registerSystemNatives(pEnv)) {  
    152.         return "couldn't register system natives";  
    153.     }  
    154.   
    155.     /* 
    156.      * Do some "late" initialization for the memory allocator.  This may 
    157.      * allocate storage and initialize classes. 
    158.      */  
    159.     if (!dvmCreateStockExceptions()) {  
    160.         return "dvmCreateStockExceptions failed";  
    161.     }  
    162.   
    163.     /* 
    164.      * At this point, the VM is in a pretty good state.  Finish prep on 
    165.      * the main thread (specifically, create a java.lang.Thread object to go 
    166.      * along with our Thread struct).  Note we will probably be executing 
    167.      * some interpreted class initializer code in here. 
    168.      */  
    169.     if (!dvmPrepMainThread()) {  
    170.         return "dvmPrepMainThread failed";  
    171.     }  
    172.   
    173.     /* 
    174.      * Make sure we haven't accumulated any tracked references.  The main 
    175.      * thread should be starting with a clean slate. 
    176.      */  
    177.     if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0)  
    178.     {  
    179.         LOGW("Warning: tracked references remain post-initialization");  
    180.         dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, "MAIN");  
    181.     }  
    182.   
    183.     /* general debugging setup */  
    184.     if (!dvmDebuggerStartup()) {  
    185.         return "dvmDebuggerStartup failed";  
    186.     }  
    187.   
    188.     if (!dvmGcStartupClasses()) {  
    189.         return "dvmGcStartupClasses failed";  
    190.     }  
    191.   
    192.     /* 
    193.      * Init for either zygote mode or non-zygote mode.  The key difference 
    194.      * is that we don't start any additional threads in Zygote mode. 
    195.      */  
    196.     if (gDvm.zygote) {  
    197.         if (!initZygote()) {  
    198.             return "initZygote failed";  
    199.         }  
    200.     } else {  
    201.         if (!dvmInitAfterZygote()) {  
    202.             return "dvmInitAfterZygote failed";  
    203.         }  
    204.     }  
    205.   
    206.   
    207. #ifndef NDEBUG  
    208.     if (!dvmTestHash())  
    209.         LOGE("dvmTestHash FAILED");  
    210.     if (false /*noisy!*/ && !dvmTestIndirectRefTable())  
    211.         LOGE("dvmTestIndirectRefTable FAILED");  
    212. #endif  
    213.   
    214.     if (dvmCheckException(dvmThreadSelf())) {  
    215.         dvmLogExceptionStackTrace();  
    216.         return "Exception pending at end of VM initialization";  
    217.     }  
    218.   
    219.     scopedShutdown.disarm();  
    220.     return "";  
    221. }  

     代码真长。寻找其中最具价值的部分

           

    插入代码:

              

    Java代码  收藏代码
    1. if (!dvmAllocTrackerStartup()) {  
    2.      return "dvmAllocTrackerStartup failed";  
    3.  }  
    4.  if (!dvmGcStartup()) {  
    5.      return "dvmGcStartup failed";  
    6.  }  
    7.  if (!dvmThreadStartup()) {  
    8.      return "dvmThreadStartup failed";  
    9.  }  
    10.  if (!dvmInlineNativeStartup()) {  
    11.      return "dvmInlineNativeStartup";  
    12.  }  
    13.  if (!dvmRegisterMapStartup()) {  
    14.      return "dvmRegisterMapStartup failed";  
    15.  }  
    16.  if (!dvmInstanceofStartup()) {  
    17.      return "dvmInstanceofStartup failed";  
    18.  }  
    19.  if (!dvmClassStartup()) {  
    20.      return "dvmClassStartup failed";  
    21.  }  

     经分析,这些都没有建立gc线程,gc线程的建立是在如下方法:

    Java代码  收藏代码
    1. dvmInitAfterZygote  

      由于跟得太深,东西很多,就不一一列举。仅仅跟一下dvmClassStartup,最终调用到了dalvik/vm/oo/Class.cpp中的方法:

    Java代码  收藏代码
    1. /* 
    2.  * Initialize the bootstrap class loader. 
    3.  * 
    4.  * Call this after the bootclasspath string has been finalized. 
    5.  */  
    6. bool dvmClassStartup()  
    7. {  
    8.     /* make this a requirement -- don't currently support dirs in path */  
    9.     if (strcmp(gDvm.bootClassPathStr, ".") == 0) {  
    10.         LOGE("ERROR: must specify non-'.' bootclasspath");  
    11.         return false;  
    12.     }  
    13.   
    14.     gDvm.loadedClasses =  
    15.         dvmHashTableCreate(256, (HashFreeFunc) dvmFreeClassInnards);  
    16.   
    17.     gDvm.pBootLoaderAlloc = dvmLinearAllocCreate(NULL);  
    18.     if (gDvm.pBootLoaderAlloc == NULL)  
    19.         return false;  
    20.   
    21.     if (false) {  
    22.         linearAllocTests();  
    23.         exit(0);  
    24.     }  
    25.   
    26.     /* 
    27.      * Class serial number.  We start with a high value to make it distinct 
    28.      * in binary dumps (e.g. hprof). 
    29.      */  
    30.     gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;  
    31.   
    32.     /* 
    33.      * Set up the table we'll use for tracking initiating loaders for 
    34.      * early classes. 
    35.      * If it's NULL, we just fall back to the InitiatingLoaderList in the 
    36.      * ClassObject, so it's not fatal to fail this allocation. 
    37.      */  
    38.     gDvm.initiatingLoaderList = (InitiatingLoaderList*)  
    39.         calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));  
    40.   
    41.     /* 
    42.      * Create the initial classes. These are the first objects constructed 
    43.      * within the nascent VM. 
    44.      */  
    45.     if (!createInitialClasses()) {  
    46.         return false;  
    47.     }  
    48.   
    49.     /* 
    50.      * Process the bootstrap class path.  This means opening the specified 
    51.      * DEX or Jar files and possibly running them through the optimizer. 
    52.      */  
    53.     assert(gDvm.bootClassPath == NULL);  
    54.     processClassPath(gDvm.bootClassPathStr, true);  
    55.   
    56.     if (gDvm.bootClassPath == NULL)  
    57.         return false;  
    58.   
    59.     return true;  
    60. }  

     根据注释,Initialize the bootstrap class loader.
    这个函数告诉我们,他建立了boottrap classloader。

    createInitialClasses加载了9大基本类型。而后的processClassPath则建立了基本的classloader。分析过后,比较失望。可能是为后续的boottrapclassloader做一些前期准备工作。

    startVM就到这里。

    好吧。现在又回到了最初的App_main.cpp中。进入了com.android.internal.os.ZygoteInit.java的main

    Java代码  收藏代码
    1. public static void main(String argv[]) {  
    2.     try {  
    3.         // Start profiling the zygote initialization.  
    4.         SamplingProfilerIntegration.start();  
    5.   
    6.         registerZygoteSocket();  
    7.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,  
    8.             SystemClock.uptimeMillis());  
    9.         preload();  
    10.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,  
    11.             SystemClock.uptimeMillis());  
    12.   
    13.         // Finish profiling the zygote initialization.  
    14.         SamplingProfilerIntegration.writeZygoteSnapshot();  
    15.   
    16.         // Do an initial gc to clean up after startup  
    17.         gc();  
    18.   
    19.         // If requested, start system server directly from Zygote  
    20.         if (argv.length != 2) {  
    21.             throw new RuntimeException(argv[0] + USAGE_STRING);  
    22.         }  
    23.   
    24.         if (argv[1].equals("start-system-server")) {  
    25.             startSystemServer();  
    26.         } else if (!argv[1].equals("")) {  
    27.             throw new RuntimeException(argv[0] + USAGE_STRING);  
    28.         }  
    29.   
    30.         Log.i(TAG, "Accepting command socket connections");  
    31.   
    32.         if (ZYGOTE_FORK_MODE) {  
    33.             runForkMode();  
    34.         } else {  
    35.             runSelectLoopMode();  
    36.         }  
    37.   
    38.         closeServerSocket();  
    39.     } catch (MethodAndArgsCaller caller) {  
    40.         caller.run();  
    41.     } catch (RuntimeException ex) {  
    42.         Log.e(TAG, "Zygote died with exception", ex);  
    43.         closeServerSocket();  
    44.         throw ex;  
    45.     }  
    46. }  

     回过头来继续看一下ZygoteInit.java这个类是如何初始化的,看如下代码:

    Java代码  收藏代码
    1. /* 
    2.  * Create a new JNIEnv struct and add it to the VM's list. 
    3.  * 
    4.  * "self" will be NULL for the main thread, since the VM hasn't started 
    5.  * yet; the value will be filled in later. 
    6.  */  
    7. JNIEnv* dvmCreateJNIEnv(Thread* self) {  
    8.     JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;  
    9.   
    10.     //if (self != NULL)  
    11.     //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);  
    12.   
    13.     assert(vm != NULL);  
    14.   
    15.     JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));  
    16.     newEnv->funcTable = &gNativeInterface;  
    17.     if (self != NULL) {  
    18.         dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);  
    19.         assert(newEnv->envThreadId != 0);  
    20.     } else {  
    21.         /* make it obvious if we fail to initialize these later */  
    22.         newEnv->envThreadId = 0x77777775;  
    23.         newEnv->self = (Thread*) 0x77777779;  
    24.     }  
    25.     if (gDvmJni.useCheckJni) {  
    26.         dvmUseCheckedJniEnv(newEnv);  
    27.     }  
    28.   
    29.     ScopedPthreadMutexLock lock(&vm->envListLock);  
    30.   
    31.     /* insert at head of list */  
    32.     newEnv->next = vm->envList;  
    33.     assert(newEnv->prev == NULL);  
    34.     if (vm->envList == NULL) {  
    35.         // rare, but possible  
    36.         vm->envList = newEnv;  
    37.     } else {  
    38.         vm->envList->prev = newEnv;  
    39.     }  
    40.     vm->envList = newEnv;  
    41.   
    42.     //if (self != NULL)  
    43.     //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);  
    44.     return (JNIEnv*) newEnv;  
    45. }  

     最重要的是gNativeInterface 我们看定义,太长了,我们找到其中的FindClass。

    Cpp代码  收藏代码
    1. static jclass FindClass(JNIEnv* env, const char* name) {  
    2.     ScopedJniThreadState ts(env);  
    3.   
    4.     const Method* thisMethod = dvmGetCurrentJNIMethod();  
    5.     assert(thisMethod != NULL);  
    6.   
    7.     Object* loader;  
    8.     Object* trackedLoader = NULL;  
    9.     if (ts.self()->classLoaderOverride != NULL) {  
    10.         /* hack for JNI_OnLoad */  
    11.         assert(strcmp(thisMethod->name, "nativeLoad") == 0);  
    12.         loader = ts.self()->classLoaderOverride;  
    13.     } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||  
    14.                thisMethod == gDvm.methDalvikSystemNativeStart_run) {  
    15.         /* start point of invocation interface */  
    16.         if (!gDvm.initializing) {  
    17.             loader = trackedLoader = dvmGetSystemClassLoader();  
    18.         } else {  
    19.             loader = NULL;  
    20.         }  
    21.     } else {  
    22.         loader = thisMethod->clazz->classLoader;  
    23.     }  
    24.   
    25.     char* descriptor = dvmNameToDescriptor(name);  
    26.     if (descriptor == NULL) {  
    27.         return NULL;  
    28.     }  
    29.     ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);  
    30.     free(descriptor);  
    31.   
    32.     jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);  
    33.     dvmReleaseTrackedAlloc(trackedLoader, ts.self());  
    34.     return jclazz;  
    35. }  

    在dalvik/vm/Init.cpp中的方法对gVM的bootpath进行了初始化:

    Java代码  收藏代码
    1. static void setCommandLineDefaults()  
    2. {  
    3.     const char* envStr = getenv("CLASSPATH");  
    4.     if (envStr != NULL) {  
    5.         gDvm.classPathStr = strdup(envStr);  
    6.     } else {  
    7.         gDvm.classPathStr = strdup(".");  
    8.     }  
    9.     envStr = getenv("BOOTCLASSPATH");  
    10.     if (envStr != NULL) {  
    11.         gDvm.bootClassPathStr = strdup(envStr);  
    12.     } else {  
    13.         gDvm.bootClassPathStr = strdup(".");  
    14.     }  
    15.   
    16.     gDvm.properties = new std::vector<std::string>();  
    17.   
    18.     /* Defaults overridden by -Xms and -Xmx. 
    19.      * TODO: base these on a system or application-specific default 
    20.      */  
    21.     gDvm.heapStartingSize = 2 * 1024 * 1024;  // Spec says 16MB; too big for us.  
    22.     gDvm.heapMaximumSize = 16 * 1024 * 1024;  // Spec says 75% physical mem  
    23.     gDvm.heapGrowthLimit = 0;  // 0 means no growth limit  
    24.     gDvm.stackSize = kDefaultStackSize;  
    25.   
    26.     gDvm.concurrentMarkSweep = true;  
    27.   
    28.     /* gDvm.jdwpSuspend = true; */  

    现在明白了,在init.rc中指定的BOOTCLASSPATH赋值给了gDvm.bootClassPathStr 。

    而下面这个地方,则对FindClass进行了初始化。还是在dalvik/vm/Init.cpp中

    Cpp代码  收藏代码
    1. */  
    2. f (!dvmFindRequiredClassesAndMembers()) {  
    3.    return "dvmFindRequiredClassesAndMembers failed";  

    initDirectMethodReferences 把方法gDvm.methDalvikSystemNativeStart_main与NativeStart进行了对应。

    Java代码  收藏代码
    1. { &gDvm.methDalvikSystemNativeStart_main, "Ldalvik/system/NativeStart;", "main", "([Ljava/lang/String;)V" },  

    主要分析FindClass方法:

     nativeLoad标示从System.loadlibrary加载。那么Zygote的dvmGetCurrentJNIMethod是哪个呢。我猜测,这个一定是没有的,也就是里面的成员变量全为空。哈哈。这意味着,最终调用到了

    dvmFindClassNoInit方法中。

    然后是ClassObject* dvmFindSystemClassNoInit(const char* descriptor)
    {
        return findClassNoInit(descriptor, NULL, NULL);
    }
    然后是findClassNoInit

    ZygoteInit这个类根本是没有ClassLoader的。而是直接从包里面查找得到的。

    进入ZygoteInit后。就是java代码了。

  • 相关阅读:
    《区块链100问》第38集:比特币钱包是干嘛的?
    《区块链100问》第39集:冷钱包热钱包
    《区块链100问》第40集:全节点钱包和轻钱包
    《区块链100问》第41集:比特币可以用于支付吗?
    《区块链100问》第42集:区块链和比特币的关系
    《区块链100问》第43集:区块链技术发展史
    KindEditor使用
    Django之验证码
    Django之ModelForm
    Django之Form详解
  • 原文地址:https://www.cnblogs.com/xiaochao1234/p/4173731.html
Copyright © 2020-2023  润新知