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


    安卓高手之路之ClassLoader(二) - 修补C++ - ITeye技术网站

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

    Cpp代码  收藏代码
    1. int main(int argc, const charconst 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. }  
    int main(int argc, const char* const argv[])
    {
        // These are global variables in ProcessState.cpp
        //ProcessState.cpp中可能要用到一些main函数。
        mArgC = argc;
        mArgV = argv;
    
        mArgLen = 0;
        for (int i=0; i<argc; i++) {
            mArgLen += strlen(argv[i]) + 1;
        }
        mArgLen--;
    
        AppRuntime runtime;
        const char* argv0 = argv[0];
    
        // Process command line arguments
        // ignore argv[0]
        argc--;
        argv++;
    
        // Everything up to '--' or first non '-' arg goes to the vm
    
        int i = runtime.addVmArguments(argc, argv);
    
        // Parse runtime arguments.  Stop at first unrecognized option.
        bool zygote = false;
        bool startSystemServer = false;
        bool application = false;
        const char* parentDir = NULL;
        const char* niceName = NULL;
        const char* className = NULL;
        while (i < argc) {
            const char* arg = argv[i++];
            if (!parentDir) {
                parentDir = arg;
            } else if (strcmp(arg, "--zygote") == 0) {
                zygote = true;
                niceName = "zygote";
            } else if (strcmp(arg, "--start-system-server") == 0) {
                startSystemServer = true;
            } else if (strcmp(arg, "--application") == 0) {
                application = true;
            } else if (strncmp(arg, "--nice-name=", 12) == 0) {
                niceName = arg + 12;
            } else {
                className = arg;
                break;
            }
        }
    
        if (niceName && *niceName) {
            setArgv0(argv0, niceName);
            set_process_name(niceName);
        }
    
        runtime.mParentDir = parentDir;
    
        if (zygote) {
            runtime.start("com.android.internal.os.ZygoteInit",
                    startSystemServer ? "start-system-server" : "");
        } else if (className) {
            // Remainder of args get passed to startup class main()
            runtime.mClassName = className;
            runtime.mArgC = argc - i;
            runtime.mArgV = argv + i;
            runtime.start("com.android.internal.os.RuntimeInit",
                    application ? "application" : "tool");
        } else {
            fprintf(stderr, "Error: no class name or --zygote supplied.
    ");
            app_usage();
            LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
            return 10;
        }
    }
    

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

        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" : "");  
       runtime.start("com.android.internal.os.ZygoteInit",
                    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");  
      runtime.mClassName = className;
         runtime.mArgC = argc - i; //className,包括className以后的参数个数。
       runtime.mArgV = argv + i; //截止到className的参数个数
      runtime.start("com.android.internal.os.RuntimeInit",
                    application ? "application" : "tool");

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

      

    Java代码  收藏代码
    1. runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");  
    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");  
    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");  
    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. }  
    /*
     * Start the Android runtime.  This involves starting the virtual machine
     * and calling the "static void main(String[] args)" method in the class
     * named by "className".
     *
     * Passes the main function two arguments, the class name and the specified
     * options string.
     */
    void AndroidRuntime::start(const char* className, const char* options)
    {
        LOGD("
    >>>>>> AndroidRuntime START %s <<<<<<
    ",
                className != NULL ? className : "(unknown)");
    
        blockSigpipe();
    
        /*
         * 'startSystemServer == true' means runtime is obsolete and not run from
         * init.rc anymore, so we print out the boot start event here.
         */
        if (strcmp(options, "start-system-server") == 0) {
            /* track our progress through the boot sequence */
            const int LOG_BOOT_PROGRESS_START = 3000;
            LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
                           ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    
        const char* rootDir = getenv("ANDROID_ROOT");
        if (rootDir == NULL) {
            rootDir = "/system";
            if (!hasDir("/system")) {
                LOG_FATAL("No root directory specified, and /android does not exist.");
                return;
            }
            setenv("ANDROID_ROOT", rootDir, 1);
        }
    
        //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
        //LOGD("Found LD_ASSUME_KERNEL='%s'
    ", kernelHack);
    
        /* start the virtual machine */
        JNIEnv* env;
        if (startVm(&mJavaVM, &env) != 0) {
            return;
        }
        onVmCreated(env);
    
        /*
         * Register android functions.
         */
        if (startReg(env) < 0) {
            LOGE("Unable to register all android natives
    ");
            return;
        }
    
        /*
         * We want to call main() with a String array with arguments in it.
         * At present we have two arguments, the class name and an option string.
         * Create an array to hold them.
         */
        jclass stringClass;
        jobjectArray strArray;
        jstring classNameStr;
        jstring optionsStr;
    
        stringClass = env->FindClass("java/lang/String");
        assert(stringClass != NULL);
        strArray = env->NewObjectArray(2, stringClass, NULL);
        assert(strArray != NULL);
        classNameStr = env->NewStringUTF(className);
        assert(classNameStr != NULL);
        env->SetObjectArrayElement(strArray, 0, classNameStr);
        optionsStr = env->NewStringUTF(options);
        env->SetObjectArrayElement(strArray, 1, optionsStr);
    
        /*
         * Start VM.  This thread becomes the main thread of the VM, and will
         * not return until the VM exits.
         */
        char* slashClassName = toSlashClassName(className);
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            LOGE("JavaVM unable to locate class '%s'
    ", slashClassName);
            /* keep going */
        } else {
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");
            if (startMeth == NULL) {
                LOGE("JavaVM unable to find main() in '%s'
    ", className);
                /* keep going */
            } else {
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
    
    #if 0
                if (env->ExceptionCheck())
                    threadExitUncaughtException(env);
    #endif
            }
        }
        free(slashClassName);
    
        LOGD("Shutting down VM
    ");
        if (mJavaVM->DetachCurrentThread() != JNI_OK)
            LOGW("Warning: unable to detach main thread
    ");
        if (mJavaVM->DestroyJavaVM() != 0)
            LOGW("Warning: VM did not shut down cleanly
    ");
    }

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

    Cpp代码  收藏代码
    1. LOGD(" >>>>>> AndroidRuntime START %s <<<<<< ",  
    2.         className != NULL ? className : "(unknown)");  
    3.   
    4. blockSigpipe();  
        LOGD("
    >>>>>> AndroidRuntime START %s <<<<<<
    ",
                className != NULL ? className : "(unknown)");
    
        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.     }  
    if (strcmp(options, "start-system-server") == 0) {
            /* track our progress through the boot sequence */
            const int LOG_BOOT_PROGRESS_START = 3000;
            LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
                           ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    

     下面这句话定义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.  }  
       const char* rootDir = getenv("ANDROID_ROOT");
        if (rootDir == NULL) {
            rootDir = "/system";
            if (!hasDir("/system")) {
                LOG_FATAL("No root directory specified, and /android does not exist.");
                return;
            }
            setenv("ANDROID_ROOT", rootDir, 1);
        }
    

     对照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  
    # setup the global environment
        export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
        export LD_LIBRARY_PATH /vendor/lib:/system/lib
        export ANDROID_BOOTLOGO 1
        export ANDROID_ROOT /system
        export ANDROID_ASSETS /system/app
        export ANDROID_DATA /data
        export ASEC_MOUNTPOINT /mnt/asec
        export LOOP_MOUNTPOINT /mnt/obb
        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.   }  
      /* start the virtual machine */
        JNIEnv* env;
        if (startVm(&mJavaVM, &env) != 0) {
            return;
        }
        onVmCreated(env);
    
        /*
         * Register android functions.
         */
        if (startReg(env) < 0) {
            LOGE("Unable to register all android natives
    ");
            return;
        }
    

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

    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. }  
    jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
        const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
        if (args->version < JNI_VERSION_1_2) {
            return JNI_EVERSION;
        }
    
        // TODO: don't allow creation of multiple VMs -- one per customer for now
    
        /* zero globals; not strictly necessary the first time a VM is started */
        memset(&gDvm, 0, sizeof(gDvm));
    
        /*
         * Set up structures for JNIEnv and VM.
         */
        JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
        memset(pVM, 0, sizeof(JavaVMExt));
        pVM->funcTable = &gInvokeInterface;
        pVM->envList = NULL;
        dvmInitMutex(&pVM->envListLock);
    
        UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
        memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
    
        /*
         * Convert JNI args to argv.
         *
         * We have to pull out vfprintf/exit/abort, because they use the
         * "extraInfo" field to pass function pointer "hooks" in.  We also
         * look for the -Xcheck:jni stuff here.
         */
        int argc = 0;
        for (int i = 0; i < args->nOptions; i++) {
            const char* optStr = args->options[i].optionString;
            if (optStr == NULL) {
                dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL
    ", i);
                return JNI_ERR;
            } else if (strcmp(optStr, "vfprintf") == 0) {
                gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
            } else if (strcmp(optStr, "exit") == 0) {
                gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
            } else if (strcmp(optStr, "abort") == 0) {
                gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
            } else if (strcmp(optStr, "sensitiveThread") == 0) {
                gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
            } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
                gDvmJni.useCheckJni = true;
            } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
                char* jniOpts = strdup(optStr + 10);
                size_t jniOptCount = 1;
                for (char* p = jniOpts; *p != 0; ++p) {
                    if (*p == ',') {
                        ++jniOptCount;
                        *p = 0;
                    }
                }
                char* jniOpt = jniOpts;
                for (size_t i = 0; i < jniOptCount; ++i) {
                    if (strcmp(jniOpt, "warnonly") == 0) {
                        gDvmJni.warnOnly = true;
                    } else if (strcmp(jniOpt, "forcecopy") == 0) {
                        gDvmJni.forceCopy = true;
                    } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
                        gDvmJni.logThirdPartyJni = true;
                    } else {
                        dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'
    ",
                                jniOpt);
                        return JNI_ERR;
                    }
                    jniOpt += strlen(jniOpt) + 1;
                }
                free(jniOpts);
            } else {
                /* regular option */
                argv[argc++] = optStr;
            }
        }
    
        if (gDvmJni.useCheckJni) {
            dvmUseCheckedJniVm(pVM);
        }
    
        if (gDvmJni.jniVm != NULL) {
            dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process
    ");
            return JNI_ERR;
        }
        gDvmJni.jniVm = (JavaVM*) pVM;
    
        /*
         * Create a JNIEnv for the main thread.  We need to have something set up
         * here because some of the class initialization we do when starting
         * up the VM will call into native code.
         */
        JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
    
        /* Initialize VM. */
        gDvm.initializing = true;
        std::string status =
                dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
        gDvm.initializing = false;
    
        if (!status.empty()) {
            free(pEnv);
            free(pVM);
            LOGW("CreateJavaVM failed: %s", status.c_str());
            return JNI_ERR;
        }
    
        /*
         * Success!  Return stuff to caller.
         */
        dvmChangeStatus(NULL, THREAD_NATIVE);
        *p_env = (JNIEnv*) pEnv;
        *p_vm = (JavaVM*) pVM;
        LOGV("CreateJavaVM succeeded");
        return JNI_OK;
    }

      然后调用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. }  
    /*
     * Create a new JNIEnv struct and add it to the VM's list.
     *
     * "self" will be NULL for the main thread, since the VM hasn't started
     * yet; the value will be filled in later.
     */
    JNIEnv* dvmCreateJNIEnv(Thread* self) {
        JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
    
        //if (self != NULL)
        //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
    
        assert(vm != NULL);
    
        JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
        newEnv->funcTable = &gNativeInterface;
        if (self != NULL) {
            dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
            assert(newEnv->envThreadId != 0);
        } else {
            /* make it obvious if we fail to initialize these later */
            newEnv->envThreadId = 0x77777775;
            newEnv->self = (Thread*) 0x77777779;
        }
        if (gDvmJni.useCheckJni) {
            dvmUseCheckedJniEnv(newEnv);
        }
    
        ScopedPthreadMutexLock lock(&vm->envListLock);
    
        /* insert at head of list */
        newEnv->next = vm->envList;
        assert(newEnv->prev == NULL);
        if (vm->envList == NULL) {
            // rare, but possible
            vm->envList = newEnv;
        } else {
            vm->envList->prev = newEnv;
        }
        vm->envList = newEnv;
    
        //if (self != NULL)
        //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
        return (JNIEnv*) newEnv;
    }
    

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

      

    Java代码  收藏代码
    1. std::string status =  
    2.            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);  
     std::string status =
                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 charconst 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. }  
    *
     * VM initialization.  Pass in any options provided on the command line.
     * Do not pass in the class name or the options for the class.
     *
     * Returns 0 on success.
     */
    std::string dvmStartup(int argc, const char* const argv[],
            bool ignoreUnrecognized, JNIEnv* pEnv)
    {
        ScopedShutdown scopedShutdown;
    
        assert(gDvm.initializing);
    
        LOGV("VM init args (%d):", argc);
        for (int i = 0; i < argc; i++) {
            LOGV("  %d: '%s'", i, argv[i]);
        }
        setCommandLineDefaults();
    
        /*
         * Process the option flags (if any).
         */
        int cc = processOptions(argc, argv, ignoreUnrecognized);
        if (cc != 0) {
            if (cc < 0) {
                dvmFprintf(stderr, "
    ");
                usage("dalvikvm");
            }
            return "syntax error";
        }
    
    #if WITH_EXTRA_GC_CHECKS > 1
        /* only "portable" interp has the extra goodies */
        if (gDvm.executionMode != kExecutionModeInterpPortable) {
            LOGI("Switching to 'portable' interpreter for GC checks");
            gDvm.executionMode = kExecutionModeInterpPortable;
        }
    #endif
    
        /* Configure group scheduling capabilities */
        if (!access("/dev/cpuctl/tasks", F_OK)) {
            LOGV("Using kernel group scheduling");
            gDvm.kernelGroupScheduling = 1;
        } else {
            LOGV("Using kernel scheduler policies");
        }
    
        /* configure signal handling */
        if (!gDvm.reduceSignals)
            blockSignals();
    
        /* verify system page size */
        if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) {
            return StringPrintf("expected page size %d, got %d",
                    SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE));
        }
    
        /* mterp setup */
        LOGV("Using executionMode %d", gDvm.executionMode);
        dvmCheckAsmConstants();
    
        /*
         * Initialize components.
         */
        dvmQuasiAtomicsStartup();
        if (!dvmAllocTrackerStartup()) {
            return "dvmAllocTrackerStartup failed";
        }
        if (!dvmGcStartup()) {
            return "dvmGcStartup failed";
        }
        if (!dvmThreadStartup()) {
            return "dvmThreadStartup failed";
        }
        if (!dvmInlineNativeStartup()) {
            return "dvmInlineNativeStartup";
        }
        if (!dvmRegisterMapStartup()) {
            return "dvmRegisterMapStartup failed";
        }
        if (!dvmInstanceofStartup()) {
            return "dvmInstanceofStartup failed";
        }
        if (!dvmClassStartup()) {
            return "dvmClassStartup failed";
        }
    
        /*
         * At this point, the system is guaranteed to be sufficiently
         * initialized that we can look up classes and class members. This
         * call populates the gDvm instance with all the class and member
         * references that the VM wants to use directly.
         */
        if (!dvmFindRequiredClassesAndMembers()) {
            return "dvmFindRequiredClassesAndMembers failed";
        }
    
        if (!dvmStringInternStartup()) {
            return "dvmStringInternStartup failed";
        }
        if (!dvmNativeStartup()) {
            return "dvmNativeStartup failed";
        }
        if (!dvmInternalNativeStartup()) {
            return "dvmInternalNativeStartup failed";
        }
        if (!dvmJniStartup()) {
            return "dvmJniStartup failed";
        }
        if (!dvmProfilingStartup()) {
            return "dvmProfilingStartup failed";
        }
    
        /*
         * Create a table of methods for which we will substitute an "inline"
         * version for performance.
         */
        if (!dvmCreateInlineSubsTable()) {
            return "dvmCreateInlineSubsTable failed";
        }
    
        /*
         * Miscellaneous class library validation.
         */
        if (!dvmValidateBoxClasses()) {
            return "dvmValidateBoxClasses failed";
        }
    
        /*
         * Do the last bits of Thread struct initialization we need to allow
         * JNI calls to work.
         */
        if (!dvmPrepMainForJni(pEnv)) {
            return "dvmPrepMainForJni failed";
        }
    
        /*
         * Explicitly initialize java.lang.Class.  This doesn't happen
         * automatically because it's allocated specially (it's an instance
         * of itself).  Must happen before registration of system natives,
         * which make some calls that throw assertions if the classes they
         * operate on aren't initialized.
         */
        if (!dvmInitClass(gDvm.classJavaLangClass)) {
            return "couldn't initialized java.lang.Class";
        }
    
        /*
         * Register the system native methods, which are registered through JNI.
         */
        if (!registerSystemNatives(pEnv)) {
            return "couldn't register system natives";
        }
    
        /*
         * Do some "late" initialization for the memory allocator.  This may
         * allocate storage and initialize classes.
         */
        if (!dvmCreateStockExceptions()) {
            return "dvmCreateStockExceptions failed";
        }
    
        /*
         * At this point, the VM is in a pretty good state.  Finish prep on
         * the main thread (specifically, create a java.lang.Thread object to go
         * along with our Thread struct).  Note we will probably be executing
         * some interpreted class initializer code in here.
         */
        if (!dvmPrepMainThread()) {
            return "dvmPrepMainThread failed";
        }
    
        /*
         * Make sure we haven't accumulated any tracked references.  The main
         * thread should be starting with a clean slate.
         */
        if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0)
        {
            LOGW("Warning: tracked references remain post-initialization");
            dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, "MAIN");
        }
    
        /* general debugging setup */
        if (!dvmDebuggerStartup()) {
            return "dvmDebuggerStartup failed";
        }
    
        if (!dvmGcStartupClasses()) {
            return "dvmGcStartupClasses failed";
        }
    
        /*
         * Init for either zygote mode or non-zygote mode.  The key difference
         * is that we don't start any additional threads in Zygote mode.
         */
        if (gDvm.zygote) {
            if (!initZygote()) {
                return "initZygote failed";
            }
        } else {
            if (!dvmInitAfterZygote()) {
                return "dvmInitAfterZygote failed";
            }
        }
    
    #ifndef NDEBUG
        if (!dvmTestHash())
            LOGE("dvmTestHash FAILED");
        if (false /*noisy!*/ && !dvmTestIndirectRefTable())
            LOGE("dvmTestIndirectRefTable FAILED");
    #endif
    
        if (dvmCheckException(dvmThreadSelf())) {
            dvmLogExceptionStackTrace();
            return "Exception pending at end of VM initialization";
        }
    
        scopedShutdown.disarm();
        return "";
    }
    

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

           

    插入代码:

              

    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.  }  
       if (!dvmAllocTrackerStartup()) {
            return "dvmAllocTrackerStartup failed";
        }
        if (!dvmGcStartup()) {
            return "dvmGcStartup failed";
        }
        if (!dvmThreadStartup()) {
            return "dvmThreadStartup failed";
        }
        if (!dvmInlineNativeStartup()) {
            return "dvmInlineNativeStartup";
        }
        if (!dvmRegisterMapStartup()) {
            return "dvmRegisterMapStartup failed";
        }
        if (!dvmInstanceofStartup()) {
            return "dvmInstanceofStartup failed";
        }
        if (!dvmClassStartup()) {
            return "dvmClassStartup failed";
        }

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

    Java代码  收藏代码
    1. dvmInitAfterZygote  
    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.
     *
     * Call this after the bootclasspath string has been finalized.
     */
    bool dvmClassStartup()
    {
        /* make this a requirement -- don't currently support dirs in path */
        if (strcmp(gDvm.bootClassPathStr, ".") == 0) {
            LOGE("ERROR: must specify non-'.' bootclasspath");
            return false;
        }
    
        gDvm.loadedClasses =
            dvmHashTableCreate(256, (HashFreeFunc) dvmFreeClassInnards);
    
        gDvm.pBootLoaderAlloc = dvmLinearAllocCreate(NULL);
        if (gDvm.pBootLoaderAlloc == NULL)
            return false;
    
        if (false) {
            linearAllocTests();
            exit(0);
        }
    
        /*
         * Class serial number.  We start with a high value to make it distinct
         * in binary dumps (e.g. hprof).
         */
        gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;
    
        /*
         * Set up the table we'll use for tracking initiating loaders for
         * early classes.
         * If it's NULL, we just fall back to the InitiatingLoaderList in the
         * ClassObject, so it's not fatal to fail this allocation.
         */
        gDvm.initiatingLoaderList = (InitiatingLoaderList*)
            calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));
    
        /*
         * Create the initial classes. These are the first objects constructed
         * within the nascent VM.
         */
        if (!createInitialClasses()) {
            return false;
        }
    
        /*
         * Process the bootstrap class path.  This means opening the specified
         * DEX or Jar files and possibly running them through the optimizer.
         */
        assert(gDvm.bootClassPath == NULL);
        processClassPath(gDvm.bootClassPathStr, true);
    
        if (gDvm.bootClassPath == NULL)
            return false;
    
        return true;
    }

     根据注释,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. }  
        public static void main(String argv[]) {
            try {
                // Start profiling the zygote initialization.
                SamplingProfilerIntegration.start();
    
                registerZygoteSocket();
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                preload();
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
    
                // Finish profiling the zygote initialization.
                SamplingProfilerIntegration.writeZygoteSnapshot();
    
                // Do an initial gc to clean up after startup
                gc();
    
                // If requested, start system server directly from Zygote
                if (argv.length != 2) {
                    throw new RuntimeException(argv[0] + USAGE_STRING);
                }
    
                if (argv[1].equals("start-system-server")) {
                    startSystemServer();
                } else if (!argv[1].equals("")) {
                    throw new RuntimeException(argv[0] + USAGE_STRING);
                }
    
                Log.i(TAG, "Accepting command socket connections");
    
                if (ZYGOTE_FORK_MODE) {
                    runForkMode();
                } else {
                    runSelectLoopMode();
                }
    
                closeServerSocket();
            } catch (MethodAndArgsCaller caller) {
                caller.run();
            } catch (RuntimeException ex) {
                Log.e(TAG, "Zygote died with exception", ex);
                closeServerSocket();
                throw ex;
            }
        }

     回过头来继续看一下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. }  
    /*
     * Create a new JNIEnv struct and add it to the VM's list.
     *
     * "self" will be NULL for the main thread, since the VM hasn't started
     * yet; the value will be filled in later.
     */
    JNIEnv* dvmCreateJNIEnv(Thread* self) {
        JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
    
        //if (self != NULL)
        //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
    
        assert(vm != NULL);
    
        JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
        newEnv->funcTable = &gNativeInterface;
        if (self != NULL) {
            dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
            assert(newEnv->envThreadId != 0);
        } else {
            /* make it obvious if we fail to initialize these later */
            newEnv->envThreadId = 0x77777775;
            newEnv->self = (Thread*) 0x77777779;
        }
        if (gDvmJni.useCheckJni) {
            dvmUseCheckedJniEnv(newEnv);
        }
    
        ScopedPthreadMutexLock lock(&vm->envListLock);
    
        /* insert at head of list */
        newEnv->next = vm->envList;
        assert(newEnv->prev == NULL);
        if (vm->envList == NULL) {
            // rare, but possible
            vm->envList = newEnv;
        } else {
            vm->envList->prev = newEnv;
        }
        vm->envList = newEnv;
    
        //if (self != NULL)
        //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
        return (JNIEnv*) newEnv;
    }
    

     最重要的是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. }  
    static jclass FindClass(JNIEnv* env, const char* name) {
        ScopedJniThreadState ts(env);
    
        const Method* thisMethod = dvmGetCurrentJNIMethod();
        assert(thisMethod != NULL);
    
        Object* loader;
        Object* trackedLoader = NULL;
        if (ts.self()->classLoaderOverride != NULL) {
            /* hack for JNI_OnLoad */
            assert(strcmp(thisMethod->name, "nativeLoad") == 0);
            loader = ts.self()->classLoaderOverride;
        } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
                   thisMethod == gDvm.methDalvikSystemNativeStart_run) {
            /* start point of invocation interface */
            if (!gDvm.initializing) {
                loader = trackedLoader = dvmGetSystemClassLoader();
            } else {
                loader = NULL;
            }
        } else {
            loader = thisMethod->clazz->classLoader;
        }
    
        char* descriptor = dvmNameToDescriptor(name);
        if (descriptor == NULL) {
            return NULL;
        }
        ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
        free(descriptor);
    
        jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
        dvmReleaseTrackedAlloc(trackedLoader, ts.self());
        return jclazz;
    }

    在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; */  
    static void setCommandLineDefaults()
    {
        const char* envStr = getenv("CLASSPATH");
        if (envStr != NULL) {
            gDvm.classPathStr = strdup(envStr);
        } else {
            gDvm.classPathStr = strdup(".");
        }
        envStr = getenv("BOOTCLASSPATH");
        if (envStr != NULL) {
            gDvm.bootClassPathStr = strdup(envStr);
        } else {
            gDvm.bootClassPathStr = strdup(".");
        }
    
        gDvm.properties = new std::vector<std::string>();
    
        /* Defaults overridden by -Xms and -Xmx.
         * TODO: base these on a system or application-specific default
         */
        gDvm.heapStartingSize = 2 * 1024 * 1024;  // Spec says 16MB; too big for us.
        gDvm.heapMaximumSize = 16 * 1024 * 1024;  // Spec says 75% physical mem
        gDvm.heapGrowthLimit = 0;  // 0 means no growth limit
        gDvm.stackSize = kDefaultStackSize;
    
        gDvm.concurrentMarkSweep = true;
    
        /* gDvm.jdwpSuspend = true; */
    

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

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

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

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

    Java代码  收藏代码
    1. { &gDvm.methDalvikSystemNativeStart_main, "Ldalvik/system/NativeStart;""main""([Ljava/lang/String;)V" },  
     { &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代码了。

  • 相关阅读:
    C# winform 数据库链接
    Second easyui框架学习
    First,映射数据库到项目
    Mybatis随笔
    spring注解简单了解
    SSH Mybatis 框架
    Maven pom.xml
    Spring
    LayaBox 摄像机Unit8Array数据获取、截图
    lvs和keepalived搭建高可用性系统
  • 原文地址:https://www.cnblogs.com/seven1979/p/4369607.html
Copyright © 2020-2023  润新知