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

前面已经实现了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__); 
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值