Android的Framework分析

大家都知道android是基于linux的kernel上的。android可以 运行在intel,高通,nvidia等硬件平台。但是涉及到一些GPU,显卡和一些设备的驱动问题,因为这些驱动都不是开源的,google位了兼容这些设备厂商的驱动源码,提出了硬件抽象层HAL的概念。HAL层对上为framework和native开发提供统一的API接口,为下层驱动的代码提供统一的调用接口。本文主要讲解HAL是如何实现的。

1.HAL的数据结构

 HAL的通用写法里面有两个重要的结构体:

1.1 hw_module_t 硬件模块结构体

1typedef struct hw_module_t { 2 /** tag must be initialized to HARDWARE_MODULE_TAG */ 3 uint32_t tag; 4 5 6 uint16_t module_api_version; 7#define version_major module_api_version 8 /** 9 * version_major/version_minor defines are supplied here for temporary 10 * source code compatibility. They will be removed in the next version. 11 * ALL clients must convert to the new version format. 12 */ 13 14 /** 15 * The API version of the HAL module interface. This is meant to 16 * version the hw_module_t, hw_module_methods_t, and hw_device_t 17 * structures and definitions. 18 * 19 * The HAL interface owns this field. Module users/implementations 20 * must NOT rely on this value for version information. 21 * 22 * Presently, 0 is the only valid value. 23 */ 24 uint16_t hal_api_version; 25#define version_minor hal_api_version 26 27 /** Identifier of module */ 28 const char *id; 29 30 /** Name of this module */ 31 const char *name; 32 33 /** Author/owner/implementor of the module */ 34 const char *author; 35 36 /** Modules methods */ 37 struct hw_module_methods_t* methods; 38 39 /** module's dso */ 40 void* dso; 41 42 /** padding to 128 bytes, reserved for future use */ 43 uint32_t reserved[32-7]; 44 45} hw_module_t;

该结构体表示 抽象的硬件模块,包含硬件模块的一些基本信息。里面内嵌了一个

1typedef struct hw_module_methods_t { 2    /** Open a specific device */ 3    int (*open)(const struct hw_module_t* module, const char* id, 4            struct hw_device_t** device); 5 6 7} hw_module_methods_t;

模块方法的结构体,open的函数指针,用于打开一个硬件设备hw_device_t。开发者需要实现这个open函数。

1.2硬件设备结构体

1typedef struct hw_device_t { 2 /** tag must be initialized to HARDWARE_DEVICE_TAG */ 3 uint32_t tag; 4 5 uint32_t version; 6 7 8 /** reference to the module this device belongs to */ 9 struct hw_module_t* module; 10 11 12 /** padding reserved for future use */ 13 uint32_t reserved[12]; 14 15 16 /** Close this device */ 17 int (*close)(struct hw_device_t* device); 18 19 20} hw_device_t;

表示一个硬件抽象设备。这是通用的结构体,开发者可以继承这个结构体添加自己需要的接口。

1.3 获取一个hw_model_t模块

HAL层提供一个方法用户获取一个model,进而同过open方法打开设备device

1/** 2 * Get the module info associated with a module by id. 3 * 4 * @return: 0 == success, <0 == error and *module == NULL 5 */ 6int hw_get_module(const char *id, const struct hw_module_t **module);

定义一个全局变量

const struct hw_module_t   HAL_MODULE_INFO_SYM={ ...};

用于在hw_get_modules通过解析so时,得到该全局变量。

2.硬件模块库的装载于解析
装载和解析有hw_get_module 完成,它会安按照一定的规则去查找so库,然后解析出全局变量名,得到硬件设备的open函数,最后通过参数返回一个device的指针给调用者。

2.1搜索so的规则;

1/** Base path of the hal modules */ 2#define HAL_LIBRARY_PATH1 "/system/lib/hw" 3#define HAL_LIBRARY_PATH2 "/vendor/lib/hw" 4 5/** 6 * There are a set of variant filename for modules. The form of the filename 7 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 8 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: 9 * 10 * led.trout.so 11 * led.msm7k.so 12 * led.ARMV6.so 13 * led.default.so 14 */ 15 16static const char *variant_keys[] = { 17 "ro.hardware", /* This goes first so that it can pick up a different 18 file on the emulator. */ 19 "ro.product.board", 20 "ro.board.platform", 21 "ro.arch" 22};

搜索规则就是按照上面的说明进行。

2.2函数加载解析的过程

(1)调用hw_get_module,通过传给他一个module_id 字符串例如“camera”等。调用hw_get_module_by_class(id, NULL, module);

 (2)搜索对应的so并调用load去解析so

1int hw_get_module_by_class(const char *class_id, const char *inst, 2 const struct hw_module_t **module) 3{ 4 int status = -EINVAL; 5 int i = 0; 6 char prop[PATH_MAX] = {0}; 7 char path[PATH_MAX] = {0}; 8 char name[PATH_MAX] = {0}; 9 10 if (inst) 11 snprintf(name, PATH_MAX, "%s.%s", class_id, inst); 12 else 13 strlcpy(name, class_id, PATH_MAX); 14 15 /* 16 * Here we rely on the fact that calling dlopen multiple times on 17 * the same .so will simply increment a refcount (and not load 18 * a new copy of the library). 19 * We also assume that dlopen() is thread-safe. 20 */ 21 22 /* Loop through the configuration variants looking for a module */ 23 for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) { 24 if (i < HAL_VARIANT_KEYS_COUNT) { 25 if (property_get(variant_keys[i], prop, NULL) == 0) { 26 continue; 27 } 28 snprintf(path, sizeof(path), "%s/%s.%s.so", 29 HAL_LIBRARY_PATH2, name, prop); 30 if (access(path, R_OK) == 0) break; 31 32 snprintf(path, sizeof(path), "%s/%s.%s.so", 33 HAL_LIBRARY_PATH1, name, prop); 34 if (access(path, R_OK) == 0) break; 35 } else { 36 snprintf(path, sizeof(path), "%s/%s.default.so", 37 HAL_LIBRARY_PATH2, name); 38 if (access(path, R_OK) == 0) break; 39 40 snprintf(path, sizeof(path), "%s/%s.default.so", 41 HAL_LIBRARY_PATH1, name); 42 if (access(path, R_OK) == 0) break; 43 } 44 } 45 46 status = -ENOENT; 47 if (i < HAL_VARIANT_KEYS_COUNT+1) { 48 /* load the module, if this fails, we're doomed, and we should not try 49 * to load a different variant. */ 50 status = load(class_id, path, module); 51 } 52 53 return status; 54}

(3)load函数解析so,得到hw_module_t的hw_device_t的函数指针。

1/** 2 * Load the file defined by the variant and if successful 3 * return the dlopen handle and the hmi. 4 * @return 0 = success, !0 = failure. 5 */ 6static int load(const char *id, 7 const char *path, 8 const struct hw_module_t **pHmi) 9{ 10 int status = -EINVAL; 11 void *handle = NULL; 12 struct hw_module_t *hmi = NULL; 13 14 /* 15 * load the symbols resolving undefined symbols before 16 * dlopen returns. Since RTLD_GLOBAL is not or'd in with 17 * RTLD_NOW the external symbols will not be global 18 */ 19 handle = dlopen(path, RTLD_NOW); 20 if (handle == NULL) { 21 char const *err_str = dlerror(); 22 ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown"); 23 status = -EINVAL; 24 goto done; 25 } 26 27 /* Get the address of the struct hal_module_info. */ 28 const char *sym = HAL_MODULE_INFO_SYM_AS_STR; 29 hmi = (struct hw_module_t *)dlsym(handle, sym); 30 if (hmi == NULL) { 31 ALOGE("load: couldn't find symbol %s", sym); 32 status = -EINVAL; 33 goto done; 34 } 35 36 /* Check that the id matches */ 37 if (strcmp(id, hmi->id) != 0) { 38 ALOGE("load: id=%s != hmi->id=%s", id, hmi->id); 39 status = -EINVAL; 40 goto done; 41 } 42 43 hmi->dso = handle; 44 45 /* success */ 46 status = 0; 47 48 done: 49 if (status != 0) { 50 hmi = NULL; 51 if (handle != NULL) { 52 dlclose(handle); 53 handle = NULL; 54 } 55 } else { 56 ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", 57 id, path, *pHmi, handle); 58 } 59 60 *pHmi = hmi; 61 62 return status; 63}

版权声明:本文为博主原创文章,未经博主允许不得转载。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

一篇文章带你了解JavaScript日期

日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用