这一篇是紧接着上一篇《(原创)基于Android R之ART虚拟机的创建流程》遗留的一些问题做进一步分析。上一篇我们遗留了两个内容,一个是JavaVmExt类,另一个则是InitNativeMethods方法的实现没有做进一步的分析。这篇我们接着对这两个部分做进一步分析,下面所有分析的代码都是基于Android11_R17进行分析。
JavaVmExt类
JavaVmExt类总体比较简单,JavaVmExt类是继承JavaVM类,并再次基础上再额外实现了一部分方法。在做进一步分析前,有必要先将JavaVmExt的类关系图画一画,类关系图如下:
- 从图中可以了解到,通过typedef,JavaVM实际上就是_JavaVM
- JavaVmExt类是继承JavaVM类而来的
- _JavaVM的第一个结构体需要指向JNIInvokeInterface,JNIInvokeInterface定义如下,在其中提供了一些控制JavaVM状态的方法
1 2 3 4 5 6 7 8 9 10 11 12 |
struct JNIInvokeInterface { void* reserved0; void* reserved1; void* reserved2; jint (*DestroyJavaVM)(JavaVM*); jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*); jint (*DetachCurrentThread)(JavaVM*); jint (*GetEnv)(JavaVM*, void**, jint); jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); }; |
回想上一篇,我们如果要创建JavaVM的话是通过调用JavaVmExt::Create
方法的,
1 2 3 4 5 6 7 8 9 10 11 12 |
std::unique_ptr<JavaVMExt> JavaVMExt::Create(Runtime* runtime, const RuntimeArgumentMap& runtime_options, std::string* error_msg) NO_THREAD_SAFETY_ANALYSIS { // 内部通过new JavaVMExt来创建,需要注意的时,在Android R这个版本,JavaVMExt的构造函数定义为私有方法了 // 所以在外部无法直接通过new JavaVMExt进行创建 std::unique_ptr<JavaVMExt> java_vm(new JavaVMExt(runtime, runtime_options, error_msg)); if (java_vm && java_vm->globals_.IsValid() && java_vm->weak_globals_.IsValid()) { return java_vm; } return nullptr; } |
如上所说,Android R上已无法通过new JavaVMExt
的方式直接创建JavaVM,下面我们看看JavaVMExt的构造方法,我们重点关注基类JavaVM中的functions
赋值情况,其余部分暂时忽略
1 2 3 4 5 6 7 8 9 10 11 12 13 |
JavaVMExt::JavaVMExt(Runtime* runtime, const RuntimeArgumentMap& runtime_options, std::string* error_msg) : ...... check_jni_(false), // Initialized properly in the constructor body below. ...... unchecked_functions_(&gJniInvokeInterface), ...... { functions = unchecked_functions_; SetCheckJniEnabled(runtime_options.Exists(RuntimeArgumentMap::CheckJni)); } |
在方法的初始化列表中,首先会将gJniInvokeInterface
赋值给unchecked_functions_
。而在方法体内,首先会再将unchecked_functions_
赋值给functions
。同时要注意SetCheckJniEnabled
内部也有一个判断和赋值的过程:
1 2 3 4 5 6 7 8 9 |
bool JavaVMExt::SetCheckJniEnabled(bool enabled) { bool old_check_jni = check_jni_; check_jni_ = enabled; functions = enabled ? GetCheckJniInvokeInterface() : unchecked_functions_; MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); runtime_->GetThreadList()->ForEach(ThreadEnableCheckJni, &check_jni_); return old_check_jni; } |
上述代码中首先判断check_jni_
是否为true,如果为true的话就调用GetCheckJniInvokeInterface
,该方法内部会返回gCheckInvokeInterface
。我们将gJniInvokeInterface
和gCheckInvokeInterface
两个指向的方法对比如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
const JNIInvokeInterface gJniInvokeInterface = { nullptr, // reserved0 nullptr, // reserved1 nullptr, // reserved2 JII::DestroyJavaVM, JII::AttachCurrentThread, JII::DetachCurrentThread, JII::GetEnv, JII::AttachCurrentThreadAsDaemon }; const JNIInvokeInterface gCheckInvokeInterface = { nullptr, // reserved0 nullptr, // reserved1 nullptr, // reserved2 CheckJII::DestroyJavaVM, CheckJII::AttachCurrentThread, CheckJII::DetachCurrentThread, CheckJII::GetEnv, CheckJII::AttachCurrentThreadAsDaemon }; |
上述总结起来就是
functions_
是JavaVMExt基类JavaVM的第一个成员变量,类型为JNIInvokeInterface
。而unchecked_functions_
是JavaVMExt的成员变量,数据类型也是JNIInvokeInterface
,两者的作用稍有区别- 如果不启用jni检查的话,这两个成员变量都指向
gJniInvokeInterface
- 如果启用了jni检查的话,这两个成员变量就指向不同的
JNIInvokeInterface
成员变量的了。其中unchecked_functions_
代表无需jni检查的对象,而functions_
代表需要jni检查的对象。此时会先调用functions_
中的启用JNI检查的方法,这部分方法调用完后会再次调用unchecked_functions_
的方法进行实际的操作
JavaVMExt的内容相对简单,就分析到这里。
InitNativeMethods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
void Runtime::InitNativeMethods() { VLOG(startup) << "Runtime::InitNativeMethods entering"; Thread* self = Thread::Current(); // 这里获取JNIEnv对象 JNIEnv* env = self->GetJniEnv(); CHECK_EQ(self->GetState(), kNative); // 注册运行时本身提供的native方法 RegisterRuntimeNativeMethods(env); // 初始化JNI中使用到的类,初始化要求首先加载了运行时的native方法 WellKnownClasses::Init(env); // 设置 libjavacore / libopenjdk / libicu_jni 三个so库。这三个都是普通的so库 // 正常情况是都可以通过System.loadLibrary进行加载,但是libcore不行 // 是因为libcore就是就是提供System.loadLibrary方法实现的库 // 加载顺序也有一定的讲究,这里libicu_jni需要先初始化,因为libopenjdk内部有依赖于libicu_jni中的方法 { std::string error_msg; if (!java_vm_->LoadNativeLibrary( env, "libicu_jni.so", nullptr, WellKnownClasses::java_lang_Object, &error_msg)) { LOG(FATAL) << "LoadNativeLibrary failed for \"libicu_jni.so\": " << error_msg; } } { std::string error_msg; if (!java_vm_->LoadNativeLibrary( env, "libjavacore.so", nullptr, WellKnownClasses::java_lang_Object, &error_msg)) { LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << error_msg; } } { constexpr const char* kOpenJdkLibrary = kIsDebugBuild ? "libopenjdkd.so" : "libopenjdk.so"; std::string error_msg; if (!java_vm_->LoadNativeLibrary( env, kOpenJdkLibrary, nullptr, WellKnownClasses::java_lang_Object, &error_msg)) { LOG(FATAL) << "LoadNativeLibrary failed for \"" << kOpenJdkLibrary << "\": " << error_msg; } } // 初始化运行时常用到的native方法 WellKnownClasses::LateInit(env); VLOG(startup) << "Runtime::InitNativeMethods exiting"; } |
InitNativeMethods
方法的作用就是用于注册运行时会用的到的native 方法,并且加载三个关键的so库,其中就有openjdk环境。接下来简单看下RegisterRuntimeNativeMethods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { register_dalvik_system_DexFile(env); register_dalvik_system_BaseDexClassLoader(env); register_dalvik_system_VMDebug(env); register_dalvik_system_VMRuntime(env); register_dalvik_system_VMStack(env); register_dalvik_system_ZygoteHooks(env); register_java_lang_Class(env); register_java_lang_Object(env); register_java_lang_invoke_MethodHandleImpl(env); register_java_lang_ref_FinalizerReference(env); register_java_lang_reflect_Array(env); register_java_lang_reflect_Constructor(env); register_java_lang_reflect_Executable(env); register_java_lang_reflect_Field(env); register_java_lang_reflect_Method(env); register_java_lang_reflect_Parameter(env); register_java_lang_reflect_Proxy(env); register_java_lang_ref_Reference(env); register_java_lang_String(env); register_java_lang_StringFactory(env); register_java_lang_System(env); register_java_lang_Thread(env); register_java_lang_Throwable(env); register_java_lang_VMClassLoader(env); register_java_util_concurrent_atomic_AtomicLong(env); register_libcore_util_CharsetUtils(env); register_org_apache_harmony_dalvik_ddmc_DdmServer(env); register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(env); register_sun_misc_Unsafe(env); } |
从上方法体可以看出,开始加载一部分ART虚拟机使用到的native方法,下面注册的是java运行环境中会用到的native方法。我们可以挑其中一个看,这里选择register_dalvik_system_DexFile
register_dalvik_system_DexFile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
// 正常情况是这个方法在源码文件的最后面的,这里方便好看提到前面了 void register_dalvik_system_DexFile(JNIEnv* env) { REGISTER_NATIVE_METHODS("dalvik/system/DexFile"); } static JNINativeMethod gMethods[] = { NATIVE_METHOD(DexFile, closeDexFile, "(Ljava/lang/Object;)Z"), NATIVE_METHOD(DexFile, defineClassNative, "(Ljava/lang/String;" "Ljava/lang/ClassLoader;" "Ljava/lang/Object;" "Ldalvik/system/DexFile;" ")Ljava/lang/Class;"), NATIVE_METHOD(DexFile, getClassNameList, "(Ljava/lang/Object;)[Ljava/lang/String;"), NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"), NATIVE_METHOD(DexFile, getDexOptNeeded, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)I"), NATIVE_METHOD(DexFile, openDexFileNative, "(Ljava/lang/String;" "Ljava/lang/String;" "I" "Ljava/lang/ClassLoader;" "[Ldalvik/system/DexPathList$Element;" ")Ljava/lang/Object;"), NATIVE_METHOD(DexFile, openInMemoryDexFilesNative, "([Ljava/nio/ByteBuffer;" "[[B" "[I" "[I" "Ljava/lang/ClassLoader;" "[Ldalvik/system/DexPathList$Element;" ")Ljava/lang/Object;"), NATIVE_METHOD(DexFile, getClassLoaderContext, "(Ljava/lang/ClassLoader;" "[Ldalvik/system/DexPathList$Element;" ")Ljava/lang/String;"), NATIVE_METHOD(DexFile, verifyInBackgroundNative, "(Ljava/lang/Object;" "Ljava/lang/ClassLoader;" "Ljava/lang/String;" ")V"), NATIVE_METHOD(DexFile, isValidCompilerFilter, "(Ljava/lang/String;)Z"), NATIVE_METHOD(DexFile, isProfileGuidedCompilerFilter, "(Ljava/lang/String;)Z"), NATIVE_METHOD(DexFile, getNonProfileGuidedCompilerFilter, "(Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(DexFile, getSafeModeCompilerFilter, "(Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(DexFile, isBackedByOatFile, "(Ljava/lang/Object;)Z"), NATIVE_METHOD(DexFile, getDexFileStatus, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(DexFile, getDexFileOutputPaths, "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J"), NATIVE_METHOD(DexFile, getDexFileOptimizationStatus, "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), NATIVE_METHOD(DexFile, setTrusted, "(Ljava/lang/Object;)V") }; |
写过JNI方法的同学这里就比较容易理解了,这里就是注册了与上次Java的native方法,当上层Java调用到native定义的方法是,就会通过JNI调用到这里。各个方法的具体实现这里就不多做分析,有兴趣的同学可以选择一两个来查看
好的,这篇就到这里,不过又得留个坑,这里我们看到有涉及JNIEnv这个对象,那么这个JNIEnv对象又是什么东西,提供什么内容呢?我们下一篇见咯