Android系统的zygote启动
Android系统boot启动进入kernel,后启动init进程,开始解析init.rc文件,当解析到zygoter就开始启动zygote进程。
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
priority -20
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
(一)首先调用app_process.cpp中main函数
int main(int argc, char* const argv[])
{
#ifdef __arm__
/*
* b/7188322 - Temporarily revert to the compat memory layout
* to avoid breaking third party apps.
*
* THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
*
* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
* changes the kernel mapping from bottom up to top-down.
* This breaks some programs which improperly embed
* an out of date copy of Android's linker.
*/
char value[PROPERTY_VALUE_MAX];
property_get("ro.kernel.qemu", value, "");
bool is_qemu = (strcmp(value, "1") == 0);
if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {
int current = personality(0xFFFFFFFF);
if ((current & ADDR_COMPAT_LAYOUT) == 0) {
personality(current | ADDR_COMPAT_LAYOUT);
setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
execv("/system/bin/app_process", argv);
return -1;
}
}
unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
#endif
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
mArgLen = 0;
for (int i=0; i<argc; i++) {
mArgLen += strlen(argv[i]) + 1;
}
mArgLen--;
AppRuntime runtime;
const char* argv0 = argv[0];
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// Everything up to '--' or first non '-' arg goes to the vm
int i = runtime.addVmArguments(argc, argv);
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
const char* parentDir = NULL;
const char* niceName = NULL;
const char* className = NULL;
while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg;
} else if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = "zygote";
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName = arg + 12;
} else {
className = arg;
break;
}
}
if (niceName && *niceName) {
setArgv0(argv0, niceName);
set_process_name(niceName);
}
runtime.mParentDir = parentDir;
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
} else if (className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ? "application" : "tool");
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}
因为传入参数为zygote,start-system-server参数,得到zygote = true, startSystemServer = true,调用runtime的start方法,runtime是AppRuntime定义变量,并且继承AndroidRuntime,调用AndroidRuntime的start方法,并传入字符串参数“com.android.internal.os.ZygoteInit”, “start-system-server”
void AndroidRuntime::start(const char* className, const char* options)
{
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)");
/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
if (strcmp(options, "start-system-server") == 0) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring optionsStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
optionsStr = env->NewStringUTF(options);
env->SetObjectArrayElement(strArray, 1, optionsStr);
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
1)在AndroidRuntime中的main函数中调用JniInvocation的init方法,可以看到此方法去加载了libdvm.so库,并检查库中一些重要方法入口,需要注意JNI_CreateJavaVM方法;
bool JniInvocation::Init(const char* library) {
#ifdef HAVE_ANDROID_OS
char default_library[PROPERTY_VALUE_MAX];
property_get(kLibrarySystemProperty, default_library, kLibraryFallback);
#else
const char* default_library = kLibraryFallback;
#endif
if (library == NULL) {
library = default_library;
}
handle_ = dlopen(library, RTLD_NOW);
if (handle_ == NULL) {
if (strcmp(library, kLibraryFallback) == 0) {
// Nothing else to try.
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
// Note that this is enough to get something like the zygote
// running, we can't property_set here to fix this for the future
// because we are root and not the system user. See
// RuntimeInit.commonInit for where we fix up the property to
// avoid future fallbacks. http://b/11463182
ALOGW("Falling back from %s to %s after dlopen error: %s",
library, kLibraryFallback, dlerror());
library = kLibraryFallback;
handle_ = dlopen(library, RTLD_NOW);
if (handle_ == NULL) {
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
2)调用startVm方法
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;
}
此方法开始初始化一堆虚拟机相关的参数,开始调用Jni.cpp方法JNI_CreateJavaVM方法创建java虚拟机。
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;
}
通过dvmCreateJNIEnv创建jniEnv环境变量,并调用dvmStartup开始启动虚拟机;
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 "";
}
此方法中调用setCommandLineDefaults方法初始化android核心jar路径,并且保存到全局变量gDvm.classPathStr中,并且初始化了一系列虚拟机默认参数,java堆栈大小等等,后面调用processOptions方法,部分参数会更加输参数虚拟机参数修改;
static void setCommandLineDefaults()
{
const char* envStr = getenv("CLASSPATH");
if (envStr != NULL) {
gDvm.classPathStr = strdup(envStr);
} else {
gDvm.classPathStr = strdup(".");
}
envStr = getenv("BOOTCLASSPATH");
if (envStr != NULL) {
gDvm.bootClassPathStr = strdup(envStr);
} else {
gDvm.bootClassPathStr = strdup(".");
}
gDvm.properties = new std::vector<std::string>();
/* Defaults overridden by -Xms and -Xmx.
* TODO: base these on a system or application-specific default
*/
gDvm.heapStartingSize = 2 * 1024 * 1024; // Spec says 16MB; too big for us.
gDvm.heapMaximumSize = 16 * 1024 * 1024; // Spec says 75% physical mem
gDvm.heapGrowthLimit = 0; // 0 means no growth limit
gDvm.lowMemoryMode = false;
gDvm.stackSize = kDefaultStackSize;
gDvm.mainThreadStackSize = kDefaultStackSize;
// When the heap is less than the maximum or growth limited size,
// fix the free portion of the heap. The utilization is the ratio
// of live to free memory, 0.5 implies half the heap is available
// to allocate into before a GC occurs. Min free and max free
// force the free memory to never be smaller than min free or
// larger than max free.
gDvm.heapTargetUtilization = 0.5;
gDvm.heapMaxFree = 2 * 1024 * 1024;
gDvm.heapMinFree = gDvm.heapMaxFree / 4;
gDvm.concurrentMarkSweep = true;
/* gDvm.jdwpSuspend = true; */
/* allowed unless zygote config doesn't allow it */
gDvm.jdwpAllowed = true;
/* default verification and optimization modes */
gDvm.classVerifyMode = VERIFY_MODE_ALL;
gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
gDvm.monitorVerification = false;
gDvm.generateRegisterMaps = true;
gDvm.registerMapMode = kRegisterMapModeTypePrecise;
/*
* Default execution mode.
*
* This should probably interact with the mterp code somehow, e.g. if
* we know we're using the "desktop" build we should probably be
* using "portable" rather than "fast".
*/
#if defined(WITH_JIT)
gDvm.executionMode = kExecutionModeJit;
gDvmJit.num_entries_pcTable = 0;
gDvmJit.includeSelectedMethod = false;
gDvmJit.includeSelectedOffset = false;
gDvmJit.methodTable = NULL;
gDvmJit.classTable = NULL;
gDvmJit.codeCacheSize = DEFAULT_CODE_CACHE_SIZE;
gDvm.constInit = false;
gDvm.commonInit = false;
#else
gDvm.executionMode = kExecutionModeInterpFast;
#endif
/*
* SMP support is a compile-time define, but we may want to have
* dexopt target a differently-configured device.
*/
gDvm.dexOptForSmp = (ANDROID_SMP != 0);
/*
* Default profiler configuration.
*/
gDvm.profilerClockSource = kProfilerClockSourceDual;
}
static int processOptions(int argc, const char* const argv[],
bool ignoreUnrecognized)
{
int i;
ALOGV("VM options (%d):", argc);
for (i = 0; i < argc; i++)
ALOGV(" %d: '%s'", i, argv[i]);
/*
* Over-allocate AssertionControl array for convenience. If allocated,
* the array must be able to hold at least one entry, so that the
* zygote-time activation can do its business.
*/
assert(gDvm.assertionCtrl == NULL);
if (argc > 0) {
gDvm.assertionCtrl =
(AssertionControl*) malloc(sizeof(AssertionControl) * argc);
if (gDvm.assertionCtrl == NULL)
return -1;
assert(gDvm.assertionCtrlCount == 0);
}
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "-help") == 0) {
/* show usage and stop */
return -1;
} else if (strcmp(argv[i], "-version") == 0) {
/* show version and stop */
showVersion();
return 1;
} else if (strcmp(argv[i], "-showversion") == 0) {
/* show version and continue */
showVersion();
} else if (strcmp(argv[i], "-classpath") == 0 ||
strcmp(argv[i], "-cp") == 0)
{
/* set classpath */
if (i == argc-1) {
dvmFprintf(stderr, "Missing classpath path list\n");
return -1;
}
free(gDvm.classPathStr); /* in case we have compiled-in default */
gDvm.classPathStr = strdup(argv[++i]);
} else if (strncmp(argv[i], "-Xbootclasspath:",
sizeof("-Xbootclasspath:")-1) == 0)
{
/* set bootclasspath */
const char* path = argv[i] + sizeof("-Xbootclasspath:")-1;
if (*path == '\0') {
dvmFprintf(stderr, "Missing bootclasspath path list\n");
return -1;
}
free(gDvm.bootClassPathStr);
gDvm.bootClassPathStr = strdup(path);
} else if (strncmp(argv[i], "-Xbootclasspath/a:",
sizeof("-Xbootclasspath/a:")-1) == 0) {
const char* appPath = argv[i] + sizeof("-Xbootclasspath/a:")-1;
if (*(appPath) == '\0') {
dvmFprintf(stderr, "Missing appending bootclasspath path list\n");
return -1;
}
char* allPath;
if (asprintf(&allPath, "%s:%s", gDvm.bootClassPathStr, appPath) < 0) {
dvmFprintf(stderr, "Can't append to bootclasspath path list\n");
return -1;
}
free(gDvm.bootClassPathStr);
gDvm.bootClassPathStr = allPath;
} else if (strncmp(argv[i], "-Xbootclasspath/p:",
sizeof("-Xbootclasspath/p:")-1) == 0) {
const char* prePath = argv[i] + sizeof("-Xbootclasspath/p:")-1;
if (*(prePath) == '\0') {
dvmFprintf(stderr, "Missing prepending bootclasspath path list\n");
return -1;
}
char* allPath;
if (asprintf(&allPath, "%s:%s", prePath, gDvm.bootClassPathStr) < 0) {
dvmFprintf(stderr, "Can't prepend to bootclasspath path list\n");
return -1;
}
free(gDvm.bootClassPathStr);
gDvm.bootClassPathStr = allPath;
} else if (strncmp(argv[i], "-D", 2) == 0) {
/* Properties are handled in managed code. We just check syntax. */
if (strchr(argv[i], '=') == NULL) {
dvmFprintf(stderr, "Bad system property setting: \"%s\"\n",
argv[i]);
return -1;
}
gDvm.properties->push_back(argv[i] + 2);
} else if (strcmp(argv[i], "-jar") == 0) {
// TODO: handle this; name of jar should be in argv[i+1]
dvmFprintf(stderr, "-jar not yet handled\n");
assert(false);
} else if (strncmp(argv[i], "-Xms", 4) == 0) {
size_t val = parseMemOption(argv[i]+4, 1024);
if (val != 0) {
if (val >= kMinHeapStartSize && val <= kMaxHeapSize) {
gDvm.heapStartingSize = val;
} else {
dvmFprintf(stderr,
"Invalid -Xms '%s', range is %dKB to %dKB\n",
argv[i], kMinHeapStartSize/1024, kMaxHeapSize/1024);
return -1;
}
} else {
dvmFprintf(stderr, "Invalid -Xms option '%s'\n", argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-Xmx", 4) == 0) {
size_t val = parseMemOption(argv[i]+4, 1024);
if (val != 0) {
if (val >= kMinHeapSize && val <= kMaxHeapSize) {
gDvm.heapMaximumSize = val;
} else {
dvmFprintf(stderr,
"Invalid -Xmx '%s', range is %dKB to %dKB\n",
argv[i], kMinHeapSize/1024, kMaxHeapSize/1024);
return -1;
}
} else {
dvmFprintf(stderr, "Invalid -Xmx option '%s'\n", argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-XX:HeapGrowthLimit=", 20) == 0) {
size_t val = parseMemOption(argv[i] + 20, 1024);
if (val != 0) {
gDvm.heapGrowthLimit = val;
} else {
dvmFprintf(stderr, "Invalid -XX:HeapGrowthLimit option '%s'\n", argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-XX:HeapMinFree=", 16) == 0) {
size_t val = parseMemOption(argv[i] + 16, 1024);
if (val != 0) {
gDvm.heapMinFree = val;
} else {
dvmFprintf(stderr, "Invalid -XX:HeapMinFree option '%s'\n", argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-XX:HeapMaxFree=", 16) == 0) {
size_t val = parseMemOption(argv[i] + 16, 1024);
if (val != 0) {
gDvm.heapMaxFree = val;
} else {
dvmFprintf(stderr, "Invalid -XX:HeapMaxFree option '%s'\n", argv[i]);
return -1;
}
} else if (strcmp(argv[i], "-XX:LowMemoryMode") == 0) {
gDvm.lowMemoryMode = true;
} else if (strncmp(argv[i], "-XX:HeapTargetUtilization=", 26) == 0) {
const char* start = argv[i] + 26;
const char* end = start;
double val = strtod(start, const_cast<char**>(&end));
// Ensure that we have a value, there was no cruft after it and it
// satisfies a sensible range.
bool sane_val = (start != end) && (end[0] == '\0') &&
(val >= 0.1) && (val <= 0.9);
if (sane_val) {
gDvm.heapTargetUtilization = val;
} else {
dvmFprintf(stderr, "Invalid -XX:HeapTargetUtilization option '%s'\n", argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-Xss", 4) == 0) {
size_t val = parseMemOption(argv[i]+4, 1);
if (val != 0) {
if (val >= kMinStackSize && val <= kMaxStackSize) {
gDvm.stackSize = val;
if (val > gDvm.mainThreadStackSize) {
gDvm.mainThreadStackSize = val;
}
} else {
dvmFprintf(stderr, "Invalid -Xss '%s', range is %d to %d\n",
argv[i], kMinStackSize, kMaxStackSize);
return -1;
}
} else {
dvmFprintf(stderr, "Invalid -Xss option '%s'\n", argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-XX:mainThreadStackSize=", strlen("-XX:mainThreadStackSize=")) == 0) {
size_t val = parseMemOption(argv[i] + strlen("-XX:mainThreadStackSize="), 1);
if (val != 0) {
if (val >= kMinStackSize && val <= kMaxStackSize) {
gDvm.mainThreadStackSize = val;
} else {
dvmFprintf(stderr, "Invalid -XX:mainThreadStackSize '%s', range is %d to %d\n",
argv[i], kMinStackSize, kMaxStackSize);
return -1;
}
} else {
dvmFprintf(stderr, "Invalid -XX:mainThreadStackSize option '%s'\n", argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-XX:+DisableExplicitGC", 22) == 0) {
gDvm.disableExplicitGc = true;
} else if (strcmp(argv[i], "-verbose") == 0 ||
strcmp(argv[i], "-verbose:class") == 0)
{
// JNI spec says "-verbose:gc,class" is valid, but cmd line
// doesn't work that way; may want to support.
gDvm.verboseClass = true;
} else if (strcmp(argv[i], "-verbose:jni") == 0) {
gDvm.verboseJni = true;
} else if (strcmp(argv[i], "-verbose:gc") == 0) {
gDvm.verboseGc = true;
} else if (strcmp(argv[i], "-verbose:shutdown") == 0) {
gDvm.verboseShutdown = true;
} else if (strncmp(argv[i], "-enableassertions", 17) == 0) {
enableAssertions(argv[i] + 17, true);
} else if (strncmp(argv[i], "-ea", 3) == 0) {
enableAssertions(argv[i] + 3, true);
} else if (strncmp(argv[i], "-disableassertions", 18) == 0) {
enableAssertions(argv[i] + 18, false);
} else if (strncmp(argv[i], "-da", 3) == 0) {
enableAssertions(argv[i] + 3, false);
} else if (strcmp(argv[i], "-enablesystemassertions") == 0 ||
strcmp(argv[i], "-esa") == 0)
{
enableAssertions(NULL, true);
} else if (strcmp(argv[i], "-disablesystemassertions") == 0 ||
strcmp(argv[i], "-dsa") == 0)
{
enableAssertions(NULL, false);
} else if (strncmp(argv[i], "-Xcheck:jni", 11) == 0) {
/* nothing to do now -- was handled during JNI init */
} else if (strcmp(argv[i], "-Xdebug") == 0) {
/* accept but ignore */
} else if (strncmp(argv[i], "-Xrunjdwp:", 10) == 0 ||
strncmp(argv[i], "-agentlib:jdwp=", 15) == 0)
{
const char* tail;
if (argv[i][1] == 'X')
tail = argv[i] + 10;
else
tail = argv[i] + 15;
if (strncmp(tail, "help", 4) == 0 || !parseJdwpOptions(tail)) {
showJdwpHelp();
return 1;
}
} else if (strcmp(argv[i], "-Xrs") == 0) {
gDvm.reduceSignals = true;
} else if (strcmp(argv[i], "-Xnoquithandler") == 0) {
/* disables SIGQUIT handler thread while still blocking SIGQUIT */
/* (useful if we don't want thread but system still signals us) */
gDvm.noQuitHandler = true;
} else if (strcmp(argv[i], "-Xzygote") == 0) {
gDvm.zygote = true;
#if defined(WITH_JIT)
gDvmJit.runningInAndroidFramework = true;
#endif
} else if (strncmp(argv[i], "-Xdexopt:", 9) == 0) {
if (strcmp(argv[i] + 9, "none") == 0)
gDvm.dexOptMode = OPTIMIZE_MODE_NONE;
else if (strcmp(argv[i] + 9, "verified") == 0)
gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
else if (strcmp(argv[i] + 9, "all") == 0)
gDvm.dexOptMode = OPTIMIZE_MODE_ALL;
else if (strcmp(argv[i] + 9, "full") == 0)
gDvm.dexOptMode = OPTIMIZE_MODE_FULL;
else {
dvmFprintf(stderr, "Unrecognized dexopt option '%s'\n",argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-Xverify:", 9) == 0) {
if (strcmp(argv[i] + 9, "none") == 0)
gDvm.classVerifyMode = VERIFY_MODE_NONE;
else if (strcmp(argv[i] + 9, "remote") == 0)
gDvm.classVerifyMode = VERIFY_MODE_REMOTE;
else if (strcmp(argv[i] + 9, "all") == 0)
gDvm.classVerifyMode = VERIFY_MODE_ALL;
else {
dvmFprintf(stderr, "Unrecognized verify option '%s'\n",argv[i]);
return -1;
}
} else if (strncmp(argv[i], "-Xjnigreflimit:", 15) == 0) {
// Ignored for backwards compatibility.
} else if (strncmp(argv[i], "-Xjnitrace:", 11) == 0) {
gDvm.jniTrace = strdup(argv[i] + 11);
} else if (strcmp(argv[i], "-Xlog-stdio") == 0) {
gDvm.logStdio = true;
} else if (strncmp(argv[i], "-Xint", 5) == 0) {
if (argv[i][5] == ':') {
if (strcmp(argv[i] + 6, "portable") == 0)
gDvm.executionMode = kExecutionModeInterpPortable;
else if (strcmp(argv[i] + 6, "fast") == 0)
gDvm.executionMode = kExecutionModeInterpFast;
#ifdef WITH_JIT
else if (strcmp(argv[i] + 6, "jit") == 0)
gDvm.executionMode = kExecutionModeJit;
#endif
else {
dvmFprintf(stderr,
"Warning: Unrecognized interpreter mode %s\n",argv[i]);
/* keep going */
}
} else {
/* disable JIT if it was enabled by default */
gDvm.executionMode = kExecutionModeInterpFast;
}
} else if (strncmp(argv[i], "-Xlockprofthreshold:", 20) == 0) {
gDvm.lockProfThreshold = atoi(argv[i] + 20);
#ifdef WITH_JIT
} else if (strncmp(argv[i], "-Xjitop", 7) == 0) {
processXjitop(argv[i]);
} else if (strncmp(argv[i], "-Xjitmethod:", 12) == 0) {
processXjitmethod(argv[i] + strlen("-Xjitmethod:"), true);
} else if (strncmp(argv[i], "-Xjitclass:", 11) == 0) {
processXjitmethod(argv[i] + strlen("-Xjitclass:"), false);
} else if (strncmp(argv[i], "-Xjitoffset:", 12) == 0) {
processXjitoffset(argv[i] + strlen("-Xjitoffset:"));
} else if (strncmp(argv[i], "-Xjitconfig:", 12) == 0) {
processXjitconfig(argv[i] + strlen("-Xjitconfig:"));
} else if (strncmp(argv[i], "-Xjitblocking", 13) == 0) {
gDvmJit.blockingMode = true;
} else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) {
gDvmJit.threshold = atoi(argv[i] + 15);
} else if (strncmp(argv[i], "-Xjitcodecachesize:", 19) == 0) {
gDvmJit.codeCacheSize = atoi(argv[i] + 19) * 1024;
if (gDvmJit.codeCacheSize == 0) {
gDvm.executionMode = kExecutionModeInterpFast;
}
} else if (strncmp(argv[i], "-Xincludeselectedop", 19) == 0) {
gDvmJit.includeSelectedOp = true;
} else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) {
gDvmJit.includeSelectedMethod = true;
} else if (strncmp(argv[i], "-Xjitcheckcg", 12) == 0) {
gDvmJit.checkCallGraph = true;
/* Need to enable blocking mode due to stack crawling */
gDvmJit.blockingMode = true;
} else if (strncmp(argv[i], "-Xjitdumpbin", 12) == 0) {
gDvmJit.printBinary = true;
} else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
gDvmJit.printMe = true;
} else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
gDvmJit.profileMode = kTraceProfilingContinuous;
} else if (strncmp(argv[i], "-Xjitdisableopt", 15) == 0) {
/* Disable selected optimizations */
if (argv[i][15] == ':') {
sscanf(argv[i] + 16, "%x", &gDvmJit.disableOpt);
/* Disable all optimizations */
} else {
gDvmJit.disableOpt = -1;
}
} else if (strncmp(argv[i], "-Xjitsuspendpoll", 16) == 0) {
gDvmJit.genSuspendPoll = true;
#endif
} else if (strncmp(argv[i], "-Xstacktracefile:", 17) == 0) {
gDvm.stackTraceFile = strdup(argv[i]+17);
} else if (strcmp(argv[i], "-Xgenregmap") == 0) {
gDvm.generateRegisterMaps = true;
} else if (strcmp(argv[i], "-Xnogenregmap") == 0) {
gDvm.generateRegisterMaps = false;
} else if (strcmp(argv[i], "Xverifyopt:checkmon") == 0) {
gDvm.monitorVerification = true;
} else if (strcmp(argv[i], "Xverifyopt:nocheckmon") == 0) {
gDvm.monitorVerification = false;
} else if (strncmp(argv[i], "-Xgc:", 5) == 0) {
if (strcmp(argv[i] + 5, "precise") == 0)
gDvm.preciseGc = true;
else if (strcmp(argv[i] + 5, "noprecise") == 0)
gDvm.preciseGc = false;
else if (strcmp(argv[i] + 5, "preverify") == 0)
gDvm.preVerify = true;
else if (strcmp(argv[i] + 5, "nopreverify") == 0)
gDvm.preVerify = false;
else if (strcmp(argv[i] + 5, "postverify") == 0)
gDvm.postVerify = true;
else if (strcmp(argv[i] + 5, "nopostverify") == 0)
gDvm.postVerify = false;
else if (strcmp(argv[i] + 5, "concurrent") == 0)
gDvm.concurrentMarkSweep = true;
else if (strcmp(argv[i] + 5, "noconcurrent") == 0)
gDvm.concurrentMarkSweep = false;
else if (strcmp(argv[i] + 5, "verifycardtable") == 0)
gDvm.verifyCardTable = true;
else if (strcmp(argv[i] + 5, "noverifycardtable") == 0)
gDvm.verifyCardTable = false;
else {
dvmFprintf(stderr, "Bad value for -Xgc");
return -1;
}
ALOGV("Precise GC configured %s", gDvm.preciseGc ? "ON" : "OFF");
} else if (strcmp(argv[i], "-Xcheckdexsum") == 0) {
gDvm.verifyDexChecksum = true;
} else if (strcmp(argv[i], "-Xprofile:threadcpuclock") == 0) {
gDvm.profilerClockSource = kProfilerClockSourceThreadCpu;
} else if (strcmp(argv[i], "-Xprofile:wallclock") == 0) {
gDvm.profilerClockSource = kProfilerClockSourceWall;
} else if (strcmp(argv[i], "-Xprofile:dualclock") == 0) {
gDvm.profilerClockSource = kProfilerClockSourceDual;
} else {
if (!ignoreUnrecognized) {
dvmFprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
return -1;
}
}
}
return 0;
}
调用dvmCheckAsmConstants检测meterp解析参数配置,dvmQuasiAtomicsStartup, 初始化原子操作的mutex,dvmGcStartup初始化mutex,初始化GC堆区,
dvmThreadStartup,初始化线程相关的环境,dvmInlineNativeStartup,分配InlineNative相关的内存,将gDvm.inlinedMethods指向这块内存,所谓InlineNative就是指一些Java方法,使用了效率更高的C函数实现,执行这些方法时,直接调用到这些C函数,不用在执行字节码,和inLine有异曲同工之妙,dvmRegisterMapStartup,分配MapStats的内存,将gDvm.registerMapStats指向这块内存,MapStats应该是和RegisterMap相关。dvmInstanceofStartup分配instanceofCache的内存,将gDvm.instanceofCache指向这块内存,着重看看dvmClassStartup方法。
bool dvmClassStartup()
{
/* make this a requirement -- don't currently support dirs in path */
if (strcmp(gDvm.bootClassPathStr, ".") == 0) {
ALOGE("ERROR: must specify non-'.' bootclasspath");
return false;
}
gDvm.loadedClasses =
dvmHashTableCreate(256, (HashFreeFunc) dvmFreeClassInnards);
gDvm.pBootLoaderAlloc = dvmLinearAllocCreate(NULL);
if (gDvm.pBootLoaderAlloc == NULL)
return false;
if (false) {
linearAllocTests();
exit(0);
}
/*
* Class serial number. We start with a high value to make it distinct
* in binary dumps (e.g. hprof).
*/
gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;
/*
* Set up the table we'll use for tracking initiating loaders for
* early classes.
* If it's NULL, we just fall back to the InitiatingLoaderList in the
* ClassObject, so it's not fatal to fail this allocation.
*/
gDvm.initiatingLoaderList = (InitiatingLoaderList*)
calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));
/*
* Create the initial classes. These are the first objects constructed
* within the nascent VM.
*/
if (!createInitialClasses()) {
return false;
}
/*
* Process the bootstrap class path. This means opening the specified
* DEX or Jar files and possibly running them through the optimizer.
*/
assert(gDvm.bootClassPath == NULL);
ALOGI("bootclasspath=%s", gDvm.bootClassPathStr);
processClassPath(gDvm.bootClassPathStr, true);
if (gDvm.bootClassPath == NULL)
return false;
return true;
}
可以看到在dvmClassStartup中,调用createInitialClasses方法虚拟机加载了java使用核心类,通过调用processClassPath方法,传入gDvm.bootClassPathStr为android系统/system/framework目录下使用的核心jar,这样zygote进程就初始化了android系统需要使用的java类了;dvmFindRequiredClassesAndMembers,主要是将相关常用到的类、属性、构造器、方法等,直接关联到gDvm的相关指针上;dvmStringInternStartup,创建了internedStrings和literalStrings的Hash表;dvmNativeStartup,创建用于保存sharedLib(也就是so)的Hash表,将gDvm.nativeLibs指向此表,以后每个加载的so的相关信息都会被保存到这个表中,避免重复加载。dvmInternalNativeStartup, 遍历很多类,设置这些类的classDescriptorHash,这些类来自于libcore中,对应在dalvik下c语言实现;dvmJniStartup,初始化了jni的全局引用表和全局弱引用表;dvmProfilingStartup初始化Dalvik虚拟机的性能分析模块,性能分析模块可以通过启动参数打开; dvmCreatelnlineSubsTable初始化Dalvik虚拟机的优化模块,这个模块执行一些简单的字节码的优化;dvmValidateBoxClasses装载Boolean,Boolean,Float,Double,Byte,Short,Integer,Long基本类;dvmPrepMainForJni 准备主线程的JNI环境,把前面创建的JNIEnv和主线程关联起来;dvmInitClass装在Class类;registerSystemNatives注册com/android/dex/Dex类,加载libjavacore.so,libnativehelper.so库;dvmCreateStockExceptions创建一些异常对象,包括OutOfMemoryError, InternalError和NoClassDefFoundError.保存在gDvm中;dvmPrepMainThread.创建和主线程相关联的Java对象,包括Thread, ThreadGroup和VMThread对象;dvmReferenceTableEntries检查当前应用表,确保主线程当前没有引用;dvmDebuggerStartup初始化调试信息;
dvmGcStartupClasses启动GC;initZygote初始化zygote运行的相关信息;dvmCheckException异常信息检查;到这dvmStartup调用完成,装在android应用运行一些基本环境。
3)startReg开始注册android使用的核心jni方法;
4)到这jni环境变量初始化完成,传入两个参数"com.android.internal.os.ZygoteInit","start-system-server",通过env->FindClass,找到java类ZygoteInit,并获取入口方法main,这样程序跳转到了java;
(二)ZygoteInit的main方法
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gc();
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
if (argv[1].equals("start-system-server")) {
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
main函数主要做了以下几件事
1)registerZygoteSocket初始化一个zygote socket;
2)startSystemServer 启动了Android系统进程system_server进程,同过zygote fork出一个进程,然后启动调用com.android.server.SystemServer,开始初始化;
3)监听socket;