美文网首页
NDK开发之动态注册本地方法

NDK开发之动态注册本地方法

作者: 呵呵_9e25 | 来源:发表于2019-05-16 10:33 被阅读0次
    1. 静态注册
      一般我们写的java native方法在c层都有对应的方法,例如
      java 代码如下
    package com.example.administrator.ndkstudydemo.demo;
    public class CounterNative {
     private native void init();
    }
    

    声明了一个init本地方法,对应的如果静态注册,会生成一个这样的方法在c代码里面,c代码如下

    extern "C"
    JNIEXPORT void JNICALL
    Java_com_example_administrator_ndkstudydemo_demo_CounterNative_init(JNIEnv *env,jobject thiz) {}
    

    这就是典型的静态注册,通过Java_包名_方法名的规则生成

    正常情况下它没什么问题,但是它第一相对不安全,为啥这么说?

    相对不安全
    • 相对不安全是因为首先java代码反编译者(统称hacker)很容易反编译,如果你在so写了核心逻辑,hacker就会通过java里面的名字按图索骥的找到c里面的代码,这样就有利于hacker分析我们的逻辑。
    • 另外为什么我们把相对引了起来,是因为如果了解JNI加载逻辑的的都知道,在System.loadLibrary("so名称");的时候会先调用JNI_OnLoad方法,我们做动态注册也会在这里进行(后面会讲到),那么其实hacker只要在找不到静态注册的方法,就可以分析这个函数里的逻辑,同样可以找到方法。
    1. 动态注册
      首先java代码不变,我们改变c++代码
    jint JNI_OnLoad(JavaVM *vm, void *reserved) {
        JNIEnv *env;
        jvm = vm;
        if (jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
            return -1;
        }
       //动态注册函数
        if (registerNatives(env) != JNI_TRUE) {
            return -1;
        }
        return JNI_VERSION_1_6;
    }
    

    首先重写JNI_OnLoad方法,核心逻辑是注释部分代码if (registerNatives(env) != JNI_TRUE) { return -1; },接下来我们看一下这个registerNatives函数实现

    //java类全路径
    static const char *classPathName = "com/example/administrator/ndkstudydemo/demo/CounterNative";
    //方法数组
    static JNINativeMethod methods[] = {
            {"init", "()V", (void *) Java_com_example_administrator_ndkstudydemo_demo_CounterNative_nativeSetup}
    };
    static int registerNatives(JNIEnv *env) {
        registerNativeMethods(env, classPathName, methods, sizeof(methods) / sizeof(methods[0]));
        return JNI_TRUE;
    }
    
    static int registerNativeMethods(JNIEnv *env, const char *className,
                                     JNINativeMethod *gMethods, int numMethods) {
        jclass clazz = env->FindClass(className);
       //调用env注册本地方法的函数,传入需要修改的方法数组,和需要修改的方法数
        env->RegisterNatives(clazz, gMethods, numMethods);
        return JNI_TRUE;
    }
    

    其实就是调用env的一个注册本地方法的函数env->RegisterNatives(clazz, gMethods, numMethods),它需要三个参数,第一个是方法所在的class对象,还有对应的java方法数组,第三个参数就是方法数组数目,这样就完成了动态注册本地方法

    1. 总结
      java的本地方法名init只是本地方法nativeSetup的一个别名,在vm方法表里存储了他们的对应关系,才使得java方法能正确访问到本地方法

    相关文章

      网友评论

          本文标题:NDK开发之动态注册本地方法

          本文链接:https://www.haomeiwen.com/subject/mfsbaqtx.html