zoukankan      html  css  js  c++  java
  • 转载.Android HAL实现的三种方式(1) 基于JNI的简单HAL设计

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

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

    最后是应用程序代码:

    1. public class LedClient extends Activity { 
    2.  
    3.     static { 
    4.         System.load("/system/lib/libmokoid_runtime.so"); 
    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); 

     上面使用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

  • 相关阅读:
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Hibernate_criteria
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Hibernate_named_HQL
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Hibernate_implicit_join
    HDU
    HDU
    HDU
    HDU
    HDU
    BZOJ
    HDU
  • 原文地址:https://www.cnblogs.com/gooogleman/p/2579431.html
Copyright © 2011-2022 走看看