首页 > 代码库 > 安卓高手之路之ClassLoader(二)

安卓高手之路之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.\n");  
  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指定,在目录android40\system\core\rootdir中的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("\n>>>>>> AndroidRuntime START %s <<<<<<\n",  
  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‘\n", 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\n");  
  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‘\n", 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‘\n", 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\n");  
  102.     if (mJavaVM->DetachCurrentThread() != JNI_OK)  
  103.         LOGW("Warning: unable to detach main thread\n");  
  104.     if (mJavaVM->DestroyJavaVM() != 0)  
  105.         LOGW("Warning: VM did not shut down cleanly\n");  
  106. }  

 

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

 

Cpp代码  技术分享
  1. LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",  
  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\n");  
  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\n", 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‘\n",  
  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\n");  
  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, "\n");  
  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代码了。

安卓高手之路之ClassLoader(二)