Android中获取native层Runtime的方法

2,317

通过 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;