Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析
分类:Android2012-07-2301:251529人阅读评论(16)收藏举报前面在介绍Android系统的开机画面时提到,Android设备的显示屏被抽象为一个帧缓冲区,而Android系统中的SurfaceFlinger服务就是通过向这个帧缓冲区写入内容来绘制应用程序的用户界面的。Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。本文将详细分析Gralloc模块的实现,为后续分析SurfaceFlinger服务的实现打下基础。
在前面Android系统的开机画面显示过程分析一文中提到,Linux内核在启动的过程中会创建一个类别和名称分别为“graphics”和“fb0”的设备,用来描述系统中的第一个帧缓冲区,即第一个显示屏,其中,数字0表示从设备号。注意,系统中至少要存在一个显示屏,因此,名称为“fb0”的设备是肯定会存在的,否则的话,就是出错了。Android系统和Linux内核本身的设计都是支持多个显示屏的,不过,在Android目前的实现中,只支持一个显示屏。
在前面Android系统的开机画面显示过程分析一文中还提到,init进程在启动的过程中,会启动另外一个进程ueventd来管理系统的设备文件。当ueventd进程启动起来之后,会通过netlink接口来Linux内核通信,以便可以获得内核中的硬件设备变化通知。而当ueventd进程发现内核中创建了一个类型和名称分别为“graphics”和“fb0”的设备的时候,就会这个设备创建一个/dev/graphics/fb0设备文件。这样,用户空间的
应用程序就可以通过设备文件/dev/graphics/fb0来访问内核中的帧缓冲区,即在设备的显示屏中绘制指定的画面。注意,用户空间的应用程序一般是通过内存映射的方式来访问设备文件/dev/graphics/fb0的。
Android系统定义了硬件抽象层模块的编写规范,具体可以参考Android硬件抽象层(HAL)概要介绍和学习计划一文。本文假设读者已经熟悉Android系统的硬件抽象层编写规范,因此,我们将按照帧缓冲区的使用情景以及硬件抽象层编写规范来介绍Gralloc模块的实现。
用户空间的应用程序在使用帧缓冲区之间,首先要加载Gralloc模块,并且获得一个gralloc设备和一个fb设备。有了gralloc设备之后,用户空间中的应用程序就可以申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间来,以便可以向里面写入要绘制的画面的内容。最后,用户空间中的应用程序就通过fb设备来将前面已经准备好了的图形缓冲区渲染到帧缓冲区中去,即将图形缓冲区的内容绘制到显示屏中去。相应地,当用户空间中的应用程序不再需要使用一块图形缓冲区的时候,就可以通过gralloc设备来释放它,并且将它从地址空间中解除映射。接下来,我们就按照上述使用情景来分析Gralloc 模块的实现。
1.Gralloc模块的加载过程。
每一个HAL模块都有一个ID值,以这些ID值为参数来调用硬件抽象层提供的函数
hw_get_module就可以将指定的模块加载到内存来,并且获得一个hw_module_t接口来打开相应的设备。
Gralloc模块的ID值定义在hardware/libhardware/include/hardware/gralloc.件中,如下所示:[cpp]view plaincopy
1#define GRALLOC_HARDWARE_MODULE_ID"gralloc"
函数hw_get_module实现在hardware/libhardware/hardware.c文件中,如下所示:
[cpp]view plaincopy
2/**Base path of the hal modules*/
3#define HAL_LIBRARY_PATH1"/system/lib/hw"
4#define HAL_LIBRARY_PATH2"/vendor/lib/hw"
5
6/**
7*There are a set of variant filename for modules.The form of the filename
8*is"<MODULE_ID>.variant.so"so for the led module the Dream variants
9*of base"ro.product.board","ro.board.platform"and"ro.arch"would be:
10*
ut.so
12*led.msm7k.so
13*led.ARMV6.so
14*led.default.so
15*/
16
17static const char*variant_keys[]={
18"ro.hardware",/*This goes first so that it can pick up a different 19file on the emulator.*/
20"ro.product.board",
21"ro.board.platform",
22"ro.arch"
23};
24
25static const int HAL_VARIANT_KEYS_COUNT=
26(sizeof(variant_keys)/sizeof(variant_keys[0]));
27
<
29
30int hw_get_module(const char*id,const struct hw_module_t**module)
31{
32int status;
33int i;
34const struct hw_module_t*hmi=NULL;
linux和安卓的关系35char prop[PATH_MAX];
36char path[PATH_MAX];
37
38/*
39*Here we rely on the fact that calling dlopen multiple times on
40*the same.so will simply increment a refcount(and not load
41*a new copy of the library).
42*We also assume that dlopen()is thread-safe.
43*/
44
45/*Loop through the configuration variants looking for a module*/
46for(i=0;i<HAL_VARIANT_KEYS_COUNT+1;i++){
47if(i<HAL_VARIANT_KEYS_COUNT){
48if(property_get(variant_keys[i],prop,NULL)==0){
49continue;
50}
51
52snprintf(path,sizeof(path),"%s/%s.%s.so",
53HAL_LIBRARY_PATH1,id,prop);
54if(access(path,R_OK)==0)break;
55
56snprintf(path,sizeof(path),"%s/%s.%s.so",
57HAL_LIBRARY_PATH2,id,prop);
58if(access(path,R_OK)==0)break;
59}else{
60snprintf(path,sizeof(path),"%s/%s.default.so",
61HAL_LIBRARY_PATH1,id);
62if(access(path,R_OK)==0)break;
63}
64}
65
66status=-ENOENT;
67if(i<HAL_VARIANT_KEYS_COUNT+1){
68/*load the module,if this fails,we're doomed,and we should not try
69*to load a different variant.*/
70status=load(id,path,module);
71}
72
73return status;
74}
函数hw_get_module依次在目录/system/lib/hw和/vendor/lib/hw中查一个名称为
"<MODULE_ID>.variant.so"的文件,其中,<MODULE_ID>是一个模块ID,而variant表示"ro.hardware"、"ro.product.board"、"ro.board.platform"和"ro.arch"四个系统属性值之一。例如,对于Gralloc模块来说,函数hw_get_module依次在目录/system/lib/hw和/vendor/lib/hw中检查是否存在以下四个文件:gralloc.<ro.hardware>.so
gralloc.<ro.product.board>.so
gralloc.<ro.board.platform>.so
gralloc.<ro.arch>.so
只要其中的一个文件存在,函数hw_get_module就会停止查过程,并且调用另外一个函数load 来将这个文件加载到内存中来。另一方面,如果在/system/lib/hw和/vendor/lib/hw中均不存这些文件,那么函数hw_get_module就会在目录/system/lib/hw中查是否存在一个名称为gralloc.default.so的文件。如果存在的话,那么也会调用函数load将它加载到内存中来。
函数load也是实现在文件hardware/libhardware/hardware.c文件中,如下所示:
[cpp]view plaincopy
75static int load(const char*id,
76const char*path,
77const struct hw_module_t**pHmi)
78{
79int status;
80void*handle;
81struct hw_module_t*hmi;
82
83/*
84*load the symbols resolving undefined symbols before
85*dlopen returns.Since RTLD_GLOBAL is not or'd in with
86*RTLD_NOW the external symbols will not be global
87*/
88handle=dlopen(path,RTLD_NOW);
89if(handle==NULL){
90char const*err_str=dlerror();
91LOGE("load:module=%s\n%s",path,err_str?err_str:"unknown"); 92status=-EINVAL;
93goto done;
94}
95
96/*Get the address of the struct hal_module_info.*/
97const char*sym=HAL_MODULE_INFO_SYM_AS_STR;
98hmi=(struct hw_module_t*)dlsym(handle,sym);
99if(hmi==NULL){
100LOGE("load:couldn't find symbol%s",sym);
101status=-EINVAL;
102goto done;
103}
104
105/*Check that the id matches*/
106if(strcmp(id,hmi->id)!=0){
107LOGE("load:id=%s!=hmi->id=%s",id,hmi->id);
108status=-EINVAL;
109goto done;
110}
111
112hmi->dso=handle;
113
114/*success*/
115status=0;
116
117done:
118if(status!=0){
119hmi=NULL;
120if(handle!=NULL){
121dlclose(handle);
122handle=NULL;
123}
124}else{
125LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
126id,path,*pHmi,handle);
127}
128
129*pHmi=hmi;
130
131return status;
132}
在Linux系统中,后缀名为"so"的文件为动态链接库文件,可能通过函数dlopen来加载到内存中。硬件抽象层模块编写规范规定每一个硬件抽象层模块都必须导出一个符号名称为
HAL_MODULE_INFO_SYM_AS_STR的符号,而且这个符号必须是用来描述一个类型为hw_module_t的结构体的。
HAL_MODULE_INFO_SYM_AS_STR是一个宏,定义在文件
hardware/libhardware/include/hardware/hardware.件中,如下所示:
[cpp]view plaincopy
133#define HAL_MODULE_INFO_SYM_AS_STR"HMI"
将Gralloc模块加载到内存中来之后,就可以调用函数dlsym来获得它所导出的符号HMI。由于这个符号
指向的是一个hw_module_t结构体,因此,最后函数load就可以强制地将这个符号转换为一个
hw_module_t结构体指针,并且保存在输出参数pHmi中返回给调用者。调用者获得了这个hw_module_t结构体指针之后,就可以创建一个gralloc设备或者一个fb设备。
模块Gralloc实现在目录hardware/libhardware/modules/gralloc中,它导出的符号HMI定义在文件hardware/libhardware/modules/gralloc/gralloc.cpp文件中,如下所示:
[cpp]view plaincopy
134static struct hw_module_methods_t gralloc_module_methods={
135open:gralloc_device_open
136};
137
138struct private_module_t HAL_MODULE_INFO_SYM={
139base:{
140common:{
141tag:HARDWARE_MODULE_TAG,
142version_major:1,
143version_minor:0,
144id:GRALLOC_HARDWARE_MODULE_ID,
145name:"Graphics Memory Allocator Module",
146author:"The Android Open Source Project",
147methods:&gralloc_module_methods
148},
149registerBuffer:gralloc_register_buffer,
150unregisterBuffer:gralloc_unregister_buffer,
151lock:gralloc_lock,
152unlock:gralloc_unlock,
153},
154framebuffer:0,
155flags:0,
156numBuffers:0,
157bufferMask:0,
158lock:PTHREAD_MUTEX_INITIALIZER,
159currentBuffer:0,
160};
HAL_MODULE_INFO_SYM也是一个宏,它的值是与宏HAL_MODULE_INFO_SYM_AS_STR对应的,它也是定义在文件hardware/libhardware/include/hardware/hardware.件中,如下所示:
[cpp]view plaincopy
161#define HAL_MODULE_INFO_SYM HMI
符号HAL_MODULE_INFO_SYM的类型为private_module_t。前面提到,符号
HAL_MODULE_INFO_SYM必须指向一个hw_module_t结构体,但是这里它指向的却是一个
private_module_t结构体,是不是有问题呢?为了弄清楚这个问题,我们首先了解一下结构体
private_module_t的定义,如图1所示:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。