在上两篇文章中(http://www.linuxidc.com/Linux/2011-07/38978.htm与 http://www.linuxidc.com/Linux/2011-07/38980.htm),我
们介绍了如何为Android 系统的硬件编写驱动程序,包括如何在Linux 内核空间实现内核驱动程序和在用户空间实现硬件抽象
层接口。实现这两者的目的是为了向更上一层提供硬件访问接口,即为Android 的ApplicationFrameworks 层提供硬件服务。
我们知道,Android 系统的应用程序是用Java 语言编写的,而硬件驱动程序是用C 语言来实现的,那么,Java 接口如何去访
问C 接口呢?众所周知,Java 提供了JNI 方法调用,同样,在Android 系统中,Java应用程序通过JNI 来调用硬件抽象层接口。
在这一篇文章中,我们将介绍如何为Android硬件抽象层接口编写JNI 方法,以便使得上层的Java 应用程序能够使用下层提
供的硬件服务。
一. 参照在Ubuntu 上为Android增加硬件抽象层(HAL)模块访问Linux 内核驱动程序一文,准备好硬件抽象层模块,确保
Android 系统镜像文件system.img 已经包含hello.default 模块。
二. 进入到frameworks/base/services/jni 目录,新建com_Android_server_HelloService.cpp 文件:
linuxidc@www.linuxidc.com:~/Android$cd frameworks/base/services/jni
linuxidc@www.linuxidc.com:~/Android/frameworks/base/services/jni$vi com_android_server_HelloService.cpp
在com_Android_server_HelloService.cpp文件中,实现JNI 方法。注意文件的命令方法,com_android_server 前缀表示的是包
名,表示硬件服务HelloService是放在frameworks/base/services/java 目录下的com/android/server 目录的,即存在一个命令为
com.android.server.HelloService的类。这里,我们暂时略去HelloService 类的描述,在下一篇文章中,我们将回到HelloService
类来。简单地说,HelloService是一个提供Java 接口的硬件访问服务类。
首先是包含相应的头文件:
1.#define LOG_TAG"HelloService"
2.#include"jni.h"
3.#include"JNIHelp.h"
4.#include"Android_runtime/AndroidRuntime.h"
5.#include<utils/misc.h>
6.#include<utils/Log.h>
7.#include<hardware/hardware.h>
8.#include<hardware/hello.h>
9.#include<stdio.h> 接着定义hello_init、hello_getVal和hello_setVal 三个JNI 方法:
1.namespace Android
2.{
3. /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/
4. structhello_device_t* hello_device = NULL;
5. /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val 的值*/
6. static voidhello_setVal(JNIEnv* env, jobject clazz, jint value) {
7. int val = value;
8. LOGI("HelloJNI: set value %d to device.", val);
9. if(!hello_device) {
10. LOGI("HelloJNI: device is not open.");
11. return;
12. }
13.
14.hello_device->set_val(hello_device, val);
15. }
16. /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val 的值*/
17. static jinthello_getVal(JNIEnv* env, jobject clazz) {
18. int val = 0;
19. if(!hello_device){
20. LOGI("HelloJNI: device is not open.");
21. return val;
22. }
23.hello_device->get_val(hello_device, &val);
24.
25. LOGI("HelloJNI: get value %d from device.", val);
26.
27. return val;
28. }
29. /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
30. static inline inthello_device_open(const hw_module_t* module, struct hello_device_t** device) {
31. returnmodule->methods->open(module, HELLO_HARDWARE_MODULE_ID, (structhw_device_t**)device);
32. }
33. /*通过硬件模块ID 来加载指定的硬件抽象层模块并打开硬件*/
34. static jbooleanhello_init(JNIEnv* env, jclass clazz) {
35. hello_module_t*module;
36.
37. LOGI("HelloJNI: initializing......");
38.if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const structhw_module_t**)&module) == 0) {
39. LOGI("HelloJNI: hello Stub found.");
40. if(hello_device_open(&(module->common),&hello_device) == 0) {
41. LOGI("HelloJNI: hello device is open.");
42. return 0;
43. }
44. LOGE("HelloJNI: failed to open hello device.");
45. return -1;
46. }
47. LOGE("HelloJNI: failed to get hello stub module.");
48. return -1;
49. }
50. /*JNI 方法表*/
51. static constJNINativeMethod method_table[] = {
52.{"init_native", "()Z", (void*)hello_init},
53.{"setVal_native", "(I)V", (void*)hello_setVal},
54.{"getVal_native", "()I", (void*)hello_getVal},
55. };
56. /*注册JNI 方法*/
57. intregister_Android_server_HelloService(JNIEnv *env) {
58. returnjniRegisterNativeMethods(env, "com/Android/server/HelloService",method_table, NELEM(method_table));
59. }
60.};
注意,在hello_init函数中,通过Android 硬件抽象层提供的hw_get_module 方法来加载模块ID为HELLO_HARDWARE_MODULE_ID
的硬件抽象层模块,其中,HELLO_HARDWARE_MODULE_ID是在<hardware/hello.h>中定义的。Android 硬件抽象层会根据
HELLO_HARDWARE_MODULE_ID的值在Android 系统的/system/lib/hw目录中找到相应的模块,然后加载起来,并且返回
hw_module_t 接口给调用者使用。在jniRegisterNativeMethods 函数中,第二个参数的值必须对应HelloService 所在的包的路径,
即com.android.server.HelloService。
三. 修改同目录下的onload.cpp 文件,首先在namespace Android 增加register_android_server_HelloService函数声明:
namespace Android {
intregister_Android_server_HelloService(JNIEnv *env);
};
在JNI_onLoad增加register_Android_server_HelloService 函数调用:
extern "C"jint JNI_onLoad(JavaVM* vm, void* reserved)
{
register_android_server_HelloService(JNIEnv*env);
}
这样,在Android 系统初始化时,就会自动加载该JNI 方法调用表。
四. 修改同目录下的Android.mk 文件,在LOCAL_SRC_FILES 变量中增加一行:
LOCAL_SRC_FILES:= /
com_android_server_AlarmManagerService.cpp/
com_android_server_BatteryService.cpp/
com_android_server_InputManager.cpp/
com_android_server_LightsService.cpp/
com_android_server_PowerManagerService.cpp/
com_android_server_SystemServer.cpp/
com_android_server_UsbService.cpp/
com_android_server_VibratorService.cpp/
com_android_server_location_GpsLocationProvider.cpp/
com_android_server_HelloService.cpp/
onload.cpp
五. 编译和重新找亿system.img:
USER-NAME@MACHINE-NAME:~/Android$mmm frameworks/base/services/jni
USER-NAME@MACHINE-NAME:~/Android$make snod
这样,重新打包的system.img镜像文件就包含我们刚才编写的JNI 方法了,也就是我们可以通过Android 系统的
Application Frameworks层提供的硬件服务HelloService 来调用这些JNI 方法,进而调用低层的硬件抽象层接口去访问硬件了。
前面提到, 在这篇文章中, 我们暂时忽略了HelloService 类的实现, 在下一篇文章中
http://www.linuxidc.com/Linux/2011-07/38982.htm,我们将描述如何实现硬件服务HelloService。