@(Android研究)[Android|源码|虚拟机]java
[TOC]android
虚拟机启动时的函数调用路径:数组
app_main.cc - main |-- AndroidRuntime::start |-- AndroidRuntime::startVm |-- JNI_CreateJavaVM
当init进程启动zygote进程时会建立虚拟机,下是zygote代码的main函数,本文从这里开始分析虚拟机如何建立,这个函数在文件"frameworks/base/cmds/app_process/app_main.cpp"中,下面是它的源码:app
int main(int argc, char* const argv[]) { ...... AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // 处理命令行参数 // 忽略 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 : 启动系统服务 // --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. int i; for (i = 0; i < argc; i++) { if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(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); } 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()); set_process_name(niceName.string()); } 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."); return 10; } }
**runtime.start(...)**语句启动了Android运行时,在启动Android运行时的同时会启动虚拟机。main函数中的局部变量runtime是AppRuntime类的对象,这个类的代码定义在文件"frameworks/base/cmds/app_process/app_main.cpp"中,AppRuntime类继承了AndroidRuntime类,而start函数就是AndroidRuntime类的成员函数。ide
AndroidRuntime类定义在文件"frameworks/base/core/jni/AndroidRuntime.cpp"中,下面是AndroidRuntime::start函数的代码:函数
/* * 启动Android运行时。它启动虚拟机并调用经过"className"参数所指定的类名中 * 的"static void main(String[] args)"方法。 * * 向main函数传入两个参数:类名和被指定的选项字符串。 */ void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); ...... /* 启动虚拟机。 */ JniInvocation jni_invocation; jni_invocation.Init(NULL); // 初始化JNI API接口 JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) { return; } onVmCreated(env); // 在zygote中这个函数什么都不作。 /* * Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } /* * 咱们要调用main(),将一个字符串数组当作参数传入。 * 目前,咱们有两个参数,类名和一个选项字符串。 * 建立一个数组来保存它们。 */ 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。这个线程成为VM的主线程,直到VM结束前不会返回。 * * 对于zygote而言除非设备关机不然这个线程是不会退出的,将zygote * 比做服务端,这个服务端会一直等待并处理各类客户端的请求。 */ 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 { // 调用Java方法。 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"); }
这个函数主要作了下面三件事情:ui
这个函数中调用了**onVmCreated(env);**语句,对于zygote来讲,这个函数不作任何事情。this
jni_invocation虽然是AndroidRuntime::start函数的局部变量,可是对于zygote而言除非设备关机不然是不会退出AndroidRuntime::start函数的。对于普通APP,除非APP结束不然也不会退出AndroidRuntime::start函数。在另外一篇分析zygote启动过程的文章中会说明缘由。命令行
JniInvocation::Init这个函数用于初始化JNI调用,这个函数在文件libnativehelper/JniInvocation.cpp中,下面是这个函数的代码:线程
/** * 初始化JNI调用API。参数library应当传入可供dlopen打开的有效的共享库, * 这个共享库提供一个JNI调用实现,或者参数library被传入null则将经过 * persist.sys.dalvik.vm.lib使用默认值。 */ bool JniInvocation::Init(const char* library) { #ifdef HAVE_ANDROID_OS char buffer[PROPERTY_VALUE_MAX]; #else char* buffer = NULL; #endif // 得到共享库名。 library = GetLibrary(library, buffer); // 加载这个共享库。 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; } } // 找到符号JNI_GetDefaultJavaVMInitArgs。 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_), "JNI_GetDefaultJavaVMInitArgs")) { return false; } // 找到符号JNI_CreateJavaVM。 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_), "JNI_CreateJavaVM")) { return false; } // 找到符号JNI_GetCreatedJavaVMs。 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_), "JNI_GetCreatedJavaVMs")) { return false; } return true; }
这个函数作了下面两件事情:
JniInvocation类中的成员变量handle_保存了共享库的句柄,成员函数JNI_GetDefaultJavaVMInitArgs_、*JNI_CreateJavaVM_和JNI_GetCreatedJavaVMs_*均保存了从共享库中得到的函数地址。
JniInvocation::Init调用了JniInvocation::GetLibrary函数得到了共享库名,这个共享库中有JNI函数的实现,这个函数在文件libnativehelper/JniInvocation.cpp中,下面是它的代码:
#ifdef HAVE_ANDROID_OS static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2"; static const char* kDebuggableSystemProperty = "ro.debuggable"; static const char* kDebuggableFallback = "0"; // Not debuggable. #endif static const char* kLibraryFallback = "libart.so"; const char* JniInvocation::GetLibrary(const char* library, char* buffer) { #ifdef HAVE_ANDROID_OS const char* default_library; char debuggable[PROPERTY_VALUE_MAX]; property_get(kDebuggableSystemProperty, debuggable, kDebuggableFallback); if (strcmp(debuggable, "1") != 0) { // Not a debuggable build. // Do not allow arbitrary library. This // will also ignore the default library, but initialize to fallback // for cleanliness. library = kLibraryFallback; default_library = kLibraryFallback; } else { // Debuggable build. // Accept the library parameter. For the case it is NULL, load the default // library from the system property. if (buffer != NULL) { property_get(kLibrarySystemProperty, buffer, kLibraryFallback); default_library = buffer; } else { // 若是没有指定缓冲区,使用备用的默认值。 default_library = kLibraryFallback; } } #else UNUSED(buffer); const char* default_library = kLibraryFallback; #endif if (library == NULL) { library = default_library; } return library; }
能够发现JniInvocation::GetLibrary函数中默认的库是kLibraryFallback,而这个变量的值为libart.so,这个函数的返回值与kLibrarySystemProperty变量也有关系,而这个变量中保存的属性对应的值一般为libart.so。因此在这里我武断的认定这个函数的返回值总为libart.so以便后面分析。
对AndroidRuntime::start函数中所执行**jni_invocation.Init(NULL);**语句作一个总结
:
继续对AndroidRuntime::start函数进行分析,在执行完**jni_invocation.Init(NULL);**语句后紧接着调用了startVm函数,这个函数启动了虚拟机。这个函数在文件frameworks/base/core/jni/AndroidRuntime.cpp中,下面是它的源码:
/* * Start the Dalvik Virtual Machine. * (PS:这里翻译过来是:启动Dalvik虚拟机,我认为是这只不过是注释内容还未被修改,而实际上启动的已经不是dalvik虚拟机了) * * 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. */ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) { int result = -1; JavaVMInitArgs initArgs; ...... // checkjni属性。 bool checkJni = false; property_get("dalvik.vm.checkjni", propBuf, ""); if (strcmp(propBuf, "true") == 0) { checkJni = true; } else if (strcmp(propBuf, "false") != 0) { /* 属性即不为真也不为假;转到内核参数。 */ property_get("ro.kernel.android.checkjni", propBuf, ""); if (propBuf[0] == '1') { checkJni = true; } } ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF"); if (checkJni) { /* extended JNI checking */ addOption("-Xcheck:jni"); /* 设置JNI全局引用上限 */ addOption("-Xjnigreflimit:2000"); /* with -Xcheck:jni, 这提供JNI函数调用跟踪 */ //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; } ...... /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */ parseRuntimeOption("dalvik.vm.jit.op", jitOpBuf, "-Xjitop:"); /* Force interpreter-only mode for selected methods */ parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:"); // 向mOptions中添加执行模式。 if (executionMode == kEMIntPortable) { addOption("-Xint:portable"); } else if (executionMode == kEMIntFast) { addOption("-Xint:fast"); } else if (executionMode == kEMJitCompiler) { addOption("-Xint:jit"); } // libart允许libdvm flags,但反过来不行,因此仅libart的状况下才传入一些选项。 property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so"); bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0); if (libart) { ...... } ...... initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE; /* * 初始化VM。 * * JavaVM*做用于每一个进程,JNIEnv*做用于每一个线程(The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.)。 * * 若是这个调用成功,则VM就绪,and we can start issuing * JNI calls. */ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); goto bail; } result = 0; bail: return result; }
AndroidRuntime::startVm函数主要作了两件事情:
系统属性主要经过property_get函数得到,这个函数会去系统属性文件中读取属性。
当要添加一个新的选项时会调用AndroidRuntime::addOption函数,它向mOptions中添加一个JavaVMOption对象,这个函数在frameworks/base/core/jni/AndroidRuntime.cpp文件中,下面是它的源码:
void addOption(const char* optionString, void* extra_info = NULL); void AndroidRuntime::addOption(const char* optionString, void* extraInfo) { JavaVMOption opt; opt.optionString = optionString; opt.extraInfo = extraInfo; mOptions.add(opt); }
下面开始分析JNI_CreateJavaVM函数,这个定义在libnativehelper/JniInvocation.cpp文件中,下面是它的源码:
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args); }
JniInvocation::GetJniInvocation()函数得到的是JniInvocation类的实例,JniInvocation::GetJniInvocation().JNI_CreateJavaVM调用的是JniInvocation类中非静态成员函数JNI_CreateJavaVM,下面是这个成员函数的源码:
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { return JNI_CreateJavaVM_(p_vm, p_env, vm_args); }
JNI_CreateJavaVM_是JniInvocation类中的非静态成员变量,它指向的是前面所加载的libart.so中的JNI_CreateJavaVM函数,这个成员变量在JniInvocation::Init函数中被赋值。
libart.so中的JNI_CreateJavaVM函数建立了虚拟机,它的源码art/runtime/jni_internal.cc文件中,下面是这个函数的源码:
/** * 建立虚拟机。 * 参数p_vm和p_env是输出参数。 * 参数vm_args是输入参数,这个参数保存的是虚拟机建立过程当中须要用到的选项。 */ extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args); // 检查Jni版本。 if (IsBadJniVersion(args->version)) { LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version; return JNI_EVERSION; } // 将全部的虚拟机选项均保存到options中。 RuntimeOptions options; for (int i = 0; i < args->nOptions; ++i) { JavaVMOption* option = &args->options[i]; options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo)); } // 建立运行时环境。 bool ignore_unrecognized = args->ignoreUnrecognized; if (!Runtime::Create(options, ignore_unrecognized)) { return JNI_ERR; } // 启动运行时环境。 Runtime* runtime = Runtime::Current(); bool started = runtime->Start(); if (!started) { delete Thread::Current()->GetJniEnv(); delete runtime->GetJavaVM(); LOG(WARNING) << "CreateJavaVM failed"; return JNI_ERR; } // 输出参数。 *p_env = Thread::Current()->GetJniEnv(); *p_vm = runtime->GetJavaVM(); return JNI_OK; }
JNI_CreateJavaVM函数主要作了两件事情:
RuntimeOptions类型的定义在文件art/runtime/runtime.h中:
typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;
Runtime::Create函数是一个静态函数在文件art/runtime/runtime.cc中,下面是它的源码:
bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) { // TODO: acquire a static mutex on Runtime to avoid racing. if (Runtime::instance_ != NULL) { return false; } InitLogging(NULL); // Calls Locks::Init() as a side effect. instance_ = new Runtime; if (!instance_->Init(options, ignore_unrecognized)) { delete instance_; instance_ = NULL; return false; } return true; }
经过分析上面的代码能够发现Runtime类被设计为单例模式,单例对象保存在instance_中,而后又调用了Init函数。
Runtime::Init函数在文件art/runtime/runtime.cc中,下面是它的源码:
bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) { CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize); MemMap::Init(); std::unique_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized)); ...... java_vm_ = new JavaVMExt(this, options.get()); Thread::Startup(); // ClassLinker needs an attached thread, but we can't fully attach a thread without creating // objects. We can't supply a thread group yet; it will be fixed later. Since we are the main // thread, we do not get a java peer. Thread* self = Thread::Attach("main", false, nullptr, false); ...... VLOG(startup) << "Runtime::Init exiting"; return true; }
这个函数中的new JavaVMExt语句建立了JavaVMExt对象,一个虚拟机有且仅有一个JavaVMExt对象,JavaVMExt类型继承了JavaVM类型,能够去查看"art/runtime/jni_internal.h"文件。Thread::Attach函数将虚拟机附加到主线程上。
Thread::Attach函数的源码在文件"art/runtime/thread.cc"文件中,下面是它的源码:
Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group, bool create_peer) { Thread* self; Runtime* runtime = Runtime::Current(); if (runtime == nullptr) { LOG(ERROR) << "Thread attaching to non-existent runtime: " << thread_name; return nullptr; } { MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_); if (runtime->IsShuttingDownLocked()) { ...... } else { Runtime::Current()->StartThreadBirth(); self = new Thread(as_daemon); self->Init(runtime->GetThreadList(), runtime->GetJavaVM()); Runtime::Current()->EndThreadBirth(); } } ...... }
在这个函数中建立了Thread对象,而后调用了Thread::Init函数,在这个函数中建立了当前线程的JNIEnv。
Thread::Init函数的源码在文件"art/runtime/thread.cc"文件中,下面是这个函数的源码:
void Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm) { ...... tlsPtr_.jni_env = new JNIEnvExt(this, java_vm); ...... }
这个函数中建立了JNIEnvExt对象。JNIEnvExt类型继承了JNIEnv类型,能够去"art/runtime/jni_internal.h"文件中查看。
如今回到JNI_CreateJavaVM函数中,Runtime::Create函数执行完后,将执行Runtime::Start函数启动Android运行时,然会调用这两行语句返回建立的Java虚拟机对象和当前线程的JNI环境:
*p_env = Thread::Current()->GetJniEnv(); *p_vm = runtime->GetJavaVM();
Thread::Current函数得到当前线程的对象。
Tread::GetJniEnv()得到当前线程的JNI环境,这个函数的定义在文件"art/runtime/thread-inl.h"中,下面是它的源码:
// JNI methods JNIEnvExt* GetJniEnv() const { return tlsPtr_.jni_env; }
Runtime::GetJavaVM()函数得到的是Java虚拟机对象,它的定义在文件"art/runtime/runtime.h"中,下面是它的源码:
JavaVMExt* GetJavaVM() const { return java_vm_; }
执行完JNI_CreateJavaVM函数后返回到startVM函数中。
执行完startVM成功启动虚拟机后,将会经过env->CallStaticVoidMethod语句调用"com.android.internal.os.ZygoteInit"这个Java类的main方法,这个Java方法将会启动zygote服务。
关于如何启动zygote服务将另写一篇文章分析。
至此Android5.1源码虚拟机启动过程分析完毕。