HAL

1) libhardware_legacy

是将 *.so 文件当作shared library来使用,在runtime(JNI 部份)以 direct function call 使用 HAL module。通过直接函数调用的方式,来操作驱动程序。当然,应用程序也可以不需要通过 JNI 的方式进行,直接加载 .so (dlopen)的做法调用.so 里的符号(symbol)也是一种方式。总而言之是没有经过封装,上层可以直接操作硬件。

2) libhardware

HAL stub 是一种代理人(proxy)的概念,stub 虽然仍是以 *.so檔的形式存在,但HAL已经将 *.so 档隐藏起来了。
这些硬件模块都编译成xxx.xxx.so,目标位置为/system/lib/hw目录
上层仅仅链接libhardware.so, 调用hw_get_modules 获取相应的模块,加载相应的库。

1. HAL 硬件抽象层规范

HAL_MODULE_INFO_SYM
hw_module_t
HARDWARE_MODULE_TAG
  1. 所有的hal模块都要有一个以HAL_MODULE_INFO_SYM命名的结构,而且这个结构要以hw_module_t开始,即要继承hw_module_t这个结构,比如sensor:
struct hw_module_t HAL_MODULE_INFO_SYM={};
  1. 实例变量名必须为HAL_MODULE_INFO_SYM,tag也必须为HARDWARE_MODULE_TAG.
struct sensors_module_t {
 struct hw_module_t common;
int (*get_sensors_list)(struct sensors_module_t* module,
            struct sensor_t const** list);
};
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag;
/** major version number for the module */
uint16_t version_major;
/** minor version number of the module */
      uint16_t version_minor;
/** Identifier of module */
const char *id;
/** Name of this module */
const char *name;
/** Author/owner/implementor of the module */
const char *author;
/** Modules methods */
  struct hw_module_methods_t* methods; //硬件模块的方法
/** module's dso */
void* dso;
 /** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
} hw_module_t;

hw_module_t中比较重要的是硬件模块方法结构体hw_module_methods_t定义如下:

typedef struct hw_module_methods_t {

 /** Open a specific device */

int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);

} hw_module_methods_t;

sensors_module_t,hw_module_t 不能定义为const,否则hardware.c hmi->dso=handley运行时会出现崩溃

dso就是dlopen动态库的句柄.

struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .version_major = 1,
    .version_minor = 0,
    .id = LIGHTS_HARDWARE_MODULE_ID,
    .name = "lights Module",
    .author = "Google, Inc.",
    .methods = &lights_module_methods,
};
3.提供给jni的接口 open
int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);

其中调用的设备结构体参数hw_device_t定义
每一个设备的数据结构都必须也以hw_device_t开始。

struct sensor_poll_device_t{  
struct hw_device_t common; 
function XXXX}

struct light_device_t
{struct hw_device_t common; 
function XXXX}

这些结构需要被上层服务jni函数调用。
com_android_server_lightService.cpp
SensorDevice.cpp

2. HAL访问硬件设备

比如硬件设备是 "/dev/hello"。由于设备文件是在内核驱动里面通过device_create创建的,而device_create创建的设备文件默认只有root用户可读写,

而hello_device_open一般是由上层APP来调用的,这些APP一般不具有root权限,这时候就导致打开设备文件失败
会出现

Hello Stub: failed to open /dev/hello -- Permission denied.

解决办法是类似于Linux的udev规则,打开Android源代码工程目录下,进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:

      /dev/hello 0666 root root

3.JNI的调用实现

1.上层通过hw_get_module 获取模块

hw_get_module函数声明如下:

    int hw_get_module(const char *id, const struct hw_module_t **module);
2. module->methods->open()获取到具体的设备。
3.module可以定义自己的函数供上层调用。 比如
    mSensorModule->get_sensors_list();

参数id为模块标识,定义在/hardware/libhardware/include/hardware录下的硬件模块头文件中,参数module是硬件模块地址,定义在/hardware/libhardware/include/hardware/hardware.h中

在lights.h中定义有lights模块的ID

     #define LIGHTS_HARDWARE_MODULE_ID "lights"

frameworks/base/services/jni/com_android_server_LightsService.cpp

static jint init_native(JNIEnv *env, jobject clazz)

{

    int err;

    hw_module_t* module;

    Devices* devices;

    devices = (Devices*)malloc(sizeof(Devices));

 err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

    if (err == 0) {

        devices->lights[LIGHT_INDEX_BACKLIGHT]

                = get_device(module, LIGHT_ID_BACKLIGHT);

………………………………………….

}

4 .新增服务的JNI接口

1. 新建JNI接口文件

进入到系统的JNI目录中:frameworks/base/services/jni 在这个目录中包含了系统服务的所有JNI实现的程序
新建com_android_server_XXXService.cpp
在com_android_server_XXXService.cpp文件中,实现JNI方法。注意文件的命名方法,com_android_server前缀表示的是包名, (注意名字的唯一性)
表示硬件服务XXXService是放在frameworks/base/services/java目录下的com/android/server目录,即存在一个命名为com.android.server.XXXService的类。

init函数中调用hw_get_module获取HAL层的接口

2.添加文件到Android.mk

在同一目录中有一个Android.mk文件,需要添加我们的这个服务,后续要将这个服务编译到源码中

3.添加到onload.cpp

onload.cpp程序,是系统启动的时候去运行,内部是专门注册系统服务的JNI方法的
定义在com_android_server_XXX.cpp中
jniRegisterNativeMethods函数中,第二个参数的值必须对应Service所在的包的路径,即com/android/server/XXXService。

int register_android_server_LightsService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/LightsService",
            method_table, NELEM(method_table));
}

JNI_OnLoad与JNI_OnUnload

framework/base/services/jni生成libandroid_servers.so
framework/base/services/java/com/android/server/systemserver.java
会运行loadlibrary

在Android中,当程序在java层运行System.loadLibrary("jnitest");这行代码后,程序会去载入libjnitest.so文件,与此同时,产生一个"Load"事件,这个事件触发后,程序默认会在载入的.so文件的函数列表中查找JNI_OnLoad函数并执行

添加AIDL接口

调用硬件服务的应用程序与这些硬件服务之间的通信需要通过代理来进行。为此,我们要先定义好通信接口。

进入到frameworks/base/core/java/android/os目录,新增IHelloService.aidl接口定义文件:

    package android.os;  
       
    interface IHelloService {  
        void setVal(int val);  
        int getVal();  
    }

就会根据IHelloService.aidl生成相应的IHelloService.Stub接口。

进入到frameworks/base/services/java/com/android/server目录,新增HelloService.java文件

    package com.android.server;  
    import android.content.Context;  
    import android.os.IHelloService;  
    import android.util.Slog;  
    public class HelloService extends IHelloService.Stub {  
        private static final String TAG = "HelloService";  
        HelloService() {  
            init_native();  
        }  
        public void setVal(int val) {  
            setVal_native(val);  
        }     
        public int getVal() {  
            return getVal_native();  
        }  
          
        private static native boolean init_native();  
            private static native void setVal_native(int val);  
        private static native int getVal_native();  
    };  

修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载HelloService的代码

 try {

                  Slog.i(TAG, "Hello Service");

                  ServiceManager.addService("hello", new HelloService());

            } catch (Throwable e) {

                  Slog.e(TAG, "Failure starting Hello Service", e);

            }

你可能感兴趣的:(HAL)