Android将硬件驱动一分为二。一部分在Kernel层,另一部分在用户空间。
在用户空间这部分硬件驱动就叫硬件抽象层(HAL)。
为什么安卓要一分为二?
因为Linux Kernel是开源的,但是你如果在Kernel里加东西,你加的东西也要开源。那么作为企业,为了自身Kernel的独特性和机密性就要想办法避开这个问题。
解决办法就是,将硬件驱动实现内容仍然放在Kernel并提供访问接口,但具体怎么才能访问就要通过硬件抽象层。这里硬件抽象层因为以及不属于Linux Kernel,所以厂商可以不开源。
JNI (Java native interface)
JNI简单来讲,它一种编程接口,它可以运行Java调用本地(C/C++)代码,反之亦然。
为什么存在:访问Java不能直接访问的硬件或操作系统资源等。
Java Framework Service
是Android框架中的各种服务组件,如Activity Manager Service、Window Manager Service等
HAL (Hardware Abstraction Layer)
HAL是Android系统中用于抽象硬件的一层,它定义了一套标准的接口,使得上层系统(如Android框架)可以与底层硬件进行交互,而无需关心硬件的具体实现细节。HAL的主要目的是提供一致的硬件接口定义,使得Android系统可以在不同硬件平台上运行,而无需修改上层代码。承上启下的作用。
场景模拟理解
假设一个APP需要用到摄像头。
首先APP通过IPC向Java framework service摄像头相关服务发出请求。
Java framework service接到请求后通过JNI接口向HAL摄像头相关模块发出请求。
HAL接收到请求后,会通过摄像头相应的设备文件进行通信,最终实现对摄像头的使用。
代码理解
硬件抽象层就是由设备和模块组成。
一个模块就是一个so文件(模块类型+设备名称命名)。
在so文件中用hw_module_t结构体来描述模块,功能就是打开指定设备。
typedef struct {
char module_name[50]; // 模块名称
int version; // 版本号
void (*init)(void); // 初始化函数指针
void (*deinit)(void); // 反初始化函数指针
int (*read)(char *buffer, int size); // 读取数据函数指针
int (*write)(const char *buffer, int size); // 写入数据函数指针
} hw_module_t;
然后呢,一个模块又可以包含多个设备。和模块类似,用hw_device_t来描述设备。包含硬件特点功能的函数指针。
typedef struct {
char device_name[50]; // 设备名称
int device_id; // 设备ID
void (*open)(void); // 打开设备函数指针
void (*close)(void); // 关闭设备函数指针
int (*read)(char *buffer, int size); // 读取数据函数指针
int (*write)(const char *buffer, int size); // 写入数据函数指针
} hw_device_t;