赞
踩
注:此文章主要基于展锐Android R代码加上学习总结自IngresGe大佬的分析
由*.rc文件配置启动
zygote重启条件(grep “restart zygote” 查找):
inputflinger 进程被杀 (onrestart)
servicemanager 进程被杀 (onrestart)
surfaceflinger 进程被杀 (onrestart)
netd 进程被杀 (onrestart)
zygote进程被杀 (oneshot=false)
system_server进程被杀(waitpid)
Zygote启动流程:
代码入口为:frameworks/base/cmds/app_process/app_main.cpp
app_main.cpp
刚开始进程名称为app_process改名为zygote,最后通过runtime的start()方法启动java虚拟机,进入java世界
/* * Main entry of app process. * * Starts the interpreted runtime, then starts up the application. * */ #define LOG_TAG "appproc" #include <stdio.h> #include <stdlib.h> #include <sys/prctl.h> #include <sys/stat.h> #include <unistd.h> #include <android-base/macros.h> #include <binder/IPCThreadState.h> #include <hwbinder/IPCThreadState.h> #include <utils/Log.h> #include <cutils/memory.h> #include <cutils/properties.h> #include <cutils/trace.h> #include <android_runtime/AndroidRuntime.h> #include <private/android_filesystem_config.h> // for AID_SYSTEM namespace android { static void app_usage() { fprintf(stderr, "Usage: app_process [java-options] cmd-dir start-class-name [options]\n"); } class AppRuntime : public AndroidRuntime { public: AppRuntime(char* argBlockStart, const size_t argBlockLength) : AndroidRuntime(argBlockStart, argBlockLength) , mClass(NULL) { } void setClassNameAndArgs(const String8& className, int argc, char * const *argv) { mClassName = className; for (int i = 0; i < argc; ++i) { mArgs.add(String8(argv[i])); } } virtual void onVmCreated(JNIEnv* env) { if (mClassName.isEmpty()) { return; // Zygote. Nothing to do here. } /* * This is a little awkward because the JNI FindClass call uses the * class loader associated with the native method we're executing in. * If called in onStarted (from RuntimeInit.finishInit because we're * launching "am", for example), FindClass would see that we're calling * from a boot class' native method, and so wouldn't look for the class * we're trying to look up in CLASSPATH. Unfortunately it needs to, * because the "am" classes are not boot classes. * * The easiest fix is to call FindClass here, early on before we start * executing boot class Java code and thereby deny ourselves access to * non-boot classes. */ char* slashClassName = toSlashClassName(mClassName.string()); mClass = env->FindClass(slashClassName); if (mClass == NULL) { ALOGE("ERROR: could not find class '%s'\n", mClassName.string()); } free(slashClassName); mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass)); } virtual void onStarted() { sp<ProcessState> proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool(); AndroidRuntime* ar = AndroidRuntime::getRuntime(); ar->callMain(mClassName, mClass, mArgs); IPCThreadState::self()->stopProcess(); hardware::IPCThreadState::self()->stopProcess(); } virtual void onZygoteInit() { sp<ProcessState> proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool(); } virtual void onExit(int code) { if (mClassName.isEmpty()) { // if zygote IPCThreadState::self()->stopProcess(); hardware::IPCThreadState::self()->stopProcess(); } AndroidRuntime::onExit(code); } String8 mClassName; Vector<String8> mArgs; jclass mClass; }; } using namespace android; static size_t computeArgBlockSize(int argc, char* const argv[]) { // TODO: This assumes that all arguments are allocated in // contiguous memory. There isn't any documented guarantee // that this is the case, but this is how the kernel does it // (see fs/exec.c). // // Also note that this is a constant for "normal" android apps. // Since they're forked from zygote, the size of their command line // is the size of the zygote command line. // // We change the process name of the process by over-writing // the start of the argument block (argv[0]) with the new name of // the process, so we'd mysteriously start getting truncated process // names if the zygote command line decreases in size. uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]); uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]); end += strlen(argv[argc - 1]) + 1; return (end - start); } static void maybeCreateDalvikCache() { const char* androidRoot = getenv("ANDROID_DATA"); LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset"); char dalvikCacheDir[PATH_MAX]; const int numChars = snprintf(dalvikCacheDir, PATH_MAX, "%s/dalvik-cache/" ABI_STRING, androidRoot); LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0), "Error constructing dalvik cache : %s", strerror(errno)); int result = mkdir(dalvikCacheDir, 0711); LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST), "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno)); // We always perform these steps because the directory might // already exist, with wider permissions and a different owner // than we'd like. result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT); LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno)); result = chmod(dalvikCacheDir, 0711); LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache permissions : %s", strerror(errno)); } #if defined(__LP64__) static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64"; static const char ZYGOTE_NICE_NAME[] = "zygote64"; #else static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32"; static const char ZYGOTE_NICE_NAME[] = "zygote"; #endif >>**//主函数入口main**<< >>== int main(int argc, char* const argv[]) { if (!LOG_NDEBUG) { String8 argv_String; for (int i = 0; i < argc; ++i) { argv_String.append("\""); argv_String.append(argv[i]); argv_String.append("\" "); } ALOGV("app_process main with argv: %s", argv_String.string()); } AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name. All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. // // As an exception to the above rule, anything in "spaced commands" // goes to the vm even though it has a space in it. const char* spaced_commands[] = { "-cp", "-classpath" }; // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s). bool known_command = false; int i; for (i = 0; i < argc; i++) { if (known_command == true) { runtime.addOption(strdup(argv[i])); // The static analyzer gets upset that we don't ever free the above // string. Since the allocation is from main, leaking it doesn't seem // problematic. NOLINTNEXTLINE ALOGV("app_process main add known option '%s'", argv[i]); known_command = false; continue; } for (int j = 0; j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0])); ++j) { if (strcmp(argv[i], spaced_commands[j]) == 0) { known_command = true; ALOGV("app_process main found known command '%s'", argv[i]); } } if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); // The static analyzer gets upset that we don't ever free the above // string. Since the allocation is from main, leaking it doesn't seem // problematic. NOLINTNEXTLINE ALOGV("app_process main add option '%s'", argv[i]); } // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } 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.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } } Vector<String8> args; if (!className.isEmpty()) { // We're not in zygote mode, the only argument we need to pass // to RuntimeInit is the application argument. // // The Remainder of args get passed to startup class main(). Make // copies of them before we overwrite them with the process name. args.add(application ? String8("application") : String8("tool")); runtime.setClassNameAndArgs(className, argc - i, argv + i); if (!LOG_NDEBUG) { String8 restOfArgs; char* const* argv_new = argv + i; int argc_new = argc - i; for (int k = 0; k < argc_new; ++k) { restOfArgs.append("\""); restOfArgs.append(argv_new[k]); restOfArgs.append("\" "); } ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string()); } } else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); args.add(abiFlag); // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string(), true /* setProcName */); } if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); } } ==<<
AndroidRuntime.cpp
路径:frameworks/base/core/jni/AndroidRuntime.cpp
/* * Start the Dalvik Virtual Machine. * * Various arguments, most determined by system properties, are passed in. * The "mOptions" vector is updated. * * CAUTION: when adding options in here, be careful not to put the * char buffer inside a nested scope. Adding the buffer to the * options using mOptions.add() does not copy the buffer, so if the * buffer goes out of scope the option may be overwritten. It's best * to put the buffer at the top of the function so that it is more * unlikely that someone will surround it in a scope at a later time * and thus introduce a bug. * * Returns 0 on success. */ >>** 启动java虚拟机,并进行一些配置,主要操作: 一调用startVm开启虚拟机 二调用startReg注册JNI方法 三就是使用JNI把Zygote进程启动起来 **<< ```c++ /* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */ void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); static const String8 startSystemServer("start-system-server"); /* * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { /* 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 /system does not exist."); return; } setenv("ANDROID_ROOT", rootDir, 1); } const char* runtimeRootDir = getenv("ANDROID_RUNTIME_ROOT"); if (runtimeRootDir == NULL) { LOG_FATAL("No runtime directory specified with ANDROID_RUNTIME_ROOT environment variable."); return; } const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT"); if (tzdataRootDir == NULL) { LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable."); return; } //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, zygote) != 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; stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 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 != NULL ? 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"); }
alps/libnativehelper/JniInvocation.cpp
Init函数主要作用是初始化JNI,具体工作是首先通过dlopen加载libart.so获得其句柄,然后调用dlsym从libart.so中找到
JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三个函数地址,赋值给对应成员属性,这三个函数会在后续虚拟机创建中调用.
bool JniInvocationImpl::Init(const char* library) { #ifdef __ANDROID__ char buffer[PROP_VALUE_MAX]; #else char* buffer = NULL; #endif library = GetLibrary(library, buffer); handle_ = OpenLibrary(library); if (handle_ == NULL) { if (strcmp(library, kLibraryFallback) == 0) { // Nothing else to try. ALOGE("Failed to dlopen %s: %s", library, GetError().c_str()); 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, GetError().c_str()); library = kLibraryFallback; handle_ = OpenLibrary(library); if (handle_ == NULL) { ALOGE("Failed to dlopen %s: %s", library, GetError().c_str()); return false; } } if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetDefaultJavaVMInitArgs_), "JNI_GetDefaultJavaVMInitArgs")) { return false; } if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_CreateJavaVM_), "JNI_CreateJavaVM")) { return false; } if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetCreatedJavaVMs_), "JNI_GetCreatedJavaVMs")) { return false; } return true; }
配置虚拟机相关参数,再调用之前 JniInvocation初始化得到的 JNI_CreateJavaVM_来启动虚拟机。
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) { JavaVMInitArgs initArgs; char propBuf[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 usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX]; char jitpthreadpriorityOptsBuf[sizeof("-Xjitpthreadpriority:")-1 + PROPERTY_VALUE_MAX]; char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX]; char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX]; char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX]; char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX]; char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX]; char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX]; char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX]; char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX]; char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX]; char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX]; char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX]; char foregroundHeapGrowthMultiplierOptsBuf[ sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX]; char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_variant_key[PROPERTY_KEY_MAX]; char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_features_key[PROPERTY_KEY_MAX]; char dex2oat_isa_features[sizeof("--instruction-set-features=") -1 + PROPERTY_VALUE_MAX]; char dex2oatFlagsBuf[PROPERTY_VALUE_MAX]; char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX]; char extraOptsBuf[PROPERTY_VALUE_MAX]; char voldDecryptBuf[PROPERTY_VALUE_MAX]; enum { kEMDefault, kEMIntPortable, kEMIntFast, kEMJitCompiler, } executionMode = kEMDefault; char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX]; char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX]; char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX]; char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX]; char corePlatformApiPolicyBuf[sizeof("-Xcore-platform-api-policy:") + PROPERTY_VALUE_MAX]; char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX]; char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX]; std::string fingerprintBuf; char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX]; char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX]; std::string use_apex_image = server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE, ENABLE_APEX_IMAGE, /*default_value=*/ ""); if (use_apex_image == "true") { addOption(kApexImageOption); ALOGI("Using Apex boot image: '%s'\n", kApexImageOption); } else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) { ALOGI("Using dalvik.vm.boot-image: '%s'\n", bootImageBuf); } else { ALOGI("Using default boot image"); } std::string disable_lock_profiling = server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE, DISABLE_LOCK_PROFILING, /*default_value=*/ ""); if (disable_lock_profiling == "true") { addOption(kLockProfThresholdRuntimeOption); ALOGI("Disabling lock profiling: '%s'\n", kLockProfThresholdRuntimeOption); } else { ALOGI("Leaving lock profiling enabled"); } bool checkJni = false; 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; } } ALOGV("CheckJNI is %s\n", checkJni ? "ON" : "OFF"); if (checkJni) { /* extended JNI checking */ addOption("-Xcheck:jni"); /* with -Xcheck:jni, this provides a JNI function call trace */ //addOption("-verbose:jni"); } 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; } strcpy(jniOptsBuf, "-Xjniopts:"); if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) { ALOGI("JNI options: '%s'\n", jniOptsBuf); } /* route exit() to our handler */ addOption("exit", (void*) runtime_exit); /* route fprintf() to our handler */ addOption("vfprintf", (void*) runtime_vfprintf); /* register the framework-specific "is sensitive thread" hook */ addOption("sensitiveThread", (void*) runtime_isSensitiveThread); /* enable verbose; standard options are { jni, gc, class } */ //addOption("-verbose:jni"); addOption("-verbose:gc"); //addOption("-verbose:class"); /* * The default starting and maximum size of the heap. Larger * values should be specified in a product property override. */ parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m"); parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m"); parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit="); parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree="); parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree="); parseRuntimeOption("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization="); /* Foreground heap growth multiplier option */ parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier", foregroundHeapGrowthMultiplierOptsBuf, "-XX:ForegroundHeapGrowthMultiplier="); /* * JIT related options. */ parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:"); parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:"); parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:"); parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:"); parseRuntimeOption("dalvik.vm.jitpthreadpriority", jitpthreadpriorityOptsBuf, "-Xjitpthreadpriority:"); property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, ""); if (strcmp(useJitProfilesOptsBuf, "true") == 0) { addOption("-Xjitsaveprofilinginfo"); } parseRuntimeOption("dalvik.vm.jitprithreadweight", jitprithreadweightOptBuf, "-Xjitprithreadweight:"); parseRuntimeOption("dalvik.vm.jittransitionweight", jittransitionweightOptBuf, "-Xjittransitionweight:"); property_get("dalvik.vm.profilebootimage", propBuf, ""); if (strcmp(propBuf, "true") == 0) { addOption("-Xps-profile-boot-class-path"); addOption("-Xps-profile-aot-code"); } /* * Madvise related options. */ parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:"); /* * Profile related options. */ parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf, "-Xps-hot-startup-method-samples:"); property_get("ro.config.low_ram", propBuf, ""); if (strcmp(propBuf, "true") == 0) { addOption("-XX:LowMemoryMode"); } /* * Garbage-collection related options. */ parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:"); // If it set, honor the "enable_generational_cc" device configuration; // otherwise, let the runtime use its default behavior. std::string enable_generational_cc = server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE, ENABLE_GENERATIONAL_CC, /*default_value=*/ ""); if (enable_generational_cc == "true") { addOption(kGenerationalCCRuntimeOption); } else if (enable_generational_cc == "false") { addOption(kNoGenerationalCCRuntimeOption); } parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC="); /* * Enable debugging only for apps forked from zygote. */ if (zygote) { // Set the JDWP provider and required arguments. By default let the runtime choose how JDWP is // implemented. When this is not set the runtime defaults to not allowing JDWP. addOption("-XjdwpOptions:suspend=n,server=y"); parseRuntimeOption("dalvik.vm.jdwp-provider", jdwpProviderBuf, "-XjdwpProvider:", "default"); } parseRuntimeOption("dalvik.vm.lockprof.threshold", lockProfThresholdBuf, "-Xlockprofthreshold:"); if (executionMode == kEMIntPortable) { addOption("-Xint:portable"); } else if (executionMode == kEMIntFast) { addOption("-Xint:fast"); } else if (executionMode == kEMJitCompiler) { addOption("-Xint:jit"); } // If we are booting without the real /data, don't spend time compiling. property_get("vold.decrypt", voldDecryptBuf, ""); bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) || (strcmp(voldDecryptBuf, "1") == 0)); // Extra options for boot.art/boot.oat image generation. parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf, "-Xms", "-Ximage-compiler-option"); parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf, "-Xmx", "-Ximage-compiler-option"); if (skip_compilation) { addOption("-Ximage-compiler-option"); addOption("--compiler-filter=assume-verified"); } else { parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf, "--compiler-filter=", "-Ximage-compiler-option"); } // If there is a boot profile, it takes precedence over the image and preloaded classes. if (hasFile("/system/etc/boot-image.prof")) { addOption("-Ximage-compiler-option"); addOption("--profile-file=/system/etc/boot-image.prof"); addOption("-Ximage-compiler-option"); addOption("--compiler-filter=speed-profile"); } else { // Make sure there is a preloaded-classes file. if (!hasFile("/system/etc/preloaded-classes")) { ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n", strerror(errno)); return -1; } addOption("-Ximage-compiler-option"); addOption("--image-classes=/system/etc/preloaded-classes"); // If there is a dirty-image-objects file, push it. if (hasFile("/system/etc/dirty-image-objects")) { addOption("-Ximage-compiler-option"); addOption("--dirty-image-objects=/system/etc/dirty-image-objects"); } } property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, ""); parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option"); // Extra options for DexClassLoader. parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf, "-Xms", "-Xcompiler-option"); parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf, "-Xmx", "-Xcompiler-option"); if (skip_compilation) { addOption("-Xcompiler-option"); addOption("--compiler-filter=assume-verified"); // We skip compilation when a minimal runtime is brought up for decryption. In that case // /data is temporarily backed by a tmpfs, which is usually small. // If the system image contains prebuilts, they will be relocated into the tmpfs. In this // specific situation it is acceptable to *not* relocate and run out of the prebuilts // directly instead. addOption("--runtime-arg"); addOption("-Xnorelocate"); } else { parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf, "--compiler-filter=", "-Xcompiler-option"); } parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option"); parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j", "-Ximage-compiler-option"); // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to // pass the instruction-set-features/variant as an image-compiler-option. // Note: it is OK to reuse the buffer, as the values are exactly the same between // * compiler-option, used for runtime compilation (DexClassLoader) // * image-compiler-option, used for boot-image compilation on device // Copy the variant. sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", ABI_STRING); parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant, "--instruction-set-variant=", "-Ximage-compiler-option"); parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant, "--instruction-set-variant=", "-Xcompiler-option"); // Copy the features. sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", ABI_STRING); parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features, "--instruction-set-features=", "-Ximage-compiler-option"); parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features, "--instruction-set-features=", "-Xcompiler-option"); property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, ""); parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option"); /* extra options; parse this late so it overrides others */ property_get("dalvik.vm.extra-opts", extraOptsBuf, ""); parseExtraOpts(extraOptsBuf, NULL); /* Set the properties for locale */ { strcpy(localeOption, "-Duser.locale="); const std::string locale = readLocale(); strncat(localeOption, locale.c_str(), PROPERTY_VALUE_MAX); addOption(localeOption); } // Trace files are stored in /data/misc/trace which is writable only in debug mode. property_get("ro.debuggable", propBuf, "0"); if (strcmp(propBuf, "1") == 0) { property_get("dalvik.vm.method-trace", propBuf, "false"); if (strcmp(propBuf, "true") == 0) { addOption("-Xmethod-trace"); parseRuntimeOption("dalvik.vm.method-trace-file", methodTraceFileBuf,startVm "-Xmethod-trace-file:"); parseRuntimeOption("dalvik.vm.method-trace-file-siz", methodTraceFileSizeBuf, "-Xmethod-trace-file-size:"); property_get("dalvik.vm.method-trace-stream", propBuf, "false"); if (strcmp(propBuf, "true") == 0) { addOption("-Xmethod-trace-stream"); } } } // Native bridge library. "0" means that native bridge is disabled. // // Note: bridging is only enabled for the zygote. Other runs of // app_process may not have the permissions to mount etc. property_get("ro.dalvik.vm.native.bridge", propBuf, ""); if (propBuf[0] == '\0') { ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty"); } else if (zygote && strcmp(propBuf, "0") != 0) { snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX, "-XX:NativeBridge=%s", propBuf); addOption(nativeBridgeLibrary); } #if defined(__LP64__) const char* cpu_abilist_property_name = "ro.product.cpu.abilist64"; #else const char* cpu_abilist_property_name = "ro.product.cpu.abilist32"; #endif // defined(__LP64__) property_get(cpu_abilist_property_name, propBuf, ""); if (propBuf[0] == '\0') { ALOGE("%s is not expected to be empty", cpu_abilist_property_name); return -1; } snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf); addOption(cpuAbiListBuf); // Dalvik-cache pruning counter. parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf, "-Xzygote-max-boot-retry="); /* * When running with debug.generate-debug-info, add --generate-debug-info to * the compiler options so that the boot image, if it is compiled on device, * will include native debugging information. */ property_get("debug.generate-debug-info", propBuf, ""); if (strcmp(propBuf, "true") == 0) { addOption("-Xcompiler-option"); addOption("--generate-debug-info"); addOption("-Ximage-compiler-option"); addOption("--generate-debug-info"); } // The mini-debug-info makes it possible to backtrace through JIT code. if (property_get_bool("dalvik.vm.minidebuginfo", 0)) { addOption("-Xcompiler-option"); addOption("--generate-mini-debug-info"); } // If set, the property below can be used to enable core platform API violation reporting. property_get("persist.debug.dalvik.vm.core_platform_api_policy", propBuf, ""); if (propBuf[0] != '\0') { snprintf(corePlatformApiPolicyBuf, sizeof(corePlatformApiPolicyBuf), "-Xcore-platform-api-policy:%s", propBuf); addOption(corePlatformApiPolicyBuf); } /* * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will * contain the fingerprint and can be parsed. * Fingerprints are potentially longer than PROPERTY_VALUE_MAX, so parseRuntimeOption() cannot * be used here. * Do not ever re-assign fingerprintBuf as its c_str() value is stored in mOptions. */ std::string fingerprint = GetProperty("ro.build.fingerprint", ""); if (!fingerprint.empty()) { fingerprintBuf = "-Xfingerprint:" + fingerprint; addOption(fingerprintBuf.c_str()); } 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"); return -1; } return 0; }
/* 1. Register android native functions with the VM. */ /*static*/ int AndroidRuntime::startReg(JNIEnv* env) { ATRACE_NAME("RegisterAndroidNatives"); /* * 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; }
代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
main的主要工作:
调用preload()来预加载类和资源
调用ZygoteServer()创建两个Server端的Socket--/dev/socket/zygote 和 /dev/socket/zygote_secondary,Socket用来等待ActivityManagerService来请求Zygote来创建新的应用程序进程。
调用forkSystemServer 来启动SystemServer进程,这样系统的关键服务也会由SystemServer进程启动起来。
最后调用runSelectLoop函数来等待客户端请求
public static void main(String argv[]) { ZygoteServer zygoteServer = null; // Mark zygote start. This ensures that thread creation will throw // an error. ZygoteHooks.startZygoteNoThreadCreation(); // Zygote goes into its own process group. try { Os.setpgid(0, 0); } catch (ErrnoException ex) { throw new RuntimeException("Failed to setpgid(0,0)", ex); } Runnable caller; try { // Report Zygote start time to tron unless it is a runtime restart if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { MetricsLogger.histogram(null, "boot_zygote_init", (int) SystemClock.elapsedRealtime()); } String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag, Trace.TRACE_TAG_DALVIK); bootTimingsTraceLog.traceBegin("ZygoteInit"); RuntimeInit.enableDdms(); boolean startSystemServer = false; String zygoteSocketName = "zygote"; String abiList = null; boolean enableLazyPreload = false; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if ("--enable-lazy-preload".equals(argv[i])) { enableLazyPreload = true; } else if (argv[i].startsWith(ABI_LIST_ARG)) { abiList = argv[i].substring(ABI_LIST_ARG.length()); } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. if (!enableLazyPreload) { bootTimingsTraceLog.traceBegin("ZygotePreload"); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload(bootTimingsTraceLog); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload } else { Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); gcAndFinalize(); bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC bootTimingsTraceLog.traceEnd(); // ZygoteInit // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false, 0); Zygote.initNativeState(isPrimaryZygote); ZygoteHooks.stopZygoteNoThreadCreation(); zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // {@code r == null} in the parent (zygote) process, and {@code r != null} in the // child (system_server) process. if (r != null) { r.run(); return; } } Log.i(TAG, "Accepting command socket connections"); // The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = zygoteServer.runSelectLoop(abiList); } catch (Throwable ex) { Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { if (zygoteServer != null) { zygoteServer.closeServerSocket(); } } // We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } }
Zygote进程共做了如下几件事:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。