通过 dlsym 获取
void *artHandle = ndk_dlopen("libart.so", RTLD_NOW);
__android_log_print(ANDROID_LOG_INFO, TAG, "artHandle=%p\n", artHandle);
if(artHandle == NULL) {
return false;
}
// art::Runtime::instance_
void **instance_ = static_cast<void **>(ndk_dlsym(artHandle, "_ZN3art7Runtime9instance_E"));
__android_log_print(ANDROID_LOG_INFO, TAG, "instance_=%p\n", *instance_);
void *runtime = *instance_;
因为dlsym
返回的是指定符号的指针,而art::Runtime::instance_
的类型是Runtime *
,其本身就是一个指针(源码地址见 android-7.1.2_r39/runtime/runtime.cc#instance_),所以返回值强转为void **
,即指向一个指针的指针。
通过 JavaVm 获取
在JNI中,每一个Java中的native方法对应的jni函数,都有一个JNIEnv* 指针入参,通过该指针变量的GetJavaVM函数,我们可以拿到一个JavaVM*的指针变量
JavaVM *javaVM;
env->GetJavaVM(&javaVM);
而JavaVm在JNI中的数据结构定义为(源码地址见 android-9.0.0_r20/include_jni/jni.h)
typedef _JavaVM JavaVM;
struct _JavaVM {
const struct JNIInvokeInterface* functions;
};
可以看到,只有一个JNIInvokeInterface*指针变量
而在Android中,实际使用的是JavaVMExt(源码地址见 android-9.0.0_r20/runtime/java_vm_ext.h),它继承了JavaVM,它的数据结构可以简单理解为
class JavaVMExt : public JavaVM {
private:
Runtime* const runtime_;
}
根据内存布局,我们可以将JavaVMExt等效定义为
struct JavaVMExt {
void *functions;
void *runtime;
};
指针类型,在32位上占4字节,在64位上占8字节。
因此我们只需要将我们之前拿到的JavaVM *指针,强制转换为JavaVMExt*指针,通过JavaVMExt*指针拿到Runtime*指针
JavaVM *javaVM;
env->GetJavaVM(&javaVM);
JavaVMExt *javaVMExt = (JavaVMExt *) javaVM;
void *runtime = javaVMExt->runtime;