現在在Android上的HAL開發總的來說還是隨意性比較大,Android也并沒有規范好一個具體的框架,下面我將根據Jollen的Mokoid工程,自己做了一些改動,分別給大家介紹一下三種實現方式。
這篇先介紹最簡單的一種實現方式 - Java應用程序直接調用JNI庫。
由于JNI技術的存在,在Android中,java程序能夠很好的調用C/C++庫。我們這里設計一個簡單的HAL,一共只有三層: HAL stub <-> JNI 庫 <-> JAVA應用程序。
我們現看看HAL stub的代碼:
int?led_device_close(struct?hw_device_t*?device)?{?????struct?led_control_device_t*?ctx?=?(struct?led_control_device_t*)device;?????if?(ctx)?{?????????free(ctx);?????}?????return?0;?}??int?led_on(struct?led_control_device_t?*dev,?int32_t?led)?{?????LOGI("LED?Stub:?set?%d?on.",?led);?????return?0;?}??int?led_off(struct?led_control_device_t?*dev,?int32_t?led)?{?????LOGI("LED?Stub:?set?%d?off.",?led);?????return?0;?}??static?int?led_device_open(const?struct?hw_module_t*?module,?const?char*?name,?????????struct?hw_device_t**?device)??{?????struct?led_control_device_t?*dev;??????dev?=?(struct?led_control_device_t?*)malloc(sizeof(*dev));?????memset(dev,?0,?sizeof(*dev));??????dev->common.tag?=??HARDWARE_DEVICE_TAG;?????dev->common.version?=?0;?????dev->common.module?=?module;?????dev->common.close?=?led_device_close;??????dev->set_on?=?led_on;?????dev->set_off?=?led_off;??????*device?=?&dev->common;??success:?????return?0;?}??static?struct?hw_module_methods_t?led_module_methods?=?{?????open:?led_device_open?};??const?struct?led_module_t?HAL_MODULE_INFO_SYM?=?{?????common:?{?????????tag:?HARDWARE_MODULE_TAG,?????????version_major:?1,?????????version_minor:?0,?????????id:?LED_HARDWARE_MODULE_ID,?????????name:?"Sample?LED?Stub",?????????author:?"The?Mokoid?Open?Source?Project",?????????methods:?&led_module_methods,?????}??????};?我在前面關于HAL技術的文章中已經介紹了如何寫HAL stub,需要注意的只有hw_module_t和hw_device_t這兩個數據結構,這里就不復述了。
下面看看JNI層代碼:
struct?led_control_device_t?*sLedDevice?=?NULL;??static?jboolean?mokoid_setOn(JNIEnv*?env,?jobject?thiz,?jint?led)??{?????LOGI("LedService?JNI:?mokoid_setOn()?is?invoked.");??????if?(sLedDevice?==?NULL)?{?????????LOGI("LedService?JNI:?sLedDevice?was?not?fetched?correctly.");?????????return?-1;?????}?else?{?????????return?sLedDevice->set_on(sLedDevice,?led);?????}?}??static?jboolean?mokoid_setOff(JNIEnv*?env,?jobject?thiz,?jint?led)??{?????LOGI("LedService?JNI:?mokoid_setOff()?is?invoked.");???????if?(sLedDevice?==?NULL)?{?????????LOGI("LedService?JNI:?sLedDevice?was?not?fetched?correctly.");?????????return?-1;?????}?else?{?????????return?sLedDevice->set_off(sLedDevice,?led);?????}?}???static?inline?int?led_control_open(const?struct?hw_module_t*?module,?????????struct?led_control_device_t**?device)?{?????return?module->methods->open(module,?????????????LED_HARDWARE_MODULE_ID,?(struct?hw_device_t**)device);?}??static?jboolean?mokoid_init(JNIEnv?*env,?jclass?clazz)?{?????led_module_t*?module;??????if?(hw_get_module(LED_HARDWARE_MODULE_ID,?(const?hw_module_t**)&module)?==?0)?{?????????LOGI("LedService?JNI:?LED?Stub?found.");?????????if?(led_control_open(&module->common,?&sLedDevice)?==?0)?{?????????????LOGI("LedService?JNI:?Got?Stub?operations.");?????????????return?0;?????????}?????}??????LOGE("LedService?JNI:?Get?Stub?operations?failed.");?????return?-1;?}??static?const?JNINativeMethod?gMethods[]?=?{?????{?"_init",??????"()Z",??(void?*)mokoid_init?},?????{?"_set_on",????????"(I)Z",?(void?*)mokoid_setOn?},?????{?"_set_off",???????"(I)Z",?(void?*)mokoid_setOff?},?};??int?register_mokoid_server_LedService(JNIEnv*?env)?{?????static?const?char*?const?kClassName?=?????????"com/mokoid/LedClient/LedClient";?????jclass?clazz;???????????clazz?=?env->FindClass(kClassName);?????if?(clazz?==?NULL)?{?????????LOGE("Can't?find?class?%s\n",?kClassName);?????????return?-1;?????}???????????if?(env->RegisterNatives(clazz,?gMethods,?????????????sizeof(gMethods)?/?sizeof(gMethods[0]))?!=?JNI_OK)?????{?????????LOGE("Failed?registering?methods?for?%s\n",?kClassName);?????????return?-1;?????}???????????return?0;?}??extern?"C"?jint?JNI_OnLoad(JavaVM*?vm,?void*?reserved)?{?????JNIEnv*?env?=?NULL;?????jint?result?=?-1;??????if?(vm->GetEnv((void**)?&env,?JNI_VERSION_1_4)?!=?JNI_OK)?{?????????LOGE("GetEnv?failed!");?????????return?result;?????}?????LOG_ASSERT(env,?"Could?not?retrieve?the?env!");??????register_mokoid_server_LedService(env);??????return?JNI_VERSION_1_4;?}?上面的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程序使用。
最后是應用程序代碼:
public?class?LedClient?extends?Activity?{??????static?{?????????System.load("/system/lib/libmokoid_runtime.so");?????}??????@Override?????public?void?onCreate(Bundle?savedInstanceState)?{?????????super.onCreate(savedInstanceState);???????????????????_init();?????????_set_on(1);?????????_set_off(2);??????????????????TextView?tv?=?new?TextView(this);?????????tv.setText("LED?1?is?on.?LED?2?is?off.");?????????setContentView(tv);?????}?????private?static?native?boolean?_init();?????private?static?native?boolean?_set_on(int?led);?????private?static?native?boolean?_set_off(int?led);?}??上面使用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设计的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。