现在在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. 使用ant让Android自动打包的build.xml,自动生成签名的apk文件(支
  2. Android中使用语音引擎入门七步曲
  3. Android(安卓)Studio酷炫插件(一)——自动化快速实现Parcelable接
  4. Android(安卓)APP设计加载使用gif动图需要注意的一般性问题
  5. android 安全讲座第四层 手机Root授权原理细节全解析(2)
  6. 【Android】Android(安卓)NDK开发扫盲及最新CMake的编译使用 so
  7. 箭头函数的基础使用
  8. NPM 和webpack 的基础使用
  9. Python list sort方法的具体使用

随机推荐

  1. Android ImageView的scaleType属性与adju
  2. 将Android封装库通过gradle部署到maven私
  3. 使用命令行签名Android应用程序
  4. ContentProvider和Uri详解
  5. Android中Handler小例子
  6. android之从Bmob获取数据显示在ListView
  7. Android 屏幕截图
  8. Awesome Adb——一份超全超详细的 ADB 用
  9. 如何防止android Toast重复显示?
  10. 动态修改Android参数信息的方法绕过改机