掌握API和控制点(从Java到JNI接口)_37 JNI开发与NDK 05

*.so的入口函数:JNI_OnLoad()

  • 执行System.loadLibrary()函数时, VM会反向调用*.so里的JNI_OnLoad()函数。用途有二:

       1. VM询问此*.so使用的JNI版本编号。
       2. VM要求*.so做一些初期设定工作(Initialization),例如登记<函数名称表>

  • 例如,在Android的/system/lib/libmedia_jni.so档案里,就提供了JNI_OnLoad()函数,其程序码片段为:
// #define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayer-JNI"
// ………
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed\n"); goto bail;
    }

    assert(env != NULL);
    if (register_android_media_MediaPlayer(env) < 0) {
        LOGE("ERROR: MediaPlayer native registration failed\n");
        goto bail;
    }

    /* success -- return valid version number */
    result = JNI_VERSION_1_4;
    bail: return result;
}
// KTHXBYE
  • 此函数回传JNI_VERSION_1_4值给VM,于是VM知道了其所使用的JNI版本了。
  • 此外, JNI_OnLoad()函数也做了一些初期的动作,例如指令:
if (register_android_media_MediaPlayer(env) < 0) {
    LOGE("ERROR: MediaPlayer native registration failed\n");
    goto bail;
}
  • 就将此*.so的<函数名称表>登记到VM里,以便能加快后续调用本地函数之效率。
     

 JNI_OnUnLoad()函数与JNI_OnLoad()先对应

  • 当VM释放该C模块时,则会调用JNI_OnUnload()函数来进行善后清除动作

registerNativeMethods()函数之用途

  • Java类别透过VM而调用到本地函数。
  • 一般是仰赖VM去寻找*.so里的本地函数。如果需要连续调用很多次,每次都需要寻找一遍,会多花许多时间。

此时, 将此*.so的<函数名称表>登记到VM里。例如, 在Android的/system/lib/libmedia_jni.so档案里的程序码片段如下:

// #define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayer-JNI"
// ………
static JNINativeMethod gMethods[] = {
    {"setDataSource", "(Ljava/lang/String;)V",
    (void *)android_media_MediaPlayer_setDataSource},
    {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
    (void *)android_media_MediaPlayer_setDataSourceFD},
    {"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
    {"prepareAsync", "()V",
    (void *)android_media_MediaPlayer_prepareAsync},
    {“_start", "()V", (void *)android_media_MediaPlayer_start},
    {“_stop", "()V", (void *)android_media_MediaPlayer_stop},
    (省略)
};
// ………
static int register_android_media_MediaPlayer(JNIEnv *env) {
    ………
    return AndroidRuntime::registerNativeMethods(env,
        "android/media/MediaPlayer", gMethods, NELEM(gMethods));
}

// ……….
jint JNI_OnLoad(JavaVM* vm, void* reserved){
    ………
    if (register_android_media_MediaPlayer(env) < 0) {
        LOGE("ERROR: MediaPlayer native registration failed\n");
        goto bail;
    }
// ……….
}
  • JNI_OnLoad()调用register_android_media_MediaPlayer()函数。
  • 此时,就调用到AndroidRuntime::registerNativeMethods()函数,向VM登记gMethods[]表格。
  • 登记gMethods[]表格的用途有二:
    1. 更有效率去找到C函数。
    2. 可在执行期间彈性进行抽换。

  • 由于gMethods[]是一个<名称,函数指针>对照表,在程序执行时,可多次调用
    registerNativeMethods()来更换本地函数之指针,而达到弹性抽换本地函数之目的。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

思忖小下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值