type
status
date
slug
summary
tags
category
icon
password

启动JVM的通用流程

  1. 加载虚拟机实现的动态链接库(Android中是so文件);
    1. 一般通过dlopen方法加载so文件.
  1. 设置启动参数,并使用JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*)方法创建虚拟机;
这个时候就可以执行Java程序了.
我这里用C++写了个简单的例子,用来创建JVM:

C++创建虚拟机

#include <iostream> #include <jni.h> #include <dlfcn.h> int main() { auto jvmHandler = dlopen( "../libjvm.dylib", RTLD_NOW | RTLD_NODELETE); if (jvmHandler == nullptr) { std::cerr << "load libjvm.dylib failed" << std::endl; } JavaVM *javaVm; JNIEnv *jniEnv; JavaVMInitArgs vmInitArgs; JavaVMOption *options = new JavaVMOption[2]; options[0].optionString = "-Djava.class.path=."; options[1].optionString = "-version"; vmInitArgs.version = JNI_VERSION_1_4; vmInitArgs.nOptions = 1; vmInitArgs.options = options; vmInitArgs.ignoreUnrecognized = JNI_TRUE; auto status = JNI_CreateJavaVM(&javaVm, (void **) &jniEnv, &vmInitArgs); if (status < 0 || javaVm == nullptr || jniEnv == nullptr) { std::cerr << "Create JavaVM failed!" << std::endl; return 0; } delete (options); jclass cls = jniEnv->FindClass("Main"); if (jniEnv->ExceptionCheck() == JNI_TRUE || cls == nullptr) { jniEnv->ExceptionDescribe(); jniEnv->ExceptionClear(); free(jvmHandler); std::cerr << "find class Main failed!" << std::endl; return 0; } jmethodID mehtodTestId = jniEnv->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); jniEnv->CallStaticVoidMethod(cls, mehtodTestId, nullptr); javaVm->DestroyJavaVM(); return 0; }
代码没什么好说的,按照指定的流程加载就行,实际运用的时候启动参数得设置很多.
在使用app_process创建并启动zygote进程之前,会先启动虚拟机.
在AndroidRuntime::start()方法中有这么一段代码:
/* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { return; } onVmCreated(env);
JniInvocation其实是一个中间层,通过这个中国层,那些使用JNI invocation API的应用可以动态选择JNI的实现方式.在Android中就是动态选择Dalvik虚拟机和ART虚拟机(可通过persist.sys.dalvik.vm.lib.2指定)
bool Init(const char* library) { return JniInvocationInit(impl_, library) != 0; }
libnativehelper/JniInvocation.c中:
// 默认库 static const char* kDefaultJniInvocationLibrary = "libart.so"; bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library_name) { #ifdef __ANDROID__ char buffer[PROP_VALUE_MAX]; #else char* buffer = NULL; #endif // 获取虚拟机库名,这里是libart.so library_name = JniInvocationGetLibrary(library_name, buffer); // 使用dlopen加载虚拟机库 DlLibrary library = DlOpenLibrary(library_name); if (library == NULL) { if (strcmp(library_name, kDefaultJniInvocationLibrary) == 0) { // Nothing else to try. ALOGE("Failed to dlopen %s: %s", library_name, DlGetError()); 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_name, kDefaultJniInvocationLibrary, DlGetError()); library_name = kDefaultJniInvocationLibrary; library = DlOpenLibrary(library_name); if (library == NULL) { ALOGE("Failed to dlopen %s: %s", library, DlGetError()); return false; } } // 查找对应JNI接口 DlSymbol JNI_GetDefaultJavaVMInitArgs_ = FindSymbol(library, "JNI_GetDefaultJavaVMInitArgs"); if (JNI_GetDefaultJavaVMInitArgs_ == NULL) { return false; } DlSymbol JNI_CreateJavaVM_ = FindSymbol(library, "JNI_CreateJavaVM"); if (JNI_CreateJavaVM_ == NULL) { return false; } DlSymbol JNI_GetCreatedJavaVMs_ = FindSymbol(library, "JNI_GetCreatedJavaVMs"); if (JNI_GetCreatedJavaVMs_ == NULL) { return false; } instance->jni_provider_library_name = library_name; instance->jni_provider_library = library; instance->JNI_GetDefaultJavaVMInitArgs = (jint (*)(void *)) JNI_GetDefaultJavaVMInitArgs_; instance->JNI_CreateJavaVM = (jint (*)(JavaVM**, JNIEnv**, void*)) JNI_CreateJavaVM_; instance->JNI_GetCreatedJavaVMs = (jint (*)(JavaVM**, jsize, jsize*)) JNI_GetCreatedJavaVMs_; return true; }
这里默认就是libart.so,然后使用dlopen系统调用进行加载,查找主要的JNI接口.然后将接口的实现切换为ART虚拟机.
在startVM中,首先会初始化大量的启动参数,然后就调用JNI_CreateJavaVM()方法创建ART虚拟机:
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; }
这个时候ART虚拟机就创建成功了.
Android系统启动流程-Native方法的注册Android系统启动流程-桌面程序的启动
姜康
姜康
一个软件工程师
公告
type
status
date
slug
summary
tags
category
icon
password
🎉博客网站重新制作了🎉
👏欢迎更新体验👏