從
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 = -;
JavaVMInitArgs initArgs;
JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
char stackTraceFileBuf[PROPERTY_VALUE_MAX];
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
char enableAssertBuf[sizeof("-ea:")- + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")- + PROPERTY_VALUE_MAX];
char heapstartsizeOptsBuf[sizeof("-Xms")- + PROPERTY_VALUE_MAX];
char heapsizeOptsBuf[sizeof("-Xmx")- + PROPERTY_VALUE_MAX];
char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")- + PROPERTY_VALUE_MAX];
char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")- + PROPERTY_VALUE_MAX];
char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")- + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")- + PROPERTY_VALUE_MAX];
char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")- + 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") == ) {
checkJni = true;
} else if (strcmp(propBuf, "false") != ) {
/* property is neither true nor false; fall back on kernel parameter */
property_get("ro.kernel.android.checkjni", propBuf, "");
if (propBuf[] == '1') {
checkJni = true;
}
}
property_get("dalvik.vm.execution-mode", propBuf, "");
if (strcmp(propBuf, "int:portable") == ) {
executionMode = kEMIntPortable;
} else if (strcmp(propBuf, "int:fast") == ) {
executionMode = kEMIntFast;
} else if (strcmp(propBuf, "int:jit") == ) {
executionMode = kEMJitCompiler;
}
property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
property_get("dalvik.vm.check-dex-sum", propBuf, "");
if (strcmp(propBuf, "true") == ) {
checkDexSum = true;
}
property_get("log.redirect-stdio", propBuf, "");
if (strcmp(propBuf, "true") == ) {
logStdio = true;
}
strcpy(enableAssertBuf, "-ea:");
property_get("dalvik.vm.enableassertions", enableAssertBuf+, "");
strcpy(jniOptsBuf, "-Xjniopts:");
property_get("dalvik.vm.jniopts", jniOptsBuf+, "");
/* 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+, "4m");
opt.optionString = heapstartsizeOptsBuf;
mOptions.add(opt);
strcpy(heapsizeOptsBuf, "-Xmx");
property_get("dalvik.vm.heapsize", heapsizeOptsBuf+, "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+, NULL);
if (jitcodecachesizeOptsBuf[] != '\0') {
opt.optionString = jitcodecachesizeOptsBuf;
mOptions.add(opt);
}
strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+, "");
if (heapgrowthlimitOptsBuf[] != '\0') {
opt.optionString = heapgrowthlimitOptsBuf;
mOptions.add(opt);
}
strcpy(heapminfreeOptsBuf, "-XX:HeapMinFree=");
property_get("dalvik.vm.heapminfree", heapminfreeOptsBuf+, "");
if (heapminfreeOptsBuf[] != '\0') {
opt.optionString = heapminfreeOptsBuf;
mOptions.add(opt);
}
strcpy(heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
property_get("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf+, "");
if (heapmaxfreeOptsBuf[] != '\0') {
opt.optionString = heapmaxfreeOptsBuf;
mOptions.add(opt);
}
strcpy(heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");
property_get("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf+, "");
if (heaptargetutilizationOptsBuf[] != '\0') {
opt.optionString = heaptargetutilizationOptsBuf;
mOptions.add(opt);
}
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == ) {
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') {
const char* opc;
const char* val;
opc = strstr(dexoptFlagsBuf, "v="); /* verification */
if (opc != NULL) {
switch (*(opc+)) {
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+)) {
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) > ) {
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) > ) {
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) > ) {
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[] != '\0') {
/* accept "all" to mean "all classes and packages" */
if (strcmp(enableAssertBuf+, "all") == )
enableAssertBuf[] = '\0';
ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);
opt.optionString = enableAssertBuf;
mOptions.add(opt);
} else {
ALOGV("Assertions disabled\n");
}
if (jniOptsBuf[] != '\0') {
ALOGI("JNI options: '%s'\n", jniOptsBuf);
opt.optionString = jniOptsBuf;
mOptions.add(opt);
}
if (stackTraceFileBuf[] != '\0') {
static const char* stfOptName = "-Xstacktracefile:";
stackTraceFile = (char*) malloc(strlen(stfOptName) +
strlen(stackTraceFileBuf) +);
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=") + ];
char regionOption[sizeof("-Duser.region=") + ];
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) < ) {
ALOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
result = ;
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, , sizeof(gDvm));
/*
* Set up structures for JNIEnv and VM.
*/
JavaVMExt* pVM = (JavaVMExt*) calloc(, sizeof(JavaVMExt));
pVM->funcTable = &gInvokeInterface;
pVM->envList = NULL;
dvmInitMutex(&pVM->envListLock);
UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
memset(argv.get(), , 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 = ;
for (int i = ; 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") == ) {
gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
} else if (strcmp(optStr, "exit") == ) {
gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
} else if (strcmp(optStr, "abort") == ) {
gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
} else if (strcmp(optStr, "sensitiveThread") == ) {
gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
} else if (strcmp(optStr, "-Xcheck:jni") == ) {
gDvmJni.useCheckJni = true;
} else if (strncmp(optStr, "-Xjniopts:", ) == ) {
char* jniOpts = strdup(optStr + );
size_t jniOptCount = ;
for (char* p = jniOpts; *p != ; ++p) {
if (*p == ',') {
++jniOptCount;
*p = ;
}
}
char* jniOpt = jniOpts;
for (size_t i = ; i < jniOptCount; ++i) {
if (strcmp(jniOpt, "warnonly") == ) {
gDvmJni.warnOnly = true;
} else if (strcmp(jniOpt, "forcecopy") == ) {
gDvmJni.forceCopy = true;
} else if (strcmp(jniOpt, "logThirdPartyJni") == ) {
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) + ;
}
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(, sizeof(JNIEnvExt));
newEnv->funcTable = &gNativeInterface;
if (self != NULL) {
dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
assert(newEnv->envThreadId != );
} else {
/* make it obvious if we fail to initialize these later */
newEnv->envThreadId = ;
newEnv->self = (Thread*) ;
}
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 = ; i < argc; i++) {
ALOGV(" %d: '%s'", i, argv[i]);
}
setCommandLineDefaults();
/*
* Process the option flags (if any).
*/
int cc = processOptions(argc, argv, ignoreUnrecognized);
if (cc != ) {
if (cc < ) {
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 = ;
} 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) != )
{
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();
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < ) {
env->PopLocalFrame(NULL);
return -;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return ;
}
startReg就是注冊一些android核心類的native函數。
流程走到這裡,dalvik虛拟機已經完成建立和初始化工作,可以開始執行java代碼了。