Android HAL and JNI

主要内容:

1. HAL and JNI 框架

2. HAL 介绍

3. JNI 介绍


1. HAL and JNI 框架


2. HAL 介绍

在 Android 原始码里,HAL 主要的实作储存于以下目录:

1-. libhardware_legacy/ - 过去的实作、采取链接库模块的观念进行

2-. libhardware/ - 新版的实作、调整为 HAL stub 的观念

Hardware/libhardware/include/hardware/hardware.h

Hardware/libhardware/hardware.c

3-. ril/ - Radio Interface Layer

HAL stuct define:

Hardware/libhardware/include/hardware/hardware.h
int hw_get_module(const char *id, const struct hw_module_t **module);

int hw_get_module_by_class(const char *class_id, const char *inst,
                             const struct hw_module_t **module);
Hardware/libhardware/hardware.c :

硬件 抽象 层 模块 文件 的 命名 规范 为“< MODULE_ ID>. variant. so”


 HAL使用方法:

(1)Native code通过hw_get_module调 用获取HAL stub:

hw_get_module (LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)

(2)通过继承hw_module_methods_t的callback来 open设备:

module->methods->open(module,         LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);

(3)通过继承 hw_device_t的callback来控制设备:

sLedDevice->set_on(sLedDevice, led);sLedDevice->set_off(sLedDevice, led);



HAL的加载过程:

Hardware/libhardware/hardware.c :
模块加载过程:hw_get_module(XXX_HARDWARE_MODULE_ID, (const hw_module_t**)&module)

依次在/system/lib/hw和/vendor/lib/hw目录中检查是否存在相应的“<MODULE_ID>.variant.so”文件。
其中,variant分别等于属性“ro.hardware”、“ro.product.board”、“ro.board.platform”和“ro.arch”的值。
只要其中一个存在,即停止查找。
如果上述文件均不存在,则继续在/system/lib/hw目录中检查 “<MODULE_ID>.variant.so”文件是否存在。
调用dlopen打开上述找到的so文件。
调用dlsys获得上述打开的so文件里面的符号HAL_MODULE_INFO_SYM。

将符号HAL_MODULE_INFO_SYM强制转换为一个hw_moudle_t结构体。

HAL 驱动例子— Sensor HAL:

hardware/moto/sensors/XX_hal/SensorHal.cpp

  static struct hw_module_methods_t sensors_module_methods = {
  open: open_sensors  };
  struct sensors_module_t HAL_MODULE_INFO_SYM = {
  common: {
  tag: HARDWARE_MODULE_TAG,
  version_major: 1,
  version_minor: 0,
  id: SENSORS_HARDWARE_MODULE_ID,
  name: "Motorola Sensors Module",
  author: "Motorola",
  methods: &sensors_module_methods,
  dso: NULL,
  reserved: {0},                 },
  get_sensors_list: sensors__get_sensors_list,
  set_operation_mode: sensors__set_operation_mode   };

3. JNI 介绍

3.1 什么是JNI

在Android Framework 中,需要提供一种媒介或桥梁,将Java 层(上层)与C\C++层(底层)有机联系起来,使得他们相互协调,共同完成某些任务,充当该桥梁的就是Java本地接口JNI(Java Native Interface)。它允许Java代码与基于C/C++编写的应用程序和库进行交互操作。


3.2 什么情况下要用到JNI

1)注重处理速度
与本地代码C/C++相比,Java的代码执行速度要慢一些,如果对程序的执行速度有较高的要求,建议用C\C++编写代码,然后在Java中通过JNI调用基于C/C++编写的部分
2)硬件控制
为了更好地控制硬件,硬件代码通常用C语言编写,然后借助JNI将其与Java层连接起来,从而实现对硬件 的控制
3)既有C/C++代码的复用

在程序编写的过程中,常常有一些已经编写好的C/C++代码,既提高了编程效率,又确保了程序的安全性和健壮性。在复用这些C/C++代码时就要通过JNI来实现

3.3 Java代码中通过JNI调用C函数

在Java代码中通过JNI调用C函数的步骤如下:

第一步:编写Java代码
第二步:编译Java代码
第三步:生成C语言头文件
第四步:编写C代码
第五步:生成C共享库

第六步:运行Java程序


3.4 通过JNI注册本地方法完成映射


3.5 JNI--Sensor

JAVA中定义JNI NATIVE 接口 :

/frameworks/base/core/java/android/hardware/SystemSensorManager.java
private static native void nativeClassInit();
private static native long nativeCreate(String opPackageName);
private static native boolean nativeGetSensorAtIndex(long nativeInstance,
              Sensor sensor, int index);
private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);  
private static native int nativeCreateDirectChannel(
             long nativeInstance, long size, int channelType, int fd, HardwareBuffer buffer);
private static native void nativeDestroyDirectChannel( )

C++中实现JAVA中定义的NATIVE接口,并与JAVA中定义的方法进行映射 :

/frameworks/base/core/jni/android_hardware_SensorManager.cpp
 static const JNINativeMethod gSystemSensorManagerMethods[] = {
      {"nativeClassInit",  "()V", (void*)nativeClassInit },
      {"nativeCreate", "(Ljava/lang/String;)J", (void*)nativeCreate }, 
      {"nativeGetSensorAtIndex",        "(JLandroid/hardware/Sensor;I)Z",
              (void*)nativeGetSensorAtIndex },
      {"nativeGetDynamicSensors","(JLjava/util/List;)V",
              (void*)nativeGetDynamicSensors },
      {"nativeIsDataInjectionEnabled",          "(J)Z",

              (void*)nativeIsDataInjectionEnabled },

C++中注册NATIVE方法 :

 int register_android_hardware_SensorManager(JNIEnv *env)  {     RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",             gSystemSensorManagerMethods,   NELEM(gSystemSensorManagerMethods));      return 0;  }