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

  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. mArgLen = 0;
  8. for (int i=0; i<argc; i++) {
  9. mArgLen += strlen(argv[i]) + 1;
  10. }
  11. mArgLen--;
  12. AppRuntime runtime;
  13. const char* argv0 = argv[0];
  14. // Process command line arguments
  15. // ignore argv[0]
  16. argc--;
  17. argv++;
  18. // Everything up to '--' or first non '-' arg goes to the vm
  19. int i = runtime.addVmArguments(argc, argv);
  20. // Parse runtime arguments.  Stop at first unrecognized option.
  21. bool zygote = false;
  22. bool startSystemServer = false;
  23. bool application = false;
  24. const char* parentDir = NULL;
  25. const char* niceName = NULL;
  26. const char* className = NULL;
  27. while (i < argc) {
  28. const char* arg = argv[i++];
  29. if (!parentDir) {
  30. parentDir = arg;
  31. } else if (strcmp(arg, "--zygote") == 0) {
  32. zygote = true;
  33. niceName = "zygote";
  34. } else if (strcmp(arg, "--start-system-server") == 0) {
  35. startSystemServer = true;
  36. } else if (strcmp(arg, "--application") == 0) {
  37. application = true;
  38. } else if (strncmp(arg, "--nice-name=", 12) == 0) {
  39. niceName = arg + 12;
  40. } else {
  41. className = arg;
  42. break;
  43. }
  44. }
  45. if (niceName && *niceName) {
  46. setArgv0(argv0, niceName);
  47. set_process_name(niceName);
  48. }
  49. runtime.mParentDir = parentDir;
  50. if (zygote) {
  51. runtime.start("com.android.internal.os.ZygoteInit",
  52. startSystemServer ? "start-system-server" : "");
  53. } else if (className) {
  54. // Remainder of args get passed to startup class main()
  55. runtime.mClassName = className;
  56. runtime.mArgC = argc - i;
  57. runtime.mArgV = argv + i;
  58. runtime.start("com.android.internal.os.RuntimeInit",
  59. application ? "application" : "tool");
  60. } else {
  61. fprintf(stderr, "Error: no class name or --zygote supplied.\n");
  62. app_usage();
  63. LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
  64. return 10;
  65. }
  66. }

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

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,那么进入下面这句话

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

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

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

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

  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并没有指定,这句话也就相当于:

  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函数就变成:

  1. runtime.start("com.android.internal.os.ZygoteInit",  "start-system-server");

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

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

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

  1. LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
  2. className != NULL ? className : "(unknown)");
  3. blockSigpipe();

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

  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的目录

  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

  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

主要是下面这两句话

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

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

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

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

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

然后调用Jni.cpp中的

  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. //if (self != NULL)
  10. //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
  11. assert(vm != NULL);
  12. JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
  13. newEnv->funcTable = &gNativeInterface;
  14. if (self != NULL) {
  15. dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
  16. assert(newEnv->envThreadId != 0);
  17. } else {
  18. /* make it obvious if we fail to initialize these later */
  19. newEnv->envThreadId = 0x77777775;
  20. newEnv->self = (Thread*) 0x77777779;
  21. }
  22. if (gDvmJni.useCheckJni) {
  23. dvmUseCheckedJniEnv(newEnv);
  24. }
  25. ScopedPthreadMutexLock lock(&vm->envListLock);
  26. /* insert at head of list */
  27. newEnv->next = vm->envList;
  28. assert(newEnv->prev == NULL);
  29. if (vm->envList == NULL) {
  30. // rare, but possible
  31. vm->envList = newEnv;
  32. } else {
  33. vm->envList->prev = newEnv;
  34. }
  35. vm->envList = newEnv;
  36. //if (self != NULL)
  37. //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
  38. return (JNIEnv*) newEnv;
  39. }

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

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

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

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

插入代码:

  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线程的建立是在如下方法:

  1. dvmInitAfterZygote

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

  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. gDvm.loadedClasses =
  14. dvmHashTableCreate(256, (HashFreeFunc) dvmFreeClassInnards);
  15. gDvm.pBootLoaderAlloc = dvmLinearAllocCreate(NULL);
  16. if (gDvm.pBootLoaderAlloc == NULL)
  17. return false;
  18. if (false) {
  19. linearAllocTests();
  20. exit(0);
  21. }
  22. /*
  23. * Class serial number.  We start with a high value to make it distinct
  24. * in binary dumps (e.g. hprof).
  25. */
  26. gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;
  27. /*
  28. * Set up the table we'll use for tracking initiating loaders for
  29. * early classes.
  30. * If it's NULL, we just fall back to the InitiatingLoaderList in the
  31. * ClassObject, so it's not fatal to fail this allocation.
  32. */
  33. gDvm.initiatingLoaderList = (InitiatingLoaderList*)
  34. calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));
  35. /*
  36. * Create the initial classes. These are the first objects constructed
  37. * within the nascent VM.
  38. */
  39. if (!createInitialClasses()) {
  40. return false;
  41. }
  42. /*
  43. * Process the bootstrap class path.  This means opening the specified
  44. * DEX or Jar files and possibly running them through the optimizer.
  45. */
  46. assert(gDvm.bootClassPath == NULL);
  47. processClassPath(gDvm.bootClassPathStr, true);
  48. if (gDvm.bootClassPath == NULL)
  49. return false;
  50. return true;
  51. }

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

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

startVM就到这里。

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

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

回过头来继续看一下ZygoteInit.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. //if (self != NULL)
  10. //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
  11. assert(vm != NULL);
  12. JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
  13. newEnv->funcTable = &gNativeInterface;
  14. if (self != NULL) {
  15. dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
  16. assert(newEnv->envThreadId != 0);
  17. } else {
  18. /* make it obvious if we fail to initialize these later */
  19. newEnv->envThreadId = 0x77777775;
  20. newEnv->self = (Thread*) 0x77777779;
  21. }
  22. if (gDvmJni.useCheckJni) {
  23. dvmUseCheckedJniEnv(newEnv);
  24. }
  25. ScopedPthreadMutexLock lock(&vm->envListLock);
  26. /* insert at head of list */
  27. newEnv->next = vm->envList;
  28. assert(newEnv->prev == NULL);
  29. if (vm->envList == NULL) {
  30. // rare, but possible
  31. vm->envList = newEnv;
  32. } else {
  33. vm->envList->prev = newEnv;
  34. }
  35. vm->envList = newEnv;
  36. //if (self != NULL)
  37. //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
  38. return (JNIEnv*) newEnv;
  39. }

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

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

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

  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. gDvm.properties = new std::vector<std::string>();
  16. /* Defaults overridden by -Xms and -Xmx.
  17. * TODO: base these on a system or application-specific default
  18. */
  19. gDvm.heapStartingSize = 2 * 1024 * 1024;  // Spec says 16MB; too big for us.
  20. gDvm.heapMaximumSize = 16 * 1024 * 1024;  // Spec says 75% physical mem
  21. gDvm.heapGrowthLimit = 0;  // 0 means no growth limit
  22. gDvm.stackSize = kDefaultStackSize;
  23. gDvm.concurrentMarkSweep = true;
  24. /* gDvm.jdwpSuspend = true; */

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

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

  1. */
  2. f (!dvmFindRequiredClassesAndMembers()) {
  3. return "dvmFindRequiredClassesAndMembers failed";

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

  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(二)的更多相关文章

  1. 安卓高手之路之 ClassLoader

    我不喜欢那些泛泛而谈的去讲那些形而上学的道理,更不喜欢记那些既定的东西.靠记忆去弥补思考的人,容易陷入人云亦云的境地,最后必定被记忆所围困,而最终消亡的是创造力.希望这个高手之路系列能够记录我学习安卓 ...

  2. 安卓高手之路之ClassLoader(三)

    由于看C++和C代码看得很累,很辛苦.上一章终于解脱到java代码中来了. 第一个getClassLoader发生在main的preload方法中, public static void main(S ...

  3. ClassLoader使用记录《安卓高手之路》

    我不喜欢那些泛泛而谈的去讲那些形而上学的道理,更不喜欢记那些既定的东西.靠记忆去弥补思考的人,容易陷入人云亦云的境地,最后必定被记忆所围困,而最终消亡的是创造力.希望这个高手之路系列能够记录我学习安卓 ...

  4. 安卓高手之路之 WindowManager

    安卓中的画面不是纯粹由window组成.而是改成了window+view的组织模式.window是一个顶层窗口的概念.view就相当于在window内的控件.而subwindow则是依附于window ...

  5. 安卓高手之路之PackageManagerservice

    源码位置:frameworks/base/core/java/android/content/pm/PackageParser.java 源文件路径:android\frameworks\base\s ...

  6. 安卓高手之路之java层Binder

    很多人一提到Binder就说代理模式,人云亦云的多,能理解精髓的少. 本篇文章就从设计角度分析一下java层BInder的设计目标,以及设计思路,设计缺陷,从而驾驭它. 对于[邦德儿]的理解, 从通信 ...

  7. Python高手之路【十二】面向对象设计模式

    单例模式 单例,顾名思义单个实例. class Person: __instance = None def __init__(self): pass @staticmethod def getInst ...

  8. [js高手之路] html5 canvas系列教程 - arcTo(弧度与二次,三次贝塞尔曲线以及在线工具)

    之前,我写了一个arc函数的用法:[js高手之路] html5 canvas系列教程 - arc绘制曲线图形(曲线,弧线,圆形). arcTo: cxt.arcTo( cx, cy, x2, y2, ...

  9. [js高手之路]从原型链开始图解继承到组合继承的产生

    基于javascript原型链的层层递进查找规则,以及原型对象(prototype)的共享特性,实现继承是非常简单的事情 一.把父类的实例对象赋给子类的原型对象(prototype),可以实现继承 f ...

随机推荐

  1. IIS 7.5: HOW TO ENABLE TLS 1.1 AND TLS 1.2

    In IIS 7.5, which is installed on Windows 2008 R2 servers, only SSL 3.0 and TLS 1.0 are enabled for ...

  2. 怎样编写YARN应用程序

    (注意:本文的分析基于Hadoop trunk上的"Revision 1452188"版本号,详细可參考:http://svn.apache.org/repos/asf/hadoo ...

  3. linux mount

    挂载       mount //10.65.200.168/linux_bj /home/linux_bj -t cifs -o username=niu,password=ruanxiaopang ...

  4. 小教程:自己创建一个jQuery长阴影插件

    长阴影设计是平面设计的一个变体,添加了阴影,产生了深度的幻觉,并导致了三维的设计.在本教程中,我们将创建一个jQuery插件,通过添加完全可自定义的长阴影图标,我们可以轻松地转换平面图标. 戳我查看效 ...

  5. ArcGIS Add-in ValidateAddInXMLTask”任务意外失败

    晚上收假回来调一Add-In程序,遇到编译错误:"ValidateAddInXMLTask"任务意外失败. error MSB4018: System.IO.FileNotFoun ...

  6. ADHOC Report 配置

    ADHOC Report ADHOC Report - 临时的report,随时可以去系统中按照你选择的条件打出你想看的report Add ADHOC Report --AddReport use ...

  7. 算法笔记_228:信用卡号校验(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证 ...

  8. 路由器mtu值设置

    MTU=最大传输单元 单位:字节 英文:Maximum Transmission Unit”我们平时上网时的各种操作,都是通过一个又一个“数据包”传输来实现的.而MTU指定了网络中可传输数据包的最大尺 ...

  9. SSM实战——秒杀系统之高并发优化

    一:高并发点 高并发出现在秒杀详情页,主要可能出现高并发问题的地方有:秒杀地址暴露.执行秒杀操作. 二:静态资源访问(页面)优化——CDN CDN,内容分发网络.我们把静态的资源(html/css/j ...

  10. Kinect2.0获取关节姿态(Joint Orientation)

    Bones Hierarchy 骨骼层次结构从SpineBase作为根节点开始,一直延伸到肢体末端(头.指尖.脚): 层级结构如下图所示: 通过IBody::GetJointOrientations函 ...