从Zygote进程启动过程
分析过程中,我们知道,dalvik虚拟机的启动过程是从AndroidRuntime::startVm(JavaVM**
函数开始的,详细时序图如下:
pJavaVM, JNIEnv** pEnv)
下面我们来逐步详细地分析一下每个步骤。
1.startVm(AndroidRuntime.cpp)
/*
* Start the Dalvik Virtual Machine.
*
* Various arguments, most determined by system properties, are passed in.
* The "mOptions" vector is updated.
*
* Returns 0 on success.
*/
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
int result = -1;
JavaVMInitArgs initArgs;
JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
char stackTraceFileBuf[PROPERTY_VALUE_MAX];
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
bool checkJni = false;
bool checkDexSum = false;
bool logStdio = false;
enum {
kEMDefault,
kEMIntPortable,
kEMIntFast,
kEMJitCompiler,
} executionMode = kEMDefault;
property_get("dalvik.vm.checkjni", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
checkJni = true;
} else if (strcmp(propBuf, "false") != 0) {
/* property is neither true nor false; fall back on kernel parameter */
property_get("ro.kernel.android.checkjni", propBuf, "");
if (propBuf[0] == ‘1‘) {
checkJni = true;
}
}
property_get("dalvik.vm.execution-mode", propBuf, "");
if (strcmp(propBuf, "int:portable") == 0) {
executionMode = kEMIntPortable;
} else if (strcmp(propBuf, "int:fast") == 0) {
executionMode = kEMIntFast;
} else if (strcmp(propBuf, "int:jit") == 0) {
executionMode = kEMJitCompiler;
}
property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
property_get("dalvik.vm.check-dex-sum", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
checkDexSum = true;
}
property_get("log.redirect-stdio", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
logStdio = true;
}
strcpy(enableAssertBuf, "-ea:");
property_get("dalvik.vm.enableassertions", enableAssertBuf+4, "");
strcpy(jniOptsBuf, "-Xjniopts:");
property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");
/* route exit() to our handler */
opt.extraInfo = (void*) runtime_exit;
opt.optionString = "exit";
mOptions.add(opt);
/* route fprintf() to our handler */
opt.extraInfo = (void*) runtime_vfprintf;
opt.optionString = "vfprintf";
mOptions.add(opt);
/* register the framework-specific "is sensitive thread" hook */
opt.extraInfo = (void*) runtime_isSensitiveThread;
opt.optionString = "sensitiveThread";
mOptions.add(opt);
opt.extraInfo = NULL;
/* enable verbose; standard options are { jni, gc, class } */
//options[curOpt++].optionString = "-verbose:jni";
opt.optionString = "-verbose:gc";
mOptions.add(opt);
//options[curOpt++].optionString = "-verbose:class";
/*
* The default starting and maximum size of the heap. Larger
* values should be specified in a product property override.
*/
strcpy(heapstartsizeOptsBuf, "-Xms");
property_get("dalvik.vm.heapstartsize", heapstartsizeOptsBuf+4, "4m");
opt.optionString = heapstartsizeOptsBuf;
mOptions.add(opt);
strcpy(heapsizeOptsBuf, "-Xmx");
property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
// Increase the main thread‘s interpreter stack size for bug 6315322.
opt.optionString = "-XX:mainThreadStackSize=24K";
mOptions.add(opt);
// Set the max jit code cache size. Note: size of 0 will disable the JIT.
strcpy(jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
property_get("dalvik.vm.jit.codecachesize", jitcodecachesizeOptsBuf+19, NULL);
if (jitcodecachesizeOptsBuf[19] != ‘\0‘) {
opt.optionString = jitcodecachesizeOptsBuf;
mOptions.add(opt);
}
strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, "");
if (heapgrowthlimitOptsBuf[20] != ‘\0‘) {
opt.optionString = heapgrowthlimitOptsBuf;
mOptions.add(opt);
}
strcpy(heapminfreeOptsBuf, "-XX:HeapMinFree=");
property_get("dalvik.vm.heapminfree", heapminfreeOptsBuf+16, "");
if (heapminfreeOptsBuf[16] != ‘\0‘) {
opt.optionString = heapminfreeOptsBuf;
mOptions.add(opt);
}
strcpy(heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
property_get("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf+16, "");
if (heapmaxfreeOptsBuf[16] != ‘\0‘) {
opt.optionString = heapmaxfreeOptsBuf;
mOptions.add(opt);
}
strcpy(heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");
property_get("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf+26, "");
if (heaptargetutilizationOptsBuf[26] != ‘\0‘) {
opt.optionString = heaptargetutilizationOptsBuf;
mOptions.add(opt);
}
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
opt.optionString = "-XX:LowMemoryMode";
mOptions.add(opt);
}
/*
* Enable or disable dexopt features, such as bytecode verification and
* calculation of register maps for precise GC.
*/
property_get("dalvik.vm.dexopt-flags", dexoptFlagsBuf, "");
if (dexoptFlagsBuf[0] != ‘\0‘) {
const char* opc;
const char* val;
opc = strstr(dexoptFlagsBuf, "v="); /* verification */
if (opc != NULL) {
switch (*(opc+2)) {
case ‘n‘: val = "-Xverify:none"; break;
case ‘r‘: val = "-Xverify:remote"; break;
case ‘a‘: val = "-Xverify:all"; break;
default: val = NULL; break;
}
if (val != NULL) {
opt.optionString = val;
mOptions.add(opt);
}
}
opc = strstr(dexoptFlagsBuf, "o="); /* optimization */
if (opc != NULL) {
switch (*(opc+2)) {
case ‘n‘: val = "-Xdexopt:none"; break;
case ‘v‘: val = "-Xdexopt:verified"; break;
case ‘a‘: val = "-Xdexopt:all"; break;
case ‘f‘: val = "-Xdexopt:full"; break;
default: val = NULL; break;
}
if (val != NULL) {
opt.optionString = val;
mOptions.add(opt);
}
}
opc = strstr(dexoptFlagsBuf, "m=y"); /* register map */
if (opc != NULL) {
opt.optionString = "-Xgenregmap";
mOptions.add(opt);
/* turn on precise GC while we‘re at it */
opt.optionString = "-Xgc:precise";
mOptions.add(opt);
}
}
/* enable debugging; set suspend=y to pause during VM init */
/* use android ADB transport */
opt.optionString =
"-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
mOptions.add(opt);
ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
/* extended JNI checking */
opt.optionString = "-Xcheck:jni";
mOptions.add(opt);
/* set a cap on JNI global references */
opt.optionString = "-Xjnigreflimit:2000";
mOptions.add(opt);
/* with -Xcheck:jni, this provides a JNI function call trace */
//opt.optionString = "-verbose:jni";
//mOptions.add(opt);
}
char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)];
property_get("dalvik.vm.lockprof.threshold", propBuf, "");
if (strlen(propBuf) > 0) {
strcpy(lockProfThresholdBuf, "-Xlockprofthreshold:");
strcat(lockProfThresholdBuf, propBuf);
opt.optionString = lockProfThresholdBuf;
mOptions.add(opt);
}
/* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX];
property_get("dalvik.vm.jit.op", propBuf, "");
if (strlen(propBuf) > 0) {
strcpy(jitOpBuf, "-Xjitop:");
strcat(jitOpBuf, propBuf);
opt.optionString = jitOpBuf;
mOptions.add(opt);
}
/* Force interpreter-only mode for selected methods */
char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX];
property_get("dalvik.vm.jit.method", propBuf, "");
if (strlen(propBuf) > 0) {
strcpy(jitMethodBuf, "-Xjitmethod:");
strcat(jitMethodBuf, propBuf);
opt.optionString = jitMethodBuf;
mOptions.add(opt);
}
if (executionMode == kEMIntPortable) {
opt.optionString = "-Xint:portable";
mOptions.add(opt);
} else if (executionMode == kEMIntFast) {
opt.optionString = "-Xint:fast";
mOptions.add(opt);
} else if (executionMode == kEMJitCompiler) {
opt.optionString = "-Xint:jit";
mOptions.add(opt);
}
if (checkDexSum) {
/* perform additional DEX checksum tests */
opt.optionString = "-Xcheckdexsum";
mOptions.add(opt);
}
if (logStdio) {
/* convert stdout/stderr to log messages */
opt.optionString = "-Xlog-stdio";
mOptions.add(opt);
}
if (enableAssertBuf[4] != ‘\0‘) {
/* accept "all" to mean "all classes and packages" */
if (strcmp(enableAssertBuf+4, "all") == 0)
enableAssertBuf[3] = ‘\0‘;
ALOGI("Assertions enabled: ‘%s‘\n", enableAssertBuf);
opt.optionString = enableAssertBuf;
mOptions.add(opt);
} else {
ALOGV("Assertions disabled\n");
}
if (jniOptsBuf[10] != ‘\0‘) {
ALOGI("JNI options: ‘%s‘\n", jniOptsBuf);
opt.optionString = jniOptsBuf;
mOptions.add(opt);
}
if (stackTraceFileBuf[0] != ‘\0‘) {
static const char* stfOptName = "-Xstacktracefile:";
stackTraceFile = (char*) malloc(strlen(stfOptName) +
strlen(stackTraceFileBuf) +1);
strcpy(stackTraceFile, stfOptName);
strcat(stackTraceFile, stackTraceFileBuf);
opt.optionString = stackTraceFile;
mOptions.add(opt);
}
/* extra options; parse this late so it overrides others */
property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
parseExtraOpts(extraOptsBuf);
/* Set the properties for locale */
{
char langOption[sizeof("-Duser.language=") + 3];
char regionOption[sizeof("-Duser.region=") + 3];
strcpy(langOption, "-Duser.language=");
strcpy(regionOption, "-Duser.region=");
readLocale(langOption, regionOption);
opt.extraInfo = NULL;
opt.optionString = langOption;
mOptions.add(opt);
opt.optionString = regionOption;
mOptions.add(opt);
}
/*
* We don‘t have /tmp on the device, but we often have an SD card. Apps
* shouldn‘t use this, but some test suites might want to exercise it.
*/
opt.optionString = "-Djava.io.tmpdir=/sdcard";
mOptions.add(opt);
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
result = 0;
bail:
free(stackTraceFile);
return result;
}
startVm的大部分逻辑是在收集虚拟机的配置参数,并将这些配置信心存储到mOptions中,接着将mOptions收集的配置信息赋值给initArgs,initArgs是一个JavaVMInitArgs的对象,从名字就可以猜到该对象管理着虚拟机初始化需要的参数。收集好初始化参数后,就调用JNI_CreateJavaVM开始真刀真枪地创建虚拟机了。
2.JNI_CreateJavaVM(Jni.cpp)
/*
* Create a new VM instance.
*
* The current thread becomes the main VM thread. We return immediately,
* which effectively means the caller is executing in a native method.
*/
jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
if (dvmIsBadJniVersion(args->version)) {
ALOGE("Bad JNI version passed to CreateJavaVM: %d", args->version);
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*) calloc(1, 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\n", 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‘\n",
jniOpt);
free(pVM);
free(jniOpts);
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\n");
free(pVM);
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);
ALOGW("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;
ALOGV("CreateJavaVM succeeded");
return JNI_OK;
}
JNI_CreateJavaVM的逻辑可以分为4步
1.创建JavaVMExt对象,并初始化;
2.将部分初始化参数存储到全局对象gDvm和gDvmJni中,方便后续需要的时候直接从gDvm和gDvmJni中读取;部分初始化参数存储到argv中,供第四步dvmStartup使用;
3.调用dvmCreateJNIEnv创建JNIEnvExt对象,该对象就是主线程的JNIEnv对象;
4.调用dvmStartup启动虚拟机的各个模块;此致,虚拟机的创建工作基本完成。
这里有几个问题是值得我们注意的:
JavaVM和JNIEnv的作用
JavaVM就是虚拟机对象,它的作用简单说就是解释执行java代码,每个android app进程都会有一个虚拟机实例;JNIEnv是与线程相关的对象,每个线程对应一个JNIEnv对象,它是native世界与java世界的桥梁,native通过JNIEnv提供的接口来访问java世界。
JavaVMExt与JavaVM的关系
从文章dalvik核心数据结构我们可以看到,JavaVM其实就是一个JNIInvokeInterface的指针,JNIInvokeInterface定义了一些虚拟机操作相关的函数,JavaVMExt是JavaVM的扩展,它的第一个成员也是一个JNIInvokeInterface的指针,另外扩展了几个成员,对于开发者来说,一般是通过JavaVM来调用相关接口,而不用关注JavaVMExt是如何实现这些接口的。
JNIEnvExt与JNIEnv的关系
JNIEnvExt与JNIEnv的关系,跟JavaVMExt与JavaVM的关系是类似的,JNIEnv提供的接口定义在JNINativeInterface结构体中。
3.dvmCreateJNIEnv(Jni.cpp)
/*
* 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)
// ALOGI("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)
// ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
return (JNIEnv*) newEnv;
}
dvmCreateJNIEnv的逻辑比较简单,就是单纯地创建JNIEnvExt并初始化,最后返回新创建的JNIEnvExt对象;envThreadId和self分辨赋值为0x77777775和0x77777779,这两个值表示该JNIEnvExt还未和任何线程绑定。
4.dvmStartup(Init.cpp)
/*
* 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);
ALOGV("VM init args (%d):", argc);
for (int i = 0; i < argc; i++) {
ALOGV(" %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, "\n");
usage("dalvikvm");
}
return "syntax error";
}
#if WITH_EXTRA_GC_CHECKS > 1
/* only "portable" interp has the extra goodies */
if (gDvm.executionMode != kExecutionModeInterpPortable) {
ALOGI("Switching to ‘portable‘ interpreter for GC checks");
gDvm.executionMode = kExecutionModeInterpPortable;
}
#endif
/* Configure group scheduling capabilities */
if (!access("/dev/cpuctl/tasks", F_OK)) {
ALOGV("Using kernel group scheduling");
gDvm.kernelGroupScheduling = 1;
} else {
ALOGV("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 */
ALOGV("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)
{
ALOGW("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())
ALOGE("dvmTestHash FAILED");
if (false /*noisy!*/ && !dvmTestIndirectRefTable())
ALOGE("dvmTestIndirectRefTable FAILED");
#endif
if (dvmCheckException(dvmThreadSelf())) {
dvmLogExceptionStackTrace();
return "Exception pending at end of VM initialization";
}
scopedShutdown.disarm();
return "";
}
dvmStartup主要是启动dalvik虚拟机的各个子模块,具体每个子模块的作用可以参考Dalvik虚拟机的启动过程分析。
至此,dalvik虚拟机已经完成了模块初始化。
5.startReg(AndroidRuntime.cpp)
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven‘t really
* started the VM yet, they‘re all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
startReg就是注册一些android核心类的native函数。
流程走到这里,dalvik虚拟机已经完成创建和初始化工作,可以开始执行java代码了。