当前位置:网站首页>2. Hal hardware abstraction layer
2. Hal hardware abstraction layer
2022-07-03 11:10:00 【MrPeng1991】
1.hal Drive development
2. hal Hardware abstraction layer
3 Android Hardware access services JNI Realization
android The system hardware abstraction layer manages various hardware access interfaces in the form of modules , Each hardware module corresponds to a dynamic link library file , The naming of these dynamic link library files should conform to the specification .
Inside the system , Each hardware abstraction layer module should use a structure hw_module_t To describe , Hardware devices use structures hw_device_t To describe
1 Hardware abstraction layer module file naming specification :
// hardware/libhardware/hardware.c
/** * There are a set of variant filename for modules. The form of the filename * is "<MODULE_ID>.variant.so" so for the led module the Dream variants * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: * * MODULE_ID : Modular ID * led.trout.so * led.msm7k.so * led.ARMV6.so * led.default.so */
// variant Represents four system attributes ro.hardware、 ro.product.board、 ro.board.platform and ro.arch One of
// Take their attribute values in order from top to bottom , One of the system attributes exists , Take its value as variant Value ,
// Then check whether the corresponding file exists , If there is , Find the hardware abstraction layer module file to be loaded ;
// otherwise , Continue to find the next system attribute .
// Such as All system attributes do not exist , or All hardware abstraction layer module files do not exist ,
// Just use “ <MODULE_ID>.default.so ” As the name of the hardware abstraction layer module file to be loaded
static const char *variant_keys[] = {
"ro.hardware", /* from init The process is responsible for setting */ /* This goes first so that it can pick up a different file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
System attribute ro.hardware When the system starts , from init The process is responsible for setting .
It will read first /proc/cmdline file , Then check whether there is androidboot.hardware Properties of , If there is , Take its value as an attribute ro.hardware Value ; otherwise , will /proc/cpuinfo The hardware information in the file is parsed , That is to say take Hardware The content of the field is used as an attribute ro.hardware Value .
System attribute ro.product.board、ro.board.platform and ro.arch It's from /system/build.prop The file reads out .
file /system/build.prop It is compiled by the compilation script in the compilation system build/core/Makefile and Shell Script build/tools/buildinfo.sh Generated
2 Hardware abstraction layer module structure definition specification :
Structure hw_module_t :
// hardware\libhardware\include\hardware\hardware.h
/* * Value for the hw_module_t.tag field */
#define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))
#define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')
#define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')
struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;
/** * 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. */
/* Each module in the hardware abstraction layer must customize a hardware abstraction layer module structure , And its first member variable must be of type hw_module_t */
typedef struct hw_module_t
{
/** tag must be initialized to HARDWARE_MODULE_TAG */
/* Member variables tag The value of must be set to HARDWARE_MODULE_TAG, That is, set to a constant value ('H'<<24|'W'<<16|'M'<<8|'T'), It is used to mark that this is a hardware abstraction layer module structure */
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 */
/* Defines a list of operation methods of hardware abstraction layer modules */
struct hw_module_methods_t* methods;
/** module's dso */
/* Save the handle value obtained after loading the hardware abstraction layer module */
/* * The process of loading hardware abstraction layer modules is actually calling dlopen Function to load the corresponding DLL file . * Calling dlclose Function to unload this hardware abstraction layer module , To use this handle value */
void* dso;
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
} hw_module_t;
// ...
/** * Name of the hal_module_info */
/* Every module in the hardware abstraction layer must have an exported symbol HAL_MODULE_IFNO_SYM, namely “HMI”, It points to a custom hardware abstraction layer module structure */
#define HAL_MODULE_INFO_SYM HMI
//...
Structure hw_module_methods_t :
// hardware\libhardware\include\hardware\hardware.h
typedef struct hw_module_methods_t
{
/** Open a specific device */
/** * @function: Open the hardware device in the hardware abstraction layer module * @parameter: * module : The module of the hardware device to be opened * id : Of the hardware device to be turned on ID * device : An output parameter , Describe a hardware device that has been turned on * @return: * success: * error: * @note: */
int (*open)(const struct hw_module_t* module,
const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
Structure hw_device_t :
// hardware\libhardware\include\hardware\hardware.h
#define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')
/** * Every device data structure must begin with hw_device_t * followed by module specific public methods and attributes. */
/* * Each hardware device in the hardware abstraction layer module must customize a hardware device structure , * And its first member variable must be of type hw_device_t */
typedef struct hw_device_t
{
/** tag must be initialized to HARDWARE_DEVICE_TAG */
/* * tag must == HARDWARE_DEVICE_TAG, That is, set to a constant value ('H'<<24|'W'<<16|'D'<<8|'T'), * It is used to mark that this is a hardware device structure in the hardware abstraction layer */
uint32_t tag;
/** version number for hw_device_t */
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
uint32_t reserved[12];
/** Close this device */
/* Turn off a hardware device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
The hardware device in the hardware abstraction layer is opened by the interface provided by its module , The shutdown is completed by the interface provided by the hardware device itself
3 Write hardware abstraction layer module interface
The module interface source files in the hardware abstraction layer are generally saved in hardware/libhardware Directory
Virtual hardware devices freg The module name in the hardware abstraction layer is defined as freg
~/Android/hardware/libhardware
include
hardware
freg.h
Modules
freg
freg.cpp
Android.mk
// Android/hardware/libhardware/include/hardware/freg.h
#ifndef ANDROID_FREG_INTERFACE_H
#define ANDROID_FREG_INTERFACE_H
__BEGIN_DECLS
// Constants and structures are defined according to the hardware abstraction layer module writing specification
/** * The id of this module */
// Define modules ID
#define FREG_HARDWARE_MODULE_ID "freg"
/** * The id of this device */
// Defining devices ID
#define FREG_HARDWARE_DEVICE_ID "freg"
// Describe the custom module structure
struct freg_module_t
{
// The first member variable must be of type hw_module_t
struct hw_module_t common;
};
// Describe the virtual hardware device freg
struct freg_device_t
{
// The first member variable must be of type hw_device_t
struct hw_device_t common;
// A file descriptor , Used to describe the open device file /dev/freg
int fd;
// Write virtual hardware devices freg The register of val The content of
int (*set_val)(struct freg_device_t* dev, int val);
// Read virtual hardware devices freg The register of val The content of
int (*get_val)(struct freg_device_t* dev, int* val);
};
__END_DECLS
#endif
freg.cpp Hardware abstraction layer module freg Implementation file of :
// Android/hardware/libhardware/Modules/freg/freg.cpp
#define LOG_TAG "FregHALStub"
#include <hardware/hardware.h>
#include <hardware/freg.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#define DEVICE_NAME "/dev/freg"
#define MODULE_NAME "Freg"
#define MODULE_AUTHOR "cpucode"
/* The device opens the interface */
static int freg_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device);
/* Device shutdown interface */
static int freg_device_close(struct hw_device_t* device);
/* Device register write interface */
static int freg_set_val(struct freg_device_t* dev, int val);
/* Device register read interface */
static int freg_get_val(struct freg_device_t* dev, int* val);
/* Define module operation method structure variables */
static struct hw_module_methods_t freg_module_methods = {
open: freg_device_open
};
/* Define module structure variables */
// Each hardware abstraction layer module must export a module named HAL_MODULE_INFO_SYM The symbol of
struct freg_module_t HAL_MODULE_INFO_SYM = {
common: {
// tag must == HARDWARE_MODULE_TAG
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: FREG_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &freg_module_methods,
}
};
// Open operation
static int freg_device_open(const struct hw_module_t* module,
const char* id,
struct hw_device_t** device)
{
// Judge id With virtual hardware devices freg Of ID Whether the value is matching
if(!strcmp(id, FREG_HARDWARE_DEVICE_ID))
{
struct freg_device_t* dev;
dev = (struct freg_device_t*)malloc(sizeof(struct freg_device_t));
if(!dev)
{
LOGE("Failed to alloc space for freg_device_t.");
return -EFAULT;
}
memset(dev, 0, sizeof(struct freg_device_t));
// Hardware device label (dev->common.tag) must == HARDWARE_DEVICE_TAG
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
// The closing function is set to freg_device_close
dev->common.close = freg_device_close;
// Write function
dev->set_val = freg_set_val;
// Read function
dev->get_val = freg_get_val;
// Open the virtual hardware device file /dev/freg , And the obtained file descriptor is saved in the structure freg_device_t Member variables of fd in
if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1)
{
LOGE("Failed to open device file /dev/freg -- %s.", strerror(errno));
free(dev);
return -EFAULT;
}
*device = &(dev->common);
LOGI("Open device file /dev/freg successfully.");
return 0;
}
return -EFAULT;
}
// Virtual hardware device freg Closing function of
static int freg_device_close(struct hw_device_t* device)
{
struct freg_device_t* freg_device = (struct freg_device_t*)device;
if(freg_device)
{
// Close device file /dev/freg
close(freg_device->fd);
// release device
free(freg_device);
}
return 0;
}
static int freg_set_val(struct freg_device_t* dev, int val)
{
if(!dev)
{
LOGE("Null dev pointer.");
return -EFAULT;
}
LOGI("Set value %d to device file /dev/freg.", val);
// Write virtual hardware devices freg The register of val The content of
write(dev->fd, &val, sizeof(val));
return 0;
}
static int freg_get_val(struct freg_device_t* dev, int* val)
{
if(!dev)
{
LOGE("Null dev pointer.");
return -EFAULT;
}
if(!val)
{
LOGE("Null val pointer.");
return -EFAULT;
}
// Read virtual hardware devices freg The register of val The content of
read(dev->fd, val, sizeof(*val));
LOGI("Get value %d from device file /dev/freg.", *val);
return 0;
}
Compile the script
# Android/hardware/libhardware/Modules/freg/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
# Save in out/target/product/generic/system/lib/hw
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := freg.cpp
LOCAL_MODULE := freg.default
# Compile the hardware abstraction layer module into a dynamic link library file , The name is freg.default.so
include $(BUILD_SHARED_LIBRARY)
# According to the naming specification of the hardware abstraction layer module file , When we want to load the hardware abstraction layer module freg when , Just specify its ID value == freg
# The system will successfully find what to load according to certain rules freg.default.so file
4 Loading process of hardware abstraction layer module
Android The hardware abstraction layer modules in the system are uniformly loaded by the system , When the caller needs to load these modules , Just specify their ID The value will do
Functions responsible for loading hardware abstraction layer modules hw_get_module :
// hardware\libhardware\hardware.c
/** Base path of the hal modules */
// Define the directory of the hardware abstraction layer module file to be loaded
// The compiled module file is located in out/target/product/generic/system/lib/hw Directory ,
// And this directory is packaged , It corresponds to... On the device /system/lib/hw Catalog
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
// The defined directory is /vendor/lib/hw , It is used to save the hardware abstraction layer module interface file provided by the equipment manufacturer
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
/** * There are a set of variant filename for modules. The form of the filename * is "<MODULE_ID>.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 */
// The file name of the hardware abstraction layer module to be loaded
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"
};
// Array variant_keys Size
static const int HAL_VARIANT_KEYS_COUNT = (sizeof(variant_keys)/ sizeof(variant_keys[0]));
// id: Input parameters , Represents the hardware abstraction layer module to be loaded ID;
// module : Output parameters , If the load is successful , Then it points to a customized hardware abstraction layer module structure
// return: 0 == success, <0 == error and *pHmi == NULL
// Load the hardware abstraction layer module
int hw_get_module(const char *id, const struct hw_module_t **module)
{
int status;
int i;
const struct hw_module_t *hmi = NULL;
char prop[PATH_MAX];
char path[PATH_MAX];
/* * Here we rely on the fact that calling dlopen multiple times on * the same .so will simply increment a refcount (and not load * a new copy of the library). * We also assume that dlopen() is thread-safe. */
/* Loop through the configuration variants looking for a module */
for (i = 0 ; i < HAL_VARIANT_KEYS_COUNT + 1 ; i++)
{
// According to the array variant_keys stay HAL_LIBRARY_PATH1 and HAL_LIBRARY_PATH2 Check whether the corresponding hardware abstraction layer module file exists in the directory ,
// If there is , End for loop ;
if (i < HAL_VARIANT_KEYS_COUNT)
{
// Get the value of the system attribute
if (property_get(variant_keys[i], prop, NULL) == 0)
{
continue;
}
snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH1, id, prop);
// Judge documents /system/lib/hw/freg.goldfish.so Whether there is
if (access(path, R_OK) == 0)
{
break;
}
snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH2, id, prop);
// Judge documents /vendor/lib/hw/freg.goldfish.so Whether there is
if (access(path, R_OK) == 0)
{
break;
}
}
else
{
// Nothing can be found
snprintf(path, sizeof(path), "%s/%s.default.so", HAL_LIBRARY_PATH1, id);
// stay /system/lib/hw Check if there is a... In the directory freg.default.so file
if (access(path, R_OK) == 0)
{
break;
}
}
}
status = -ENOENT;
if (i < HAL_VARIANT_KEYS_COUNT + 1)
{
/* load the module, if this fails, we're doomed, and we should not try * to load a different variant. */
// Operation of loading hardware abstraction layer module
status = load(id, path, module);
}
return status;
}
load Function to perform the loading operation of the hardware abstraction layer module :
// hardware\libhardware\hardware.c
/** * Load the file defined by the variant and if successful * return the dlopen handle and the hmi. * @return 0 = success, !0 = failure. */
static int load(const char *id,
const char *path,
const struct hw_module_t **pHmi)
{
int status;
void *handle;
struct hw_module_t *hmi;
/* * load the symbols resolving undefined symbols before * dlopen returns. Since RTLD_GLOBAL is not or'd in with * RTLD_NOW the external symbols will not be global */
/* Load the dynamic link library file into memory */
handle = dlopen(path, RTLD_NOW);
if (handle == NULL)
{
char const *err_str = dlerror();
LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
}
/* Get the address of the struct hal_module_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
// Get the name inside as HAL_MODULE_INFO_SYM_AS_STR The symbol of
// The symbol points to a custom hardware abstraction layer module structure ,
// It contains all the information of the corresponding hardware abstraction layer module
// Put the... In the module HMI The symbol is converted to a hw_module_t Structure pointer
hmi = (struct hw_module_t *)dlsym(handle, sym);
if (hmi == NULL)
{
LOGE("load: couldn't find symbol %s", sym);
status = -EINVAL;
goto done;
}
/* Check that the id matches */
/* Verify the loaded hardware abstraction layer module ID whether And the hardware abstraction layer module required to be loaded ID Agreement */
if (strcmp(id, hmi->id) != 0)
{
LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
status = -EINVAL;
goto done;
}
// The module handle value obtained after successful loading handle Save in hw_module_t Structure pointer hmi Member variables of dso in
hmi->dso = handle;
/* success */
status = 0;
done:
if (status != 0)
{
hmi = NULL;
if (handle != NULL)
{
dlclose(handle);
handle = NULL;
}
}
else
{
LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", id, path, *pHmi, handle);
}
*pHmi = hmi;
return status;
}
5 Deal with the access rights of hardware devices
// Android/hardware/libhardware/Modules/freg/freg.cpp
// Open operation
static int freg_device_open(const struct hw_module_t* module,
const char* id,
struct hw_device_t** device)
{
// Judge id With virtual hardware devices freg Of ID Whether the value is matching
if(!strcmp(id, FREG_HARDWARE_DEVICE_ID))
{
//...
// Open the virtual hardware device file /dev/freg , And the obtained file descriptor is saved in the structure freg_device_t Member variables of fd in
// Do not modify the equipment file /dev/freg Access rights of , Cannot be opened
if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1)
{
// Failure
LOGE("Failed to open device file /dev/freg -- %s.", strerror(errno));
free(dev);
return -EFAULT;
}
//...
}
return -EFAULT;
}
stay Linux In the system , Can pass udev Rules modify the access rights of device files when the system starts
Android The system does not realize udev Mechanism
Android Provides another uevent Mechanism , You can modify the access rights of device files when the system starts
# system\core\rootdir\ueventd.rc
# ...
/dev/binder 0666 root root
# All users can access device files /dev/freg, Can Open device file /dev/freg and Read and write its contents
/dev/freg 0666 root root
# logger should be world writable (for logging) but not readable
/dev/log/* 0662 root log
# the msm hw3d client device node is world writable/readable.
/dev/msm_hw3dc 0666 root root
# gpu driver for adreno200 is globally accessible
/dev/kgsl 0666 root root
#...
Revised ueventd.rc After the document , Recompile required Android Source code Engineering
You can also avoid recompiling Android Source code engineering can make device files /dev/freg The access rights of are effective
compile Android Source code engineering , file system/core/rootdir/ueventd.rc Will be copied to out/target/product/generic/root Under the table of contents , And finally packed in ramdisk.img In the image file .
When Android When the system starts , Will be able to ramdisk.img In the image file ueventd.rc The file is installed in the root directory of the device , And by the init Process to parse its contents and modify the access rights of the corresponding device files . therefore , As long as we can modify ramdisk.img In the image file ueventd.rc The content of the document , You can modify the device file /dev/freg Access rights of
边栏推荐
- 字节跳动大裁员,测试工程师差点遭团灭:大厂招人背后的套路,有多可怕?
- Stack, monotone stack, queue, monotone queue
- Probability theory: application of convolution in calculating moving average
- Do you really need automated testing?
- (二)进制
- Imread change image display size
- 软件测试工程师的5年之痒,讲述两年突破瓶颈经验
- QT: QSS custom qtreeview instance
- Internet Socket (非)阻塞write/read n个字节
- Qt:qss custom qpprogressbar instance
猜你喜欢
Que se passe - t - il ensuite pour ceux qui se sont concentrés sur les tests automatisés?
How to realize automatic testing in embedded software testing?
The five-year itch of software testing engineers tells the experience of breaking through bottlenecks for two years
你真的需要自动化测试吗?
T5 的尝试
What are the strengths of "testers"?
Hard goods | write all the codes as soon as you change the test steps? Why not try yaml to realize data-driven?
做软件测试三年,薪资不到20K,今天,我提出了辞职…
17K薪资要什么水平?来看看95后测试工程师的面试全过程…
10. Nacos source code construction
随机推荐
如何让让别人畏惧你
面试题总结(2) IO模型,集合,NIO 原理,缓存穿透,击穿雪崩
《通信软件开发与应用》
Hal - General
最高月薪18K 拥有好的“心态和选择”, 成功就差“认真和坚持”~
redis那些事儿
Latest sales volume of pinduoduo
15 software testing Trends Worthy of attention
项目管理精华读书笔记(七)
T5 attempt
Solve the problem that pycharm Chinese input method does not follow
Tencent micro app to get wechat user information
栈,单调栈,队列,单调队列
Communication software development and Application
Crawl with requests
What happened to those who focused on automated testing?
Summary of the history of Mathematics
Game test related tests a hero's skills (spring moves are asked more questions)
QT: QSS custom qtableview instance
Basic usage of sqlmap