现在在Android上的HAL开发总的来说还是随意性比较大,Android也并没有规范好一个具体的框架,下面我将根据Jollen的Mokoid工程,自己做了一些改动,分别给大家介绍一下三种实现方式。

这篇先介绍最简单的一种实现方式 - Java应用程序直接调用JNI库。

由于JNI技术的存在,在Android中,java程序能够很好的调用C/C++库。我们这里设计一个简单的HAL,一共只有三层: HAL stub <-> JNI 库 <-> JAVA应用程序。

我们现看看HAL stub的代码:

  1. int led_device_close(struct hw_device_t* device)
  2. {
  3. struct led_control_device_t* ctx = (struct led_control_device_t*)device;
  4. if (ctx) {
  5. free(ctx);
  6. }
  7. return 0;
  8. }
  9. int led_on(struct led_control_device_t *dev, int32_t led)
  10. {
  11. LOGI("LED Stub: set %d on.", led);
  12. return 0;
  13. }
  14. int led_off(struct led_control_device_t *dev, int32_t led)
  15. {
  16. LOGI("LED Stub: set %d off.", led);
  17. return 0;
  18. }
  19. static int led_device_open(const struct hw_module_t* module, const char* name,
  20. struct hw_device_t** device)
  21. {
  22. struct led_control_device_t *dev;
  23. dev = (struct led_control_device_t *)malloc(sizeof(*dev));
  24. memset(dev, 0, sizeof(*dev));
  25. dev->common.tag =  HARDWARE_DEVICE_TAG;
  26. dev->common.version = 0;
  27. dev->common.module = module;
  28. dev->common.close = led_device_close;
  29. dev->set_on = led_on;
  30. dev->set_off = led_off;
  31. *device = &dev->common;
  32. success:
  33. return 0;
  34. }
  35. static struct hw_module_methods_t led_module_methods = {
  36. open: led_device_open
  37. };
  38. const struct led_module_t HAL_MODULE_INFO_SYM = {
  39. common: {
  40. tag: HARDWARE_MODULE_TAG,
  41. version_major: 1,
  42. version_minor: 0,
  43. id: LED_HARDWARE_MODULE_ID,
  44. name: "Sample LED Stub",
  45. author: "The Mokoid Open Source Project",
  46. methods: &led_module_methods,
  47. }
  48. /* supporting APIs go here */
  49. };

我在前面关于HAL技术的文章中已经介绍了如何写HAL stub,需要注意的只有hw_module_t和hw_device_t这两个数据结构,这里就不复述了。

下面看看JNI层代码:

  1. struct led_control_device_t *sLedDevice = NULL;
  2. static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led)
  3. {
  4. LOGI("LedService JNI: mokoid_setOn() is invoked.");
  5. if (sLedDevice == NULL) {
  6. LOGI("LedService JNI: sLedDevice was not fetched correctly.");
  7. return -1;
  8. } else {
  9. return sLedDevice->set_on(sLedDevice, led);
  10. }
  11. }
  12. static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led)
  13. {
  14. LOGI("LedService JNI: mokoid_setOff() is invoked.");
  15. if (sLedDevice == NULL) {
  16. LOGI("LedService JNI: sLedDevice was not fetched correctly.");
  17. return -1;
  18. } else {
  19. return sLedDevice->set_off(sLedDevice, led);
  20. }
  21. }
  22. /** helper APIs */
  23. static inline int led_control_open(const struct hw_module_t* module,
  24. struct led_control_device_t** device) {
  25. return module->methods->open(module,
  26. LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
  27. }
  28. static jboolean mokoid_init(JNIEnv *env, jclass clazz)
  29. {
  30. led_module_t* module;
  31. if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
  32. LOGI("LedService JNI: LED Stub found.");
  33. if (led_control_open(&module->common, &sLedDevice) == 0) {
  34. LOGI("LedService JNI: Got Stub operations.");
  35. return 0;
  36. }
  37. }
  38. LOGE("LedService JNI: Get Stub operations failed.");
  39. return -1;
  40. }
  41. static const JNINativeMethod gMethods[] = {
  42. { "_init",      "()Z",  (void *)mokoid_init },
  43. { "_set_on",        "(I)Z", (void *)mokoid_setOn },
  44. { "_set_off",       "(I)Z", (void *)mokoid_setOff },
  45. };
  46. int register_mokoid_server_LedService(JNIEnv* env) {
  47. static const char* const kClassName =
  48. "com/mokoid/LedClient/LedClient";
  49. jclass clazz;
  50. /* look up the class */
  51. clazz = env->FindClass(kClassName);
  52. if (clazz == NULL) {
  53. LOGE("Can't find class %s\n", kClassName);
  54. return -1;
  55. }
  56. /* register all the methods */
  57. if (env->RegisterNatives(clazz, gMethods,
  58. sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
  59. {
  60. LOGE("Failed registering methods for %s\n", kClassName);
  61. return -1;
  62. }
  63. /* fill out the rest of the ID cache */
  64. return 0;
  65. }
  66. extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
  67. {
  68. JNIEnv* env = NULL;
  69. jint result = -1;
  70. if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
  71. LOGE("GetEnv failed!");
  72. return result;
  73. }
  74. LOG_ASSERT(env, "Could not retrieve the env!");
  75. register_mokoid_server_LedService(env);
  76. return JNI_VERSION_1_4;
  77. }

上面的Jni代码首先通过hw_get_module得到HAL stub,open以后就可以直接使用HAL stub中定义的接口。这里还需要注意JNI_OnLoad这个函数,当Jni库被App load的时候,该函数将会自动被调用,所以我们在这里实现了注册Led Service的操作,也就是说把C/C++的接口映射到Java中去,这样在Java APP中就可以使用该接口了。在register_mokoid_server_LedService中,我们需要注意kclassname指定了需要调用该Jni库的Java APP类 - com.mokoid.LedClient.LedClient,也就是说该Jni库只能提供给该Java程序使用。

最后是应用程序代码:

  1. public class LedClient extends Activity {
  2. static {
  3. System.load("/system/lib/libmokoid_runtime.so");
  4. }
  5. @Override
  6. public void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. // Call an API on the library.
  9. _init();
  10. _set_on(1);
  11. _set_off(2);
  12. TextView tv = new TextView(this);
  13. tv.setText("LED 1 is on. LED 2 is off.");
  14. setContentView(tv);
  15. }
  16. private static native boolean _init();
  17. private static native boolean _set_on(int led);
  18. private static native boolean _set_off(int led);
  19. }

上面使用System.load来装载Jni库,当然我们也可以使用System.loadLibrary来装载,他们的唯一区别就是前者需要指定完整的路径,后者会在系统路径上(比如/system/lib/) 查找库。装载完该Jni库后,就可以使用映射后的接口了(_init, _set_on, _set_off)。

上面这种HAL的实现方式比较简单,但是也存在一个很大的问题,就是Jni库只能提供给某一个特定的Java使用,如何克服这个问题?我们可以在APP和Jni之间加一层Java service,该Jni提供给Java service使用,而所有的APP利用该service来使用Jni提供的接口。这样的话,在应用程序层,就不需要关心Jni是如何实现的了。下一篇我们会介绍这种方法。

本文出自 “Mobile and Linux Deve..” 博客,请务必保留此出处http://buaadallas.blog.51cto.com/399160/384622

转载于:https://www.cnblogs.com/gooogleman/archive/2012/07/06/2579431.html

转载.Android HAL实现的三种方式(1) - 基于JNI的简单HAL设计相关推荐

  1. android xml解析的三种方式

    2019独角兽企业重金招聘Python工程师标准>>> 在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX.Pull.Dom解析方式.最近做了 ...

  2. Android录制音频的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  3. Android 使用OpenCV的三种方式(Android Studio)

    from: http://blog.csdn.net/sbsujjbcy/article/details/49520791 其实最早接触OpenCV是很久很久之前的事了,大概在2013年的5,6月份, ...

  4. Android解析XML的三种方式

    在Android中提供了三种解析XML的方式:DOM(Document Objrect Model),SAX(Simple API XML),以及Android推荐的Pull解析方式. 如图: 本篇博 ...

  5. Android 音频录制 的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  6. Android 延时操作的三种方式

    在Android开发中我们可能会有延时执行某个操作的需求,例如我们启动应用的时候,一开始呈现的是引导页面,3秒后进入主界面,这就是一个延时操作. 下面是实现延时操作的三种方法: 一.使用线程的休眠实现 ...

  7. android动画影子效果,Android实现阴影效果的三种方式

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 实现Android阴影共有三种方式:使用.9图(略).设置视图的高度.在layer-list资源文件中模拟阴影效果,本篇 ...

  8. 三种方式实现阻塞队列(简单版)

    1.基于wait和notify方法实现的阻塞队列 public class WaitNotifyInterview {public final static int QUEUE_SIZE = 10;p ...

  9. Android延迟执行的三种方式(转载)

    1.线程 new Thread(new Runnable() {public void run() {//sleep设置的是时长Thread.sleep(1000);handler.sendMessa ...

最新文章

  1. vmware虚拟机异常关闭处理
  2. 从路由原理出发,深入阅读理解react-router 4.0的源码
  3. [文摘20070913]最好的消息
  4. redis编译包下载地址 redis-6.2.6.tar.gz
  5. 2012年第一篇博文——致谢:2011年中国IT十大杰出博客获奖感言
  6. 【NGN学习笔记】6 代理(Proxy)和背靠背用户代理(B2BUA)
  7. (完美)华为畅玩7A AUM-AL00的Usb调试模式在哪里打开的步骤
  8. node重命名文件名_node文件批量重命名
  9. 鼠标宏设置到鼠标左键,重置回去!
  10. 实用的在线文本分析工具
  11. 【一周头条盘点】中国软件网(2018.9.10~2018.9.14)
  12. 系统编程__2__父子进程的创建和回收
  13. 员工管理系统数据库课程设计
  14. SpringBoot快速开始magic-api基础
  15. Rocket - tilelink - Xbar
  16. c++ LintCode刷题记录之52. 下一个排列
  17. 信息化实施, 管理前沿 ERP生产系统
  18. 电商用户价值分析(应用RFM模型)
  19. 这篇文章记录平时学习、项目中遇到的问题(未解决的居多)
  20. 第十届蓝桥杯(国赛)——拼接

热门文章

  1. 20.4. myisamchk — MyISAM Table-Maintenance Utility
  2. Nginx服务状态的监控
  3. mikadonic-iptables学习笔记
  4. 禁止sethc.exe运行 防止3389的sethc后门
  5. POJ 1562深搜判断连体油田个数
  6. 美图秀秀首页界面按钮设计(二)
  7. Makefile的写法
  8. jQuery插件ASP.NET应用之AjaxUpload
  9. Hibernate 逆向工程生成POJO类和映射文件
  10. Linux系列-Red Hat5平台下的Postfix邮件服务搭建(二)