【android开发】Android GUI系统学习1:Gralloc

Gralloc模块是从Android Eclair(android 2.1)开始加入的一个HAL模块,Gralloc的含义为是Graphics Alloc(图形分配)。他对上为libui提供服务,为其分配显存,刷新显示等。对下对framebuffer进行管理。

gralloc代码通常位于hardware/libhardware/modules/gralloc目录下。包含以下几个文件:

Android.mk framebuffer.cpp gralloc.cpp gralloc_priv.h gr.h mapper.cpp

另外,与其相关的头文件位于hardware/libhardware/include/hardware,涉及fb.h和gralloc.h。

下面从gralloc的调用开始学习gralloc的代码。代码基于android4.4。

gralloc的调用是从FramebufferNativeWindow.cpp的构造函数开始的。FramebufferNativeWindow实现FrameBuffer的管理,它主要被SurfaceFlinger使用,也可以被OpenGL Native程序使用。在本质上,它在Framebuffer之上实现了一个ANativeWindow,目前它只管理两个buffers:front and back buffer。

如下所示(FramebufferNativeWindow.cpp):

FramebufferNativeWindow::FramebufferNativeWindow()
 : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
 {
 hw_module_t const* module;
 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
 int stride;
 int err;
 int i;
 err = framebuffer_open(module, &fbDev);
 ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));

err = gralloc_open(module, &grDev);
 ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));

// bail out if we can't initialize the modules
 if (!fbDev || !grDev)
 return;

mUpdateOnDemand = (fbDev->setUpdateRect != 0);

// initialize the buffer FIFO
 if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
 fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){ mNumBuffers = fbDev->numFramebuffers;
 } else {
 mNumBuffers = MIN_NUM_FRAME_BUFFERS;
 }
 mNumFreeBuffers = mNumBuffers;
 mBufferHead = mNumBuffers-1;

/*
 * This does not actually change the framebuffer format. It merely
 * fakes this format to surfaceflinger so that when it creates
 * framebuffer surfaces it will use this format. It's really a giant
 * HACK to allow interworking with buggy gralloc+GPU driver
 * implementations. You should *NEVER* need to set this for shipping
 * devices.
 */
 #ifdef FRAMEBUFFER_FORCE_FORMAT
 *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
 #endif

for (i = 0; i < mNumBuffers; i++) { buffers[i] = new NativeBuffer( fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
 }

for (i = 0; i < mNumBuffers; i++) { err = grDev->alloc(grDev,
 fbDev->width, fbDev->height, fbDev->format,
 GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);

ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
 i, fbDev->width, fbDev->height, strerror(-err));

if (err)
 {
 mNumBuffers = i;
 mNumFreeBuffers = i;
 mBufferHead = mNumBuffers-1;
 break;
 }
 }

const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
 const_cast<int&>(ANativeWindow::minSwapInterval) =
 fbDev->minSwapInterval;
 const_cast<int&>(ANativeWindow::maxSwapInterval) =
 fbDev->maxSwapInterval;
 } else {
 ALOGE("Couldn't get gralloc module");
 }

ANativeWindow::setSwapInterval = setSwapInterval;
 ANativeWindow::dequeueBuffer = dequeueBuffer;
 ANativeWindow::queueBuffer = queueBuffer;
 ANativeWindow::query = query;
 ANativeWindow::perform = perform;

ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
 ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
 ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
 }

这里会先根据gralloc的module ID来得到hw_module_t结构。hw_get_module->hw_get_module_by_class。在hw_get_module_by_class里面,首先根据平台配置找到gralloc动态库的位置,默认使用gralloc.default.so。 参见以下代码(hardware.c):

 for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, name, prop);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH1, name, prop);
            if (access(path, R_OK) == 0) break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH2, name);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, name);
            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. */
 status = load(class_id, path, module);
 }

找到gralloc库的路径后,会调用load函数,在load函数中使用dlopen打开找到的库,并根据HAL_MODULE_INFO_SYM_AS_STR(其值为HMI)获取到hw_module_t(即HAL_MODULE_INFO_SYM)结构体指针,以及把dlopen返回的handle保存在hw_module_t中。而hw_module_t HMI 结构是一个全局结构,在gralloc.cpp中已经得到初始化了。这也是为什么每一个HAL模块都要定义并初始化一个名字为HAL_MODULE_INFO_SYM的hw_module_t结构

struct private_module_t HAL_MODULE_INFO_SYM = {
    base: {
        common: {
            tag: HARDWARE_MODULE_TAG,
            version_major: 1,
            version_minor: 0,
            id: GRALLOC_HARDWARE_MODULE_ID,
            name: "Graphics Memory Allocator Module",
            author: "The Android Open Source Project",
            methods: &gralloc_module_methods
        },
        registerBuffer: gralloc_register_buffer,
        unregisterBuffer: gralloc_unregister_buffer,
        lock: gralloc_lock,
        unlock: gralloc_unlock,
    },
    framebuffer: 0,
    flags: 0,
    numBuffers: 0,
    bufferMask: 0,
    lock: PTHREAD_MUTEX_INITIALIZER,
    currentBuffer: 0,
};

回过头,回到FramebufferNativeWindow的构造函数出,接下来调用了err = framebuffer_open(module, &fbDev);framebuffer_open定义在fb.h中,是一个inline函数,其实最终调用了就是上面结构体中初始化的open函数,open函数指向gralloc_device_open,其实现为(gralloc.cpp):

int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
        gralloc_context_t *dev;
        dev = (gralloc_context_t*)malloc(sizeof(*dev));

        /* initialize our state here */
        memset(dev, 0, sizeof(*dev));

        /* initialize the procs */
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        dev->device.common.close = gralloc_close;

        dev->device.alloc   = gralloc_alloc;
        dev->device.free    = gralloc_free;

        *device = &dev->device.common;
        status = 0;
    } else {
        status = fb_device_open(module, name, device);
    }
    return status;
}

fb_device_open的定义如下所示(framebuffer.cpp):

int fb_device_open(hw_module_t const* module, const char* name,
        hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
        /* initialize our state here */
        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
        memset(dev, 0, sizeof(*dev));

        /* initialize the procs */
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        dev->device.common.close = fb_close;
        dev->device.setSwapInterval = fb_setSwapInterval;
        dev->device.post            = fb_post;
        dev->device.setUpdateRect = 0;

        private_module_t* m = (private_module_t*)module;
        status = mapFrameBuffer(m);
        if (status >= 0) {
            int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
            int format = (m->info.bits_per_pixel == 32)
                         ? HAL_PIXEL_FORMAT_RGBX_8888
                         : HAL_PIXEL_FORMAT_RGB_565;
            const_cast<uint32_t&>(dev->device.flags) = 0;
            const_cast<uint32_t&>(dev->device.width) = m->info.xres;
            const_cast<uint32_t&>(dev->device.height) = m->info.yres;
            const_cast<int&>(dev->device.stride) = stride;
            const_cast<int&>(dev->device.format) = format;
            const_cast<float&>(dev->device.xdpi) = m->xdpi;
            const_cast<float&>(dev->device.ydpi) = m->ydpi;
            const_cast<float&>(dev->device.fps) = m->fps;
            const_cast<int&>(dev->device.minSwapInterval) = 1;
            const_cast<int&>(dev->device.maxSwapInterval) = 1;
            *device = &dev->device.common;
        }
    }
    return status;
}

接下来的gralloc_open也是调用了gralloc_device_open,只不过name参数一个是GRALLOC_HARDWARE_GPU0,而另外一个是GRALLOC_HARDWARE_FB0,这两个函数分别得到alloc_device_t 和 framebuffer_device_t结构。到现在为止,gralloc模块的三个主要结构体,gralloc_module_t,alloc_device_t,framebuffer_device_t都已经获取到了。其中在fb_device_open函数中会获取实际的framebuffer设备(通常是/dev/graphics/fb0)的一些重要参数以及能力,比如分辨率信息以及支持多少个缓冲等,另外会把framebuffer映射到内测的地址保存到alloc_module_t中。android一般使用的都是双缓冲机制。具体代码如下(framebuffer.cpp),其中涉及到对private_module_t中一些成员的完善,涉及到gralloc_module_t以及private_handle_t等,其定义在gralloc_priv.h中,这两个结构中都保存了framebuffer的一些私有信息。

int mapFrameBufferLocked(struct private_module_t* module)
{
// already initialized...
if (module->framebuffer) {
return 0;
}

char const * const device_template[] = {
"/dev/graphics/fb%u",
"/dev/fb%u",
0 };

int fd = -1;
int i=0;
char name[64];

while ((fd==-1) && device_template[i]) {
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0);
i++;
}
if (fd < 0)
return -errno;

struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;

struct fb_var_screeninfo info;
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;

info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;

/*
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
*/
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
}

if (info.yres_virtual < info.yres * 2) {
// we need at least 2 for page-flipping
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
info.yres_virtual, info.yres*2);
}

if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;

uint64_t refreshQuotient =
(
uint64_t( info.upper_margin + info.lower_margin + info.yres )
* ( info.left_margin + info.right_margin + info.xres )
* info.pixclock
);

/* Beware, info.pixclock might be 0 under emulation, so avoid a
* division-by-0 here (SIGFPE on ARM) */
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;

if (refreshRate == 0) {
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}

if (int(info.width) <= 0 || int(info.height) <= 0) {
// the driver doesn't return that information
// default to 160 dpi
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
}

float xdpi = (info.xres * 25.4f) / info.width;
float ydpi = (info.yres * 25.4f) / info.height;
float fps = refreshRate / 1000.0f;

ALOGI( "using (fd=%d)\n"
"id = %s\n"
"xres = %d px\n"
"yres = %d px\n"
"xres_virtual = %d px\n"
"yres_virtual = %d px\n"
"bpp = %d\n"
"r = %2u:%u\n"
"g = %2u:%u\n"
"b = %2u:%u\n",
fd,
finfo.id,
info.xres,
info.yres,
info.xres_virtual,
info.yres_virtual,
info.bits_per_pixel,
info.red.offset, info.red.length,
info.green.offset, info.green.length,
info.blue.offset, info.blue.length
);

ALOGI( "width = %d mm (%f dpi)\n"
"height = %d mm (%f dpi)\n"
"refresh rate = %.2f Hz\n",
info.width, xdpi,
info.height, ydpi,
fps
);
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;

if (finfo.smem_len <= 0)
return -errno;
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;

/*
* map the framebuffer
*/

int err;
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);

module->numBuffers = info.yres_virtual / info.yres;
module->bufferMask = 0;

void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
return -errno;
}
module->framebuffer->base = intptr_t(vaddr);
memset(vaddr, 0, fbSize);
return 0;
}

由上面函数看出,mapFrameBufferLocked主要做了下面几件事情: 1. 打开framebuffer设备

2. 获取 fb_fix_screeninfo and fb_var_screeninfo

3. refill fb_var_screeninfo

4. 判断是否支持PAGE_FLIP

5. 计算刷新率

6. 打印gralloc信息

7. 填充private_module_t

8. mmap the framebuffer

由于篇幅限制,这里暂时说道这里,如要查看后续内容请查看原文:http://www.coderonline.net/android-gui%e7%b3%bb%e7%bb%9f%e5%ad%a6%e4%b9%a01%ef%bc%9agralloc.html

原文发布于微信公众号 - 程序员互动联盟(coder_online)

原文发表时间:2015-07-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

可能不知道的关于golang 的10件事情

匿名结构体 最常见的匿名用法,不用单独定义一个结构体类型 var config struct { APIKey s...

3145
来自专栏linux驱动个人学习

高通HAL层之Sensor HAL

高通的HAL层其实分为两种,一种是直接从kernel这边报数据上来的,由sensor HAL层来监听,另一种是走ADSP的模式,HAL层是通过qmi的形式进行监...

48912
来自专栏Seebug漏洞平台

Memcached 命令执行漏洞(CVE-2016-8704、CVE-2016-8705、CVE-2016-8706)简析

Author: p0wd3r, dawu (知道创宇404安全实验室) Date: 2016-11-01 0x00 漏洞概述 1.漏洞简介 Memcached...

2826
来自专栏猿湿Xoong

Android SystemUI(二):启动流程和初始化

1154
来自专栏微服务

C# 如何在Excel 动态生成PivotTable

Excel 中的透视表对于数据分析来说,非常的方便,而且很多业务人员对于Excel的操作也是非常熟悉的,因此用Excel作为分析数据的界面,不失为一种很好的选择...

26712
来自专栏Android中高级开发

Android开发之漫漫长途 IX——彻底掌握Binder

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

692
来自专栏linux驱动个人学习

高通spi 屏幕 -lk代码分析

2033
来自专栏为数不多的Android技巧

请不要滥用SharedPreference

SharedPreference是Android上一种非常易用的轻量级存储方式,由于其API及其友好,得到了很多很多开发者的青睐。但是,SharedPrefer...

734
来自专栏QQ音乐技术团队的专栏

记一次全民K歌的crash定位过程

全民K歌4.6版本发布后,出现了一个与RecyclerView相关的Bug,作此记录。

2113
来自专栏向治洪

android 网络通信框架volly

1. 什么是Volley 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection...

1775

扫描关注云+社区