NDK開(kāi)發(fā)之動(dòng)態(tài)注冊(cè)本地方法

  1. 靜態(tài)注冊(cè)
    一般我們寫(xiě)的java native方法在c層都有對(duì)應(yīng)的方法,例如
    java 代碼如下
package com.example.administrator.ndkstudydemo.demo;
public class CounterNative {
 private native void init();
}

聲明了一個(gè)init本地方法,對(duì)應(yīng)的如果靜態(tài)注冊(cè),會(huì)生成一個(gè)這樣的方法在c代碼里面,c代碼如下

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

這就是典型的靜態(tài)注冊(cè),通過(guò)Java_包名_方法名的規(guī)則生成

正常情況下它沒(méi)什么問(wèn)題,但是它第一相對(duì)不安全,為啥這么說(shuō)?

相對(duì)不安全
  • 相對(duì)不安全是因?yàn)槭紫萰ava代碼反編譯者(統(tǒng)稱(chēng)hacker)很容易反編譯,如果你在so寫(xiě)了核心邏輯,hacker就會(huì)通過(guò)java里面的名字按圖索驥的找到c里面的代碼,這樣就有利于hacker分析我們的邏輯。
  • 另外為什么我們把相對(duì)引了起來(lái),是因?yàn)槿绻私?code>JNI加載邏輯的的都知道,在System.loadLibrary("so名稱(chēng)");的時(shí)候會(huì)先調(diào)用JNI_OnLoad方法,我們做動(dòng)態(tài)注冊(cè)也會(huì)在這里進(jìn)行(后面會(huì)講到),那么其實(shí)hacker只要在找不到靜態(tài)注冊(cè)的方法,就可以分析這個(gè)函數(shù)里的邏輯,同樣可以找到方法。
  1. 動(dòng)態(tài)注冊(cè)
    首先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;
    }
   //動(dòng)態(tài)注冊(cè)函數(shù)
    if (registerNatives(env) != JNI_TRUE) {
        return -1;
    }
    return JNI_VERSION_1_6;
}

首先重寫(xiě)JNI_OnLoad方法,核心邏輯是注釋部分代碼if (registerNatives(env) != JNI_TRUE) { return -1; },接下來(lái)我們看一下這個(gè)registerNatives函數(shù)實(shí)現(xiàn)

//java類(lèi)全路徑
static const char *classPathName = "com/example/administrator/ndkstudydemo/demo/CounterNative";
//方法數(shù)組
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);
   //調(diào)用env注冊(cè)本地方法的函數(shù),傳入需要修改的方法數(shù)組,和需要修改的方法數(shù)
    env->RegisterNatives(clazz, gMethods, numMethods);
    return JNI_TRUE;
}

其實(shí)就是調(diào)用env的一個(gè)注冊(cè)本地方法的函數(shù)env->RegisterNatives(clazz, gMethods, numMethods),它需要三個(gè)參數(shù),第一個(gè)是方法所在的class對(duì)象,還有對(duì)應(yīng)的java方法數(shù)組,第三個(gè)參數(shù)就是方法數(shù)組數(shù)目,這樣就完成了動(dòng)態(tài)注冊(cè)本地方法

  1. 總結(jié)
    java的本地方法名init只是本地方法nativeSetup的一個(gè)別名,在vm方法表里存儲(chǔ)了他們的對(duì)應(yīng)關(guān)系,才使得java方法能正確訪問(wèn)到本地方法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容