定制Android系统开发之八——实现从JNI到Java的回调

来源:互联网 发布:天狮多种vb片功效 编辑:程序博客网 时间:2024/06/01 09:24

前面已经实现了APP->xxxManager->xxxManagerService->jni的函数调用,这篇博文就来实现jni->xxxManagerService的回调。

使用环境

我先说一下我的应用环境吧。我在有一个对设备节点进行轮询的线程,当能读到消息的时候就调用jni中的一个回调函数。回调函数会调用java中的函数来传递消息。

函数定义

JNI中回调函数的声明如下:

get_msg_cb(message *evtmsg)

它的参数是一个结构体,我在回调函数里将解析这个结构体,转化成int数组。再调用下面的Java函数:

private void recvMsgFromNative(int[] msg)

JNIEnv的对象

但凡做过JNI开发,都会知道,在调用JNI函数的时候,一个JNIEnv指针是必须具备的。在从Java调用的JNI函数的参数列表里面,第一个参数就是一个JNIEnv指针。但是对于我的get_msg_cb()函数,是从底层回调的,没有这个JNIEnv指针,该怎么办呢?

在JNI中,JNIEnv指针是与线程一一对应的,也就是说,每个线程都有一个JNIEnv,在线程一里不能使用线程二的JNIEnv。所以在register_android_server_iflytek_radiomanagerservice里面把JNIEnv保存在一个全局变量中,然后在get_msg_cb()函数里面使用,是不行的。但是,有一个对象却是全局的,那就是JavaVM。我们可以将JavaVM保存在全局变量中,然后通过JavaVM在get_msg_cb()里面获取JNIEnv指针。

static JavaVM * gJavaVM;int register_android_server_radiomanagerservice(JNIEnv* env) {    // 此处省略很多行    // 获取JavaVM指针,保存在全局变量里面。    env->GetJavaVM(&gJavaVM);    return 0;}

获取对象和函数的引用

Java中的非static函数是属于某个对象的,要想调用这个函数,就必须拥有这个对象的引用。我在Java里面定义了一个nativeInit()函数,并按照上一篇博文的方法映射到jni中的nativeInit()函数。在RadioManagerService()的构造函数里调用nativeInit()函数。在NativeInit()函数里面,通过JNIEnv和jobject获取了RadioManagerService对象的实例并保存在了全局变量中。同时还获取了recvMsgFromNative()函数的ID并保存在全局变量中。代码如下:

static jobject gRadioManagerServiceObj;static jclass gRadioManagerServiceClass;static void nativeInit(JNIEnv* env, jobject obj) {    ALOGD("nativeInit() is called");    mcu_rpc_init();    // 获取UartManagerService对象的实例    gRadioManagerServiceObj = env->NewGlobalRef(obj);    // Callbacks    FIND_CLASS(gRadioManagerServiceClass,            "com/android/server/RadioManagerService");    GET_METHOD_ID(gRadioManagerServiceClassInfo.recvMsgFromNative,            gRadioManagerServiceClass, "recvMsgFromNative", "([I)V");    // 注册回调    mcu_rpc_set_callback(get_msg_cb);}

JNI函数的实现

下面就是JNI函数的实现了。这里直接给出代码:

void get_msg_cb(message *evtmsg) {    ALOGD("get_msg_cb() is called");    int i;    // 通过JavaVM获取JNIEnv指针    JNIEnv* env;    gJavaVM->AttachCurrentThread(&env, NULL);    if (env == NULL) {        ALOGD("JNIEnv is null");        return;    }    // 从message结构体获取数组    jintArray returnArray = getArrayFromMsg(env, evtmsg);    // 调用Java中的函数    if (gRadioManagerServiceObj != NULL) {        env->CallVoidMethod(gRadioManagerServiceObj,                gRadioManagerServiceClassInfo.recvMsgFromNative, returnArray);    }    // 这里的returnArray是在getArrayFromMsg()函数中通过env->NewIntArray()新建出来的,所以必须delete掉,以释放空间,不然会有内存泄露    env->DeleteLocalRef(returnArray);    checkAndClearExceptionFromCallback(env, __FUNCTION__); }
0 0