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

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

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

我们现看看HAL stub的代码:

        
  1. intled_device_close(structhw_device_t*device)
  2. {
  3. structled_control_device_t*ctx=(structled_control_device_t*)device;
  4. if(ctx){
  5. free(ctx);
  6. }
  7. return0;
  8. }
  9. intled_on(structled_control_device_t*dev,int32_tled)
  10. {
  11. LOGI("LEDStub:set%don.",led);
  12. return0;
  13. }
  14. intled_off(structled_control_device_t*dev,int32_tled)
  15. {
  16. LOGI("LEDStub:set%doff.",led);
  17. return0;
  18. }
  19. staticintled_device_open(conststructhw_module_t*module,constchar*name,
  20. structhw_device_t**device)
  21. {
  22. structled_control_device_t*dev;
  23. dev=(structled_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. return0;
  34. }
  35. staticstructhw_module_methods_tled_module_methods={
  36. open:led_device_open
  37. };
  38. conststructled_module_tHAL_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:"SampleLEDStub",
  45. author:"TheMokoidOpenSourceProject",
  46. methods:&led_module_methods,
  47. }
  48. /*supportingAPIsgohere*/
  49. };

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

下面看看JNI层代码:

        
  1. structled_control_device_t*sLedDevice=NULL;
  2. staticjbooleanmokoid_setOn(JNIEnv*env,jobjectthiz,jintled)
  3. {
  4. LOGI("LedServiceJNI:mokoid_setOn()isinvoked.");
  5. if(sLedDevice==NULL){
  6. LOGI("LedServiceJNI:sLedDevicewasnotfetchedcorrectly.");
  7. return-1;
  8. }else{
  9. returnsLedDevice->set_on(sLedDevice,led);
  10. }
  11. }
  12. staticjbooleanmokoid_setOff(JNIEnv*env,jobjectthiz,jintled)
  13. {
  14. LOGI("LedServiceJNI:mokoid_setOff()isinvoked.");
  15. if(sLedDevice==NULL){
  16. LOGI("LedServiceJNI:sLedDevicewasnotfetchedcorrectly.");
  17. return-1;
  18. }else{
  19. returnsLedDevice->set_off(sLedDevice,led);
  20. }
  21. }
  22. /**helperAPIs*/
  23. staticinlineintled_control_open(conststructhw_module_t*module,
  24. structled_control_device_t**device){
  25. returnmodule->methods->open(module,
  26. LED_HARDWARE_MODULE_ID,(structhw_device_t**)device);
  27. }
  28. staticjbooleanmokoid_init(JNIEnv*env,jclassclazz)
  29. {
  30. led_module_t*module;
  31. if(hw_get_module(LED_HARDWARE_MODULE_ID,(consthw_module_t**)&module)==0){
  32. LOGI("LedServiceJNI:LEDStubfound.");
  33. if(led_control_open(&module->common,&sLedDevice)==0){
  34. LOGI("LedServiceJNI:GotStuboperations.");
  35. return0;
  36. }
  37. }
  38. LOGE("LedServiceJNI:GetStuboperationsfailed.");
  39. return-1;
  40. }
  41. staticconstJNINativeMethodgMethods[]={
  42. {"_init","()Z",(void*)mokoid_init},
  43. {"_set_on","(I)Z",(void*)mokoid_setOn},
  44. {"_set_off","(I)Z",(void*)mokoid_setOff},
  45. };
  46. intregister_mokoid_server_LedService(JNIEnv*env){
  47. staticconstchar*constkClassName=
  48. "com/mokoid/LedClient/LedClient";
  49. jclassclazz;
  50. /*lookuptheclass*/
  51. clazz=env->FindClass(kClassName);
  52. if(clazz==NULL){
  53. LOGE("Can'tfindclass%s\n",kClassName);
  54. return-1;
  55. }
  56. /*registerallthemethods*/
  57. if(env->RegisterNatives(clazz,gMethods,
  58. sizeof(gMethods)/sizeof(gMethods[0]))!=JNI_OK)
  59. {
  60. LOGE("Failedregisteringmethodsfor%s\n",kClassName);
  61. return-1;
  62. }
  63. /*fillouttherestoftheIDcache*/
  64. return0;
  65. }
  66. extern"C"jintJNI_OnLoad(JavaVM*vm,void*reserved)
  67. {
  68. JNIEnv*env=NULL;
  69. jintresult=-1;
  70. if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK){
  71. LOGE("GetEnvfailed!");
  72. returnresult;
  73. }
  74. LOG_ASSERT(env,"Couldnotretrievetheenv!");
  75. register_mokoid_server_LedService(env);
  76. returnJNI_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. publicclassLedClientextendsActivity{
  2. static{
  3. System.load("/system/lib/libmokoid_runtime.so");
  4. }
  5. @Override
  6. publicvoidonCreate(BundlesavedInstanceState){
  7. super.onCreate(savedInstanceState);
  8. //CallanAPIonthelibrary.
  9. _init();
  10. _set_on(1);
  11. _set_off(2);
  12. TextViewtv=newTextView(this);
  13. tv.setText("LED1ison.LED2isoff.");
  14. setContentView(tv);
  15. }
  16. privatestaticnativeboolean_init();
  17. privatestaticnativeboolean_set_on(intled);
  18. privatestaticnativeboolean_set_off(intled);
  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是如何实现的了。下一篇我们会介绍这种方法。

更多相关文章

  1. android之如何使用Android的搜索框架
  2. Android(安卓)事件全局监听(二)需要root权限 ,使用getevent监听Andr
  3. Android(安卓)APK 签名比对,防止软件被破解使用
  4. Android(安卓)Studio怎样提示函数使用方法
  5. 史上最全的Android开发学习教程集锦【初学者】
  6. Android中微信主界面菜单栏的布局实现代码
  7. 箭头函数的基础使用
  8. NPM 和webpack 的基础使用
  9. Python list sort方法的具体使用

随机推荐

  1. Android热修复技术原理
  2. android framework层 学习笔记(二)
  3. Android——在SurfaceView上绘图
  4. Android第二周(第二部分)-listview
  5. 【开源框架】一个基于回调机制的多线程异
  6. html5游戏移植到android并打包成apk,加广
  7. 弹幕刷屏之术——Android无时间线弹幕实
  8. Android 软键盘监听事件
  9. Android(安卓)Studio 3.0 发行说明
  10. 异步任务——AsyncTask