JNI的小总结

好久不见. 提交于 2019-12-06 08:33:30

code location

dalvik/libnativehelper/include/nativehelper/jni.h

frameworks/base/core/jni


android的JNI的调用过程中有个很重要的地方就是参数映射。体现在一个叫JNINativeMethod的结构体里面

JNINativeMethod在jni中有定义。

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;
name对应java中的method name; signature是参数列表,由一串字符串表示,fnPtr是function pointer, 指向jni中的method。

最难理解的就是signature了,里面包含JAVA<——>C/C++之间的参数的map,即每个java类型,都有一个c/c++类型与之对应。

这些对应关系在



这段时间刚好看了蓝牙耳机部分,涉及到JNI调用,小小的总结一下。

JNI是JAVA Native Interface的缩写,意思是“JAVA 本地接口”。JNI帮助JAVA能和其它编程语言(C++ , C, 汇编)和库进行交互。

JNI的架构分为四个层次,应用程序---> JAVA框架(JAVA类(声明本地接口))---> JNI ---> C/C++本地库

JNI需要在JAVA源代码中声明,在C/C++中实现JNI的各种方法,并注册到系统中。

举例说明:在BluetoothHandsfree.java中,要简历蓝牙耳机的socket连接,调用下列语句

mIncomingSco = createScoSocket();
mIncomingSco.accept();

createScoSocket()创建一个ScoSocket对象,然后调用accept方法建立连接

1022     private ScoSocket createScoSocket() {
1023         return new ScoSocket(mPowerManager, mHandler, SCO_ACCEPTED, SCO_CONNECTED, SCO_CLOSED);
1024     }

在ScoSocket类里面

110     public synchronized boolean accept() {
             //... 省略无关语句
116         if (acceptNative()) {
117             mState = STATE_ACCEPT;
118             return true;
119         }

             //... 省略无关语句
123     }

这里面的acceptNative()就是个JNI方法,在ScoSocket类里面声明并调用

124     private native boolean acceptNative();

这个方法在/frameworks/base/core/jni/android_bluetooth_ScoSocket.cpp内实现,并且注册到系统中

675 static JNINativeMethod sMethods[] = {
           //... 省略无关语句
680     {"acceptNative", "()Z", (void *)acceptNative},
682 };

JNINativeMethod结构体是JNI的核心,在jni.h里面定义

“acceptNative”:JNI函数的名称

“()Z”JNI函数的参数和返回值,"()"填的是参数(这里为空)例如:Ljava/lang/String; I 参数之间用分好隔开,这些大写字母(L, Z...)在JAVA和JNI里面都有对应的类型,L对应JAVA 对象,JNI的jobject类型; Z对应JAVA的boolean类型, JNI的jboolean类型。

然后向AndroidRuntime注册这些Native方法

684 int register_android_bluetooth_ScoSocket(JNIEnv *env) {
685     return AndroidRuntime::registerNativeMethods(env,
686             "android/bluetooth/ScoSocket", sMethods, NELEM(sMethods));
687 }
AndroidRuntime.cpp与android_bluetooth_Socket.cpp处于同一目录

它会调用register_android_bluetooth_ScoSocket(JNIEnv *env)进行注册

 

注册过程在启动虚拟机之后开始

int AndroidRuntime::startReg(JNIEnv* env)

        //... 省略无关代码
1312     if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
1313         env->PopLocalFrame(NULL);
1314         return -1;
1315     }
       //... 省略无关代码
1321 }

 

static const RegJNIRec gRegJNI[] = {

    //... 省略无关代码

    REG_JNI(register_android_bluetooth_BluetoothSocket),

}

 

REG_JNI 是一个宏定义,对注册函数进行包装

1155     #define REG_JNI(name)      { name, #name }
1156     struct RegJNIRec {
1157         int (*mProc)(JNIEnv*);
1158         const char* mName;
1159     };

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!