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

  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方法能正确访问到本地方法
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容