Android 系统的硬件抽象层以模块的形式来管理各个硬件访问接口。每一个硬件模块都对应有一个动态链接库文件。
在系统内部,每一个硬件抽象层模块都使用结构体 hw_moudle_t 描述,而硬件设备则使用结构体 hw_device_t 来描述。下面分别描述硬件抽象层模块文件的命令规范以及结构体 hw_moudle_t 和 hw_device_t 的含义。
硬件抽象层的模块文件的命令规范定义在 hardware/libhardware/hardware.c 文件中
/**
* There are a set of variant filename for modules. The form of the filename
* is ".variant.so" so for the led module the Dream variants
* of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
*
* led.trout.so
* led.msm7k.so
* led.ARMV6.so
* led.default.so
*/
static const char *variant_keys[] = {
"ro.hardware", /* This goes first so that it can pick up a different
file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
variant变量取值过程:
ro.hardware: /prop/cpuinfo 的 Hardware 字段
其他三个在:/system/build.prop 中查找
结构体 hw_device_t 和 hw_moudle_t 及其它相关结构体定义在文件 hardware/hardware.h 中
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag;
uint16_t module_api_version;
uint16_t hal_api_version;
#define version_minor hal_api_version
/** 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;
#ifdef __LP64__
uint64_t reserved[32-7];
#else
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
#endif
}
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;
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
#ifdef __LP64__
uint64_t reserved[12];
#else
uint32_t reserved[12];
#endif
/** Close this device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
###################################
(1) 硬件抽象层模块中的每一个硬件设备必须自定义一个硬件设备结构体
而且它的第一个成员变量的类型必须为 hw_device_t
(2) 结构体 hw_device_t 的成员变量 tag 的值必须设置为 HARDWARE_DEVICE_TAG
用来标识这是一个硬件抽象层中的硬件设备结构体
(3) close 是一个函数指针,用来关闭一个硬件设备
每一个硬件抽象层模块在内核中都对应一个驱动程序,硬件抽象层模块就是通过这些驱动程序来访问硬件设备的,他们通过读写设备文件来进行通信
硬件抽象层的模块接口源文件一般保存在 harware/libhardware 中,以 freg模块 寄存器操作为例,进行说明,它的目录结构如下:
~ Android/hardware/libhardware
---- include
----- hardware
---- freg.h
---- moudles
---- power
---- freg.c
---- Android.mk
其中 freg.h 和 freg.c 是源文件,Android.mk 是模块的编译脚本文件
#ifndef ANDROID_INCLUDE_HARDWARE_FRAG_H
#define ANDROID_INCLUDE_HARDWARE_FRAG_H
#include
__BEGIN_DECLS
// 硬件模块ID
#define FRAG_HARDWARE_MODULE_ID "freg"
// 硬件设备ID
#define FRAG_HARDWARE_DEVICE_ID "freg"
// 自定义硬件模块结构体
typedef struct freg_moudle_t {
struct hw_module_t common;
}
// 自定义设备结构体
typedef struct freg_device_t {
struct hw_device_t common;
int fd;
int (*set_val)(struct freg_device_t* dev, int val);
int (*get_val)(struct freg_device_t* dev, int* val);
}
__END_DECLS
#endif // ANDROID_INCLUDE_HARDWARE_FRAG_H
这个文件中的常量结构体都是按照硬件抽象层模块编写规范来定义的。
...
#define DEVICE_NAME "/dev/frag"
#define DMOUDLE_NAME "frag"
#define MOUDLE_AUTHOR "kevin"
/* 设备打开与关闭接口 */
static int freg_device_open(const struct hw_moudle_t* moudle, const char* id, struct hw_device_t** device);
static int freg_device_open( struct hw_device_t** device);
/* 设备寄存器读写接口 */
static int freg_get_val(struct freg_device_t* dev, int* val);
static int freg_set_val(struct freg_device_t* dev, int val);
/* 定义模块操作方法结构体变量 */
static struct hw_moudle_methonds_t freg_moudle_methods = {
open: freg_device_open
}
/* 定义模块结构体变量 */
struct freg_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = 1,
.hal_api_version = 1,
.id = POWER_HARDWARE_MODULE_ID,
.name = MOUDLE_NAME,
.author = MOUDLE_AUTHOR,
.methods = &freg_moudle_methods,
},
.init = power_init,
.setInteractive = power_set_interactive,
.powerHint = power_hint,
};
...
在这段代码中,最值得关注的是模块变量 HAL_MODULE_INFO_SYM 的定义,按照硬件抽象层模块编写规范,每一个硬件抽象层模块必须导出一个名称为 HAL_MODULE_INFO_SYM 的符号,它指向一个自定义的硬件抽象层模块结构体。
1. LOCAL_PATH := $(call my-dir)
2. include $(CLEAR_VARS)
3. LOCAL_MODULE_TAGS := optional
4. LOCAL_PROPRIETARY_MODULE := true
5. LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
6. LOCAL_SHARED_LIBRARIES := liblog
7. LOCAL_SRC_FILES := freg.cpp
8. LOCAL_MODULE := freg.default
9. include $(BUILD_SHARED_LIBRARY)
在 Android 硬件抽象层,负责加载硬件抽象模块的函数时 hw_get_moudle,它的原型如下:
# Android/hardware/libhardware/include/hardware/hardware.h
/**
* Get the module info associated with a module by id.
*
* @return: 0 == success, <0 == error and *module == NULL
*/
int hw_get_module(const char *id, const struct hw_module_t **module);
===================================================
id:输入参数,表示要加载的硬件抽象层模块ID
moudle:输出参数,如果加载成功,它指向一个自定义的硬件抽象层模块结构体
函数返回值等于0代表加载成功,小于0则表示加载失败
简单阐述一下 hw_get_module 的实现过程,代码在 hardware.c 中
因为上层应用框架使用java语言开发,而硬件抽象层是使用C++语言进行开发,所以必须通过Java本地接口(JNI)来调用硬件抽象层模块的接口
Android 系统的硬件访问服务通常运行在系统进程 System 中,应用程序所在的进程要想访问硬件访问服务就需要通过一种进程间通信机制。
Android 提供了一种高效的进程间通信机制 —— Binder进程间通信,应用程序通过它来访问运行在系统进程System中的硬件访问服务。因此实现硬件硬件访问服务之前,首先要定义它的服务接口。
从应用层往下分析,以PoweManager为例:
该文件中为用户提供了很多关于电源管理方法的操作,这些操作都是通过 Android Binder 进程间通信实现,简单来说就是通过 PowerManagerService 服务提供的接口来实现的
// mService = IPowerManager.Stub.asInterface("---");
final IPowerManager mService;
public boolean isInteractive() {
try {
return mService.isInteractive();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
===========================================
- 1. mService 是PoweManagerService服务的Binder代理对象
- 2. 使用 IPowerManager.Stub.asInterface 获取电源管理服务的 Binder 代理对象
- 3. 使用 mService 代理对象进行电源管理相关的操作,所以使用远程电源管理服务提供的接口
该文件定义了电源硬件访问的服务接口
Android 接口定义语言(AIDL)是 Android 系统提供的一种描述语言来定义具体跨进程访问能力的服务接口。在编译时,ADIL文件会被转换成 java 语言,这个转换 java 语言中就包含 Binder 本地对象类 Stub,它实现了 IPowerManager 接口。
前面说到服务接口是用来进程间通信的,提供服务的进程称为Service进程,而使用服务的进程称为 Client 进程(APP),在Service进程中,每一个服务都对应有一个本地 Binder 对象,它通过一个桩(Stub)来等待客户端连接。Client 客户端进程在访问服务之前,首先获取它的一个 Binder 代理对象(Proxy),然后通过这个代理对象接口访问服务接口。
前面的 AIDL 文件提供了服务接口,但是还没有一个具体的地方去实现这些接口,在 PowerManagerService.java 中从 IPowerManager.Stub 类继承下来,并且实现了这一些接口
private final class BinderService extends IPowerManager.Stub {
...
}
#include
#include
// Check validity of current handle to the power HAL service, and call getService() if necessary.
// The caller must be holding gPowerHalMutex.
bool getPowerHal() {
if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
if (gPowerHalV1_0 != nullptr) {
gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
ALOGI("Loaded power HAL service");
} else {
ALOGI("Couldn't load power HAL service");
gPowerHalExists = false;
}
}
return gPowerHalV1_0 != nullptr;
}
int register_android_server_PowerManagerService(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService",
gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
(void) res; // Faked use when LOG_NDEBUG.
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
// Callbacks
jclass clazz;
FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
"userActivityFromNative", "(JII)V");
// Initialize
for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
gLastEventTime[i] = LLONG_MIN;
}
gPowerManagerServiceObj = NULL;
return 0;
}
register_android_server_PowerManagerService 函数时上一小节中编写为了注册到 Java 虚拟机中去的。
onload.cpp 文件实现在 libandroid_service 模块中,当系统加载 libandroid_service 模块时,就会调用 onload.cpp 中的 JNI_Load 函数,添加 native 方法的 Java 虚拟机注册
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
...
register_android_server_PowerManagerService(env);
...
}
前面说到,System 系统进程中会启动各种硬件访问服务,可以在该文件中添加电源模块服务的启动,这样系统一启动,服务就开启了
private void startOtherServices() {
....
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
....
private void startOtherServices() {
...
try {
// TODO: use boot phase
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
...
}
}