zoukankan      html  css  js  c++  java
  • android 动态注册JNI函数过程源码分析

    以MediaRecorder为例介绍android中,java层的native函数是如何能找到对应的jni层的函数的。
     
    MediaRecorder.java中,生命了这样的一个方法
    private static native final void native_init();
    那是怎么知道是这个方法的呢?
     
    MediaRecorder.java位于android.media包中,所以native_init的全路径是android.media.MediaRecorder.native_init。显而易见,将“.”替换成“_”就是jni函数的名字了。这里说的就是JNI函数的注册问题,就是将java层的native函数和JNI层函数的具体实现关联起来。
     
    JNI函数的注册有两种方法,一种是静态方法,需要用javah为每个声明了native函数的java类编译出的class文件生成一个头文件,另一种是动态注册,通过数据结构保存关联关系实现注册,这里主要介绍动态注册。
     
    动态注册
    动态注册需要一个数据结构去保存相关的关联关系,这个结构(在jni.h中声明)是:
    typedef struct {
     
     
    const char* name; //java中native函数的名字
     
     
    const char* signature; //Java函数的签名信息,用字符串表示,是参数类型和返回值类型的组合
     
     
    void* fnPtr; } JNINativeMethod; //JNI层函数的函数指针,void*类型
     
     
    在JNI层中(android_media_MediaRecorder.cpp)是如何使用这个结构体的:
     
    static JNINativeMethod gMethods[] = {
     
    {"native_init","()V",(void *)android_media_MediaRecorder_native_init},
     
    };
     
    // This function only registers the native methods, and is called from
    // JNI_OnLoad in android_media_MediaPlayer.cpp
    int register_android_media_MediaRecorder(JNIEnv *env) //什么时候会调用呢?后面介绍
    {
    return AndroidRuntime::registerNativeMethods(env,
    "android/media/MediaRecorder", gMethods, NELEM(gMethods));
    }
    利用AndroidRuntime类提供的registerNativeMethods函数完成注册工作
     
    /*
    * Register native methods using JNI.
    */
    /*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
    const char* className, const JNINativeMethod* gMethods, int numMethods) //位于AndroidRuntime.cpp
    {
    return jniRegisterNativeMethods(env, className, gMethods, numMethods);
    }
     
    /*
    * Register native JNI-callable methods.
    *
    * "className" looks like "java/lang/String".
    */
    int jniRegisterNativeMethods(JNIEnv* env, const char* className,const JNINativeMethod* gMethods, int numMethods) //位于JNIHelp.c
    { jclass clazz;
    LOGV("Registering %s natives\n", className);
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL)
    {
    LOGE("Native registration unable to find class '%s'\n", className); return -1;
    }
    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
    {
    LOGE("RegisterNatives failed for '%s'\n", className); return -1;
    } return 0;}
     
     
    实际上所有的注册工作最后就是调用:
    (*env)->RegisterNatives(env,clazz,gMethods,numMethods)完成。那么这些动态注册的函数是什么时候和什么地方调用的呢?其实,当Java层通过System.loadLibrary加载完JNI动态库之后,就会查找库中叫JNI_OnLoad函数,通过调用它完成动态注册的工作。
    externint register_android_media_MediaRecorder(JNIEnv *env);
    jint JNI_OnLoad(JavaVM* vm, void* reserved) //JavaVM* vm是Java虚拟机在JNI层的对象,每一个java进程只有一个JVM
    {
    JNIEnv* env = NULL; //每一个线程有一个JNIEnv对象
    jint result = -1;
     
    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    LOGE("ERROR: GetEnv failed\n");
    goto bail;
    }
     
     
    if (register_android_media_MediaRecorder(env) < 0) { //动态注册MediaRecorder的JNI函数
    LOGE("ERROR: MediaRecorder native registration failed\n");
    goto bail;
    } /* success -- return valid version number */
    result = JNI_VERSION_1_4;
     
    bail:
    return result;
    }
     
  • 相关阅读:
    将list<对象>转换成DataTable,把DataTable转换成参数传入存储过程实现批量插入数据
    DataTable和List集合互转
    Sql2008中使用DataTable作为存储过程的参数
    jquery实现很简单的DIV拖动
    //禁用右键、文本选择功能、复制按键
    jquery---点击弹出层
    读取xml字符串
    mogodb安装,复制,副本集
    windows服务器安装zabbix客户端
    系统初始化脚本(Centos7.2)
  • 原文地址:https://www.cnblogs.com/chiefhsing/p/2892815.html
Copyright © 2011-2022 走看看