您的位置:首页 > 其它

MT6572平台加入呼吸灯功能——编写JNI

2013-11-11 16:31 344 查看
只完成驱动层和HAL层的开发,还不足以让上层APP访问到我们的硬件设备,APP客户端界面基本上都是java语言开发的,而我们前面开发的驱动层和HAL层都是用Native语言(C/C++语言)编写的,如何让上层Java语言能够调用Native语言,这就是JNI (Java Native Interface)技术完成的,当然,Native语言也可以利用JNI技术调用Java层的方法(C/C++语言中称为函数)。经过了JNI这道门,后面就进入Java世界了。

这里进行的JNI层开发以及下一篇将要讲述的Framework层API接口的开发是严格按照android推荐的框架格式来进行的。上层应用也可以单独写自己的JNI层代码来访问硬件设备。

一)编写调用HAL模块的Service文件com_android_server_BreathLedsService.cpp

进入frameworks/base/services/jni/目录,新建com_android_server_BreathLedsService.cpp:

#define LOG_TAG "BreathLedsService"

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"

#include <hardware/hw_breath_leds.h>
#include <hardware/hardware.h>

namespace android {

struct breath_leds_device_t* leds_dev = NULL;  //hw_breath_leds.h中定义的HAL设备结构体

static void leds_ctl_open(const struct hw_module_t* module, struct breath_leds_device_t** dev)
{
    //调用open函数进行一系列初始化工作
    module->methods->open(module, BREATH_LEDS_HW_MODULE_ID, (struct hw_device_t**) dev);
}

static void init_leds(JNIEnv* env, jobject thiz)
{
    breath_leds_module_t* leds_module = NULL;
    
    //通过hw_get_module函数查找HAL模块
    if (hw_get_module(BREATH_LEDS_HW_MODULE_ID, (const hw_module_t**) &leds_module) == 0)
    {
        leds_ctl_open(&(leds_module->breath_module), &leds_dev);   //装载leds_dev
    }
}

static void set_brightness_leds(JNIEnv* env, jobject thiz, jint level)
{
    leds_dev->set_breath_value(leds_dev, level);
}

//定义jni函数映射
static const JNINativeMethod method_tab[] = {
    {"init_native", "()V", (void*) init_leds},
    {"set_brightness_native", "(I)V", (void*) set_brightness_leds},
};

int register_android_server_BreathLedsService(JNIEnv *env)
{
    return AndroidRuntime::registerNativeMethods(env, 
                  "com/android/server/BreathLedsService", method_tab, NELEM(method_tab));
}

}  /*  namespace android  */

调用HAL模块涉及到一个非常重要的hw_get_module函数,基本上,JNI层就是靠该函数与HAL模块产生联系,该函数可通过HAL模块.h中定义的模块ID宏找到HAL模块,并得到hw_module_t结构体,然后调用hw_module_t.hw_module_methods_t.open函数来初始化驱动。除此之外,该文件还实现了开放给Java层的接口实现set_brightness_leds。

另外注意文件的命名方法,com_android_server前缀表示包名,表示服务类BreathLedsService放在frameworks/base/services/java目录下的com/android/server/目录下,即存在一个com.android.server.BreathLedsService类,实际上我们可以将com_android_server_BreathLedsService.cpp和下篇将要讲到的BreathLedsService.java看成一个文件,com_android_server_BreathLedsService.cpp中主要实现了BreathLedsService.java中没有实现的内容(需要使用Native语言实现)。关于BreathLedsService类我们在下篇说。

JNI代码里面一般都会含有一个JNINativeMethod数组类型的JNI函数映射表,以及一个服务注册函数register_android_server_BreathLedsService。这里来看看JNI函数映射表:

static const JNINativeMethod method_tab[] = {
    {"init_native", "()V", (void*) init_leds},
    {"set_brightness_native", "(I)V", (void*) set_brightness_leds},
};

以{"set_brightness_native", "(I)V", (void*) set_brightness_leds}为例,第三个void指针变量很显然指向的是本文件中的set_brightness_leds函数,而第一个字符串"set_brightness_native"表示的是对应的java语言中的方法名为set_brightness_native,即当java语言中调用set_brightness_native()时,实际执行的是本地的set_brightness_leds函数,set_brightness_leds()是set_brightness_native()的具体实现。在下一篇我们可以看到,set_brightness_native()在java代码中仅仅只是一个声明为没有具体实现。最后来说下
"(I)V" ,这个是JNI规范定义的Java中对应函数的签名信息,由参数类型和返回值类型共同组成。他的格式是:

(参数1类型标示参数2类型标示...参数n类型标示)返回值类型标示

void对应的类型标示为V,int类型对应的类型标示为I,所以"(I)V"表示set_brightness_native()方法含有一个int型参数,没有返回值。更多类型标示可以去百度JNI详细。

而服务注册函数register_android_server_BreathLedsService则将com_android_server_BreathLedsService.cpp与BreathLedsService.java关联起来。这里用的是动态注册方法,还有一种静态注册方法,完全是按照文件名来匹配的,具体应用自查。

二)修改onload.cpp,使系统启动时能自动加载上述服务

打开frameworks/base/services/jni/onload.cpp:

1,在namespace android { }中加入函数声明:

int register_android_server_BreathLedsService(JNIEnv* env);

2,在extern "C" jint JNI_OnLoad(){ }中添加函数调用:

register_android_server_BreathLedsService(env);


三)修改Android.mk,添加编译路径

打开打开frameworks/base/services/jni/Android.mk,在LOCAL_SRC_FILES变量中添加:

com_android_server_BreathLedsService.cpp \


四)编译
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: