Android HAL实现1——Java应用程序直接调用JNI库

先介绍最简单的一种实现方式 - 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.  

10. int led_on(struct led_control_device_t *dev, int32_t led)

11. {

12.     LOGI("LED Stub: set %d on.", led);

13.     return 0;

14. }

15. 

16. int led_off(struct led_control_device_t *dev, int32_t led)

17. {

18.     LOGI("LED Stub: set %d off.", led);

19.     return 0;

20. }

21. 

22. static int led_device_open(const struct hw_module_t* module, const char* name,

23.                                               struct hw_device_t** device) 

24. {

25.     struct led_control_device_t   *dev;

26. 

27.     dev = (struct led_control_device_t *)malloc(sizeof(*dev));

28.     memset(dev, 0, sizeof(*dev));

29. 

30.     dev->common.tag =  HARDWARE_DEVICE_TAG;

31.     dev->common.version = 0;

32.     dev->common.module = module;

33.     dev->common.close = led_device_close;

34. 

35.     dev->set_on  = led_on;‍

36.     dev->set_off  = led_off;

37. 

38.     *device = &dev->common;

39. 

40. success:

41.     return 0;

42. }

43. 

44. static struct hw_module_methods_t led_module_methods = {

45.     open: led_device_open

46. };

47. 

48. const struct  led_module_t  HAL_MODULE_INFO_SYM = {

49.     common: {

50.         tag: HARDWARE_MODULE_TAG,

51.         version_major: 1,

52.         version_minor: 0,

53.         id: LED_HARDWARE_MODULE_ID,

54.         name: "Sample LED Stub",

55.         author: "The Mokoid Open Source Project",

56.         methods: &led_module_methods,

57.     }

58.     /* supporting APIs go here */

59. };

 

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

=================================>>>

下面看看JNI层代码:

 

1.  ‍struct led_control_device_t  *sLedDevice = NULL;

2.  

3.  static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) 

4.  {

5.      LOGI("LedService JNI: mokoid_setOn() is invoked.");

6.  

7.      if (sLedDevice == NULL) {

8.          LOGI("LedService JNI: sLedDevice was not fetched correctly.");

9.          return -1;

10.     } else {

11.         return sLedDevice->set_on(sLedDevice, led);

12.     }

13. }

14. 

15. static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) 

16. {

17.     LOGI("LedService JNI: mokoid_setOff() is invoked.");

18. 

19. 

20.     if (sLedDevice == NULL) {

21.         LOGI("LedService JNI: sLedDevice was not fetched correctly.");

22.         return -1;

23.     } else {

24.         return sLedDevice->set_off(sLedDevice, led);

25.     }

26. }

27. 

28. /** helper APIs */

29. static inline int led_control_open(const struct hw_module_t*  module,

30.                                                     struct led_control_device_t**  device) {

31.     return module->methods->open(module,

32.             LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);

33. }

34. 

35. static jboolean mokoid_init(JNIEnv *env, jclass clazz)

36. {

37.     led_module_t* module;

38. 

39.     if ( hw_get_module ‍(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {

40.         LOGI("LedService JNI: LED Stub found.");

41.         if (led_control_open(&module->common, &sLedDevice) == 0) {

42.             LOGI("LedService JNI: Got Stub operations.");

43.             return 0;

44.         }

45.     }

46. 

47.     LOGE("LedService JNI: Get Stub operations failed.");

48.     return -1;

49. }

50. 

51. static const JNINativeMethod gMethods[] = {

52.     { "_init",              "()Z",  (void *)mokoid_init},

53.     { "_set_on",        "(I)Z", (void *)mokoid_setOn},

54.     { "_set_off",       "(I)Z", (void *)mokoid_setOff},

55. };

56. 

57. int register_mokoid_server_LedService(JNIEnv* env) {

58.     static const char* const kClassName =

59.         "com/mokoid/LedClient/LedClient";        // kclassname‍ 指定了需要调用该Jni库的Java APP类

60.     jclass clazz;

61. 

62.     /* look up the class */

63.     clazz = env->FindClass(kClassName);

64.     if (clazz == NULL) {

65.         LOGE("Can't find class %s\n", kClassName);

66.         return -1;

67.     }

68. 

69.     /* register all the methods */

70.     if (env->RegisterNatives(clazz, gMethods,

71.             sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)

72.     {

73.         LOGE("Failed registering methods for %s\n", kClassName);

74.         return -1;

75.     }

76. 

77.     /* fill out the rest of the ID cache */

78.     return 0;

79. }

80. 

81. extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)

82. {

83.     JNIEnv* env = NULL;

84.     jint result = -1;

85. 

86.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

87.         LOGE("GetEnv failed!");

88.         return result;

89.     }

90.     LOG_ASSERT(env, "Could not retrieve the env!");

91. 

92.     register_mokoid_server_LedService(env);

93. 

94.     return JNI_VERSION_1_4;

95. }

 

1. 上面的Jni代码首先通过hw_get_module得到HAL stub,open以后就可以直接使用HAL stub中定义的接口。

2.  这里还需要注意JNI_OnLoad这个函数,当Jni库被App load的时候,该函数将会自动被调用,所以我们在这里实现了注册Led Service的操作,也就是说把C/C++的接口映射到Java中去,这样在Java APP中就可以使用该接口了。

3.  在register_mokoid_server_LedService中,我们需要注意kclassname指定了需要调用该Jni库的Java APP类 - com.mokoid.LedClient.LedClient,也就是说该Jni库只能提供给该Java程序使用。

=================================>>>

 

最后是应用程序代码:

1.  public class LedClient extends Activity {

2.  

3.      static {

4.          System.load("/system/lib/libmokoid_runtime.so");    // 装载完该Jni库后,就可以使用映射后的接口了

5.      }

6.  

7.      @Override

8.      public void onCreate(Bundle savedInstanceState) {

9.          super.onCreate(savedInstanceState);

10. 

11.         // Call an API on the library.

12.         _init();

13.         _set_on(1);

14.         _set_off(2);

15.         

16.         TextView tv = new TextView(this);

17.         tv.setText("LED 1 is on. LED 2 is off.");

18.         setContentView(tv);

19.     }

20.     private static native boolean _init();

21.     private static native boolean _set_on(int led);

22.     private static native boolean _set_off(int led);

23. }

 

 上面使用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是如何实现的了。下一篇我们会介绍这种方法。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值