【手写实例】为服务层实现jni方法的详解

为服务层实现jni方法的详解

这里说下我们的终极目的:给Android系统增加一个服务来控制开发板上的一个IO口。

花费三个小时的时间写完了mydrv的hal。编写的时候主要还是注意那两个结构体。还有各函数的参数。欢迎查看我的HAL层
https://blog.csdn.net/daoliting5268/article/details/87874521

下面开始写jni,这就写到了native libraries层。不再抄简易手册了,直接开始写mydrv的jni。

下面简述一下我写jni的过程:

1、首先加载头文件,主要有
include <jni.h>
#include <JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>

#include <utils/misc.h> //杂项,大杂烩没找到文件说明,此处猜应该是工具中的乱七八糟的功能函数。
#include <utils/Log.h>

#include <hardware/hardware.h> //硬件抽象层native方法的头文件引入。
#include <hardware/mydrv.h>
写jni时这几个必须要引入的。

然后再namespace android {}中加上jni统一的注册接口函数:
/注册Java本地接口方法/
int register_android_server_mydrvService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, “com/android/server/MydrvService”, method_table, NELEM(method_table));
}
register_android_server_mydrvService //向Android server中注册mydrv的jni接口。
jniRegisterNativeMethods //native方法的注册函数。
此函数中的四个参数

env 当前的环境变量,这里我们不用配置调用者会自动配置,这里的调用者就是Android系统。

“com/android/server/MydrvService” 这里指明是为服务层的哪个类使用。注意只有这里指明的类才可以调用此jni的native方法。

method_table native方法,以一个table的方式注册。

NELEM(method_table) 这个就不用说了,是table的长度。

然后我们就看下这个method_table是怎么写的。
/Java本地接口方法注册/
static const JNINativeMethod method_table[] = {
{“init_native”, “()I”, (void*)mydrv_init},
{“setVal_native”, “(II)V”, (void*)mydrv_setVal},
};

很简单这个结构体数组是JNINativeMethod类型,这个类型是JNI统一形式,必须是此形式。

table中定义了jni中的方法和硬件驱动层的方法关联。

{“setVal_native”, “(II)V”, (void*)mydrv_setVal},
我们来详细解析一下其中的一个元素中的属性。

“setVal_native” 是硬件抽象层中的native方法

“(II)V” 中()内表示jni方法mydrv_setVal传入的参数类型,这里我们就看下mydrv_setVal函数的定义:
static void mydrv_setVal(JNIEnv* env, jobject clazz, jint ptr, jint value)
发现没有函数传入的参数是两个jint的类型,也就是 int类型对应II。同理"(II)V" 中的V就是函数的返回类型。

(void*)mydrv_setVal 这个就是jni中的方法了,java中会调用此方法。

好了目前为止就可以去具体是先jni方法了,想要控制驱动或者通过HAL控制驱动,那就必须要先打开驱动,这里我们看下是怎么打开的。

这里我们是通过HAL层控制的驱动设备,在init_native函数中打开的,
/加载硬件抽象层模块mydrv/
if (hw_get_module(MYDRV_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0)
首先我们要获取硬件抽象层模块,通过MYDRV_HARDWARE_MODULE_ID获取到。MYDRV_HARDWARE_MODULE_ID是在硬件抽象层中定义的,具体可以看我另外要一篇文章《手写HAL总结》。

获得驱动抽象层模块之后,那就要通过HAL来打开驱动了。
/打开mydrv硬件设备/

    if (mydrv_device_open(&(module->common), &device) == 0)

这里通过了一个函数封装,来看下函数的具体实现:
static inline int mydrv_device_open(const hw_module_t *module, struct mydrv_device_t ** device)
{
return module->methods->open(module, MYDRV_HARDWARE_MODULE_ID, (struct hw_device_t **)device);
}
就是 module->methods->open(module, MYDRV_HARDWARE_MODULE_ID, (struct hw_device_t **)device);这一个方法。
这里会返回一个device的句柄。然后java拿着jni函数,jni拿着这个句柄就可来操作驱动了。

实现完具体操作后,就要来看下我们是怎么把我们这个jni告诉Android系统的。
熟悉Android启动流程肯定会知道,Android启动服务时会首先onload加载jni,所以我们就在onload.java中注册,打开此文件你会发现好多jni函数在这里调用。
我们类比之前的也在namespace android和JNI_OnLoad中同样的格式写进去。
int register_android_server_mydrvService(JNIEnv *env);

register_android_server_mydrvService(env);

就是把我们jni中注册Java本地接口方法写进去。

ok,到此我们的jni就写完了。下面贴上源码,在framework/base/services/jni/路径下添加了一个com_android_server_mydrvservice.cpp(统一的命名规则)
这里要注意,我们目的是为服务层增加,所以此jni时候在services下的。我还知道一种是在core目录下,我只知道core下的这个是系统内部的,会编译成libruntime.so,在Android启动runtime加载java虚拟机前加载的。
源码:


#define LOG_TAG "MydrvServiceJNI"

#include <jni.h>
#include <JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>

#include <utils/misc.h> //杂项,大杂烩没找到文件说明,此处猜应该是工具中的乱七八糟的功能函数。
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/mydrv.h>

#include <stdio.h>

namespace android{


static void mydrv_setVal(JNIEnv* env, jobject clazz, jint ptr, jint value)
{
    /*将ptr转化为mydrv_device_t结构体变量*/
    mydrv_device_t* device = (mydrv_device_t*) ptr;

    if (!device)
    {
        LOGI("device mydrv is not open.");
        return;
    }

    LOGI("set value %d to device mydrv.", value);

    device->set_low(device, value);


}

static inline int mydrv_device_open(const hw_module_t *module, struct mydrv_device_t ** device)
{
    return module->methods->open(module, MYDRV_HARDWARE_MODULE_ID, (struct hw_device_t **)device);
}

static jint mydrv_init(JNIEnv* env, jclass clazz){

    mydrv_module_t* module;
    mydrv_device_t* device;

    LOGI("Initializing HAL stub mydrv.....");

    /*加载硬件抽象层模块mydrv*/
    if (hw_get_module(MYDRV_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0)
    {
        LOGI("device mydrv found.");

        /*打开mydrv硬件设备*/

        if (mydrv_device_open(&(module->common), &device) == 0)
        {
            LOGI("device mydrv is open");

            /*将mydrv_device_t转换为整形值返回*/
            return (jint)device;
        }

        LOGI("failed to open device mydrv");

        return 0;
    }

    LOGI("failed to get HAL stub mydrv.");
    
    return 0;
}


/*Java本地接口方法注册*/
static const JNINativeMethod method_table[] = {
    {"init_native", "()I", (void*)mydrv_init},
    {"setVal_native", "(II)V", (void*)mydrv_setVal},
};

/*注册Java本地接口方法*/ 
int register_android_server_mydrvService(JNIEnv *env) 
{ 
    return jniRegisterNativeMethods(env, "com/android/server/MydrvService", method_table, NELEM(method_table)); 
} 
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值