该系列文章总纲链接:Android GUI系统之SurfaceFlinger 系列文章目录


本章关键点总结 & 说明:

本章节思维导图如上。主要讲述了gralloc模块 内存分配的概念,这里 主要关注 构造器 和 alloc方法。


Android帧缓冲区硬件抽象层模块Gralloc的实现原理如下:

  1. 分配一个匹配屏幕大小的图形缓冲区
  2. 将分配好的图形缓冲区注册(映射)到当前进程的地址空间来
  3. 将要绘制的画面的内容写入到已经注册好的图形缓冲区中去,并且渲染(拷贝)到系统帧缓冲区中去

为了实现以上三个操作,我们还需要:

  1. 加载Gralloc模块
  2. 打开Gralloc模块中的gralloc设备和fb设备

其中,gralloc设备负责分配图形缓冲区,Gralloc模块负责注册图形缓冲区,而fb设备负责渲染图形缓冲区。在GrafficBuffer中,内存是由Gralloc模块中分配的,基于上一节 FB的工作原理,这里主要分析Gralloc模块如何分配内存。

1 GraphicBufferAllocator分析

在GraficBuffer中,内存申请使用的类是GraphicBufferAllocator,头文件代码如下:

class GraphicBufferAllocator : public Singleton//单例模式类{public:    ...    //主要用来获取GraphicBufferAllocator对象    static inline GraphicBufferAllocator& get() { return getInstance(); }    //分配图像缓冲区    status_t alloc(uint32_t w, uint32_t h, PixelFormat format,                    int usage,buffer_handle_t* handle, int32_t* stride);    //释放图像缓冲区    status_t free(buffer_handle_t handle);    ...};

继续查看cpp文件中的构造方法,代码如下:

GraphicBufferAllocator::GraphicBufferAllocator(): mAllocDev(0){    hw_module_t const* module;    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);//打开Gralloc模块    if (err == 0) {        gralloc_open(module, &mAllocDev);    }}

 继续分析gralloc_open函数,代码如下:

static inline int gralloc_open(const struct hw_module_t* module, struct alloc_device_t** device) {    return module->methods->open(module, GRALLOC_HARDWARE_GPU0, (struct hw_device_t**)device);}

但是与FB相比,这一次传递的参数是GRALLOC_HARDWARE_GPU0,open函数在Gralloc模块中对应的函数是gralloc_device_open,代码如下:

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));//创建结构体dev        memset(dev, 0, sizeof(*dev));        //初始化结构体        dev->device.common.tag = HARDWARE_DEVICE_TAG;        dev->device.common.version = 0;        dev->device.common.module = const_cast(module);        dev->device.common.close = gralloc_close;        dev->device.alloc = gralloc_alloc;//分配内存的函数        dev->device.free = gralloc_free;//释放内存的函数        *device = &dev->device.common;        status = 0;    } else {        ... //走if分支,忽略此处FB操作    }    return status;}

说明:在调用完open函数后,GraphicBufferAllocator和Gralloc函数就建立了联系。

2 GraphicBufferAllocator的alloc方法分析

接下来从GraphicBufferAllocator的alloc方法开始分析,代码如下:

status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,        int usage, buffer_handle_t* handle, int32_t* stride){    ATRACE_CALL();    if (!w || !h)//如果制定的w或者h其中一个为0,则分配一个1*1大小的buffer        w = h = 1;    // we have a h/w allocator and h/w buffer is requested    status_t err;         err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);        if (err == NO_ERROR) {        Mutex::Autolock _l(sLock);        KeyedVector& list(sAllocList);        int bpp = bytesPerPixel(format);        if (bpp < 0) {            // probably a HAL custom format. in any case, we don't know what its pixel size is.            bpp = 0;        }        //创建并初始化结构体变量rec        alloc_rec_t rec;        rec.w = w;        rec.h = h;        rec.s = *stride;        rec.format = format;        rec.usage = usage;        rec.size = h * stride[0] * bpp;        list.add(*handle, rec);    }    return err;}

这里alloc调用了Gralloc函数中分配的函数指针,即Gralloc模块中的函数gralloc_alloc,代码如下:

static int gralloc_alloc(alloc_device_t* dev,int w, int h, int format,                          int usage,buffer_handle_t* pHandle, int* pStride){    if (!pHandle || !pStride)        return -EINVAL;    size_t size, stride;    int align = 4;    //对齐字节树    int bpp = 0;      //每个像素字节数    switch (format) { //通过图像格式来去判断每个像素的字节数。        case HAL_PIXEL_FORMAT_RGBA_8888:        case HAL_PIXEL_FORMAT_RGBX_8888:        case HAL_PIXEL_FORMAT_BGRA_8888:            bpp = 4;            break;        case HAL_PIXEL_FORMAT_RGB_888:            bpp = 3;            break;        case HAL_PIXEL_FORMAT_RGB_565:        case HAL_PIXEL_FORMAT_RAW_SENSOR:            bpp = 2;            break;        default:            return -EINVAL;    }    size_t bpr = (w*bpp + (align-1)) & ~(align-1);//计算每行字节数,因为要对其字节,要保证每行大小都是4的倍数    size = bpr * h;//总内存大小    stride = bpr / bpp;//每行的像素数(>=w*h),方法原理:每行的总字节数/每个像素的字节数==一行的像素    int err;    if (usage & GRALLOC_USAGE_HW_FB) {//分析usage标志中是否有GRALLOC_USAGE_HW_FB        err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);//从硬件缓冲区中分配内存,关键点1    } else {        err = gralloc_alloc_buffer(dev, size, usage, pHandle);//从内存中分配缓冲区,关键点2    }    if (err < 0) {        return err;    }    *pStride = stride;    return 0;}

2.1 gralloc_alloc_framebuffer分析

如果从硬件缓冲区中分配内存,会调用gralloc_alloc_framebuffer方法,代码如下:

static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle){    private_module_t* m = reinterpret_cast(dev->common.module);    pthread_mutex_lock(&m->lock);//加锁    int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);    pthread_mutex_unlock(&m->lock);//解锁    return err;}

继续分析gralloc_alloc_framebuffer_locked的实现,代码如下:

static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev,        size_t size, int usage, buffer_handle_t* pHandle){    private_module_t* m = reinterpret_cast(dev->common.module);    if (m->framebuffer == NULL) {//第一次调用会走这里        int err = mapFrameBufferLocked(m);//分配一大块内存        if (err < 0) {            return err;        }    }    const uint32_t bufferMask = m->bufferMask;    const uint32_t numBuffers = m->numBuffers;    const size_t bufferSize = m->finfo.line_length * m->info.yres;//一屏的大小    if (numBuffers == 1) {        //单缓冲的FrameBuffer,使用普通内存来分配        int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;        return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);    }    //对于多缓冲区,采取这样的方法    if (bufferMask >= ((1LU<framebuffer->base);    private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,            private_handle_t::PRIV_FLAGS_FRAMEBUFFER);    //因为FB缓冲区块数是有限的,因此需要遍历找到一个空闲块    for (uint32_t i=0 ; ibufferMask |= (1LU<base = vaddr;    hnd->offset = vaddr - intptr_t(m->framebuffer->base);    *pHandle = hnd;    return 0;}

2.2 gralloc_alloc_buffer分析

如果从内存缓冲区中分配内存,会调用gralloc_alloc_buffer方法,代码如下:

static int gralloc_alloc_buffer(alloc_device_t* dev,        size_t size, int /*usage*/, buffer_handle_t* pHandle){    int err = 0;    int fd = -1;    size = roundUpToPageSize(size);//进行页对齐        fd = ashmem_create_region("gralloc-buffer", size);//创建匿名共享内存,使用ashmem机制    if (fd < 0) {        ALOGE("couldn't create ashmem (%s)", strerror(-errno));        err = -errno;    }    if (err == 0) {        private_handle_t* hnd = new private_handle_t(fd, size, 0);        gralloc_module_t* module = reinterpret_cast(                dev->common.module);        err = mapBuffer(module, hnd);//使用mmap来创建内存,把共享内存的句柄和首地址关联到module        if (err == 0) {            *pHandle = hnd;//把创建的结构返回回去        }    }        return err;}

因为Android的图像缓冲区是需要进程间共享访问的,因此使用了匿名共享内存(使用共享内存前必须通过Binder来传递句柄,这里通过private_handle_t结构把共享内存的fd传递出去,这样缓冲区才可以使用)。

 

更多相关文章

  1. android 控件之ProgressBar实现双进度条(通常用于流媒体的缓冲区
  2. 360面试总结(Android)
  3. Android实现弱引用AsyncTask,将内存泄漏置之度外。
  4. 在这白驹过隙的时代,Android开发者如何先人一步?
  5. 使用 Memory Profiler查看Java堆和内存分配
  6. Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原
  7. Android系统堆内存限制浅析
  8. java/Android内存泄漏和内存溢出详解
  9. Android内存泄漏终极解决篇(下)

随机推荐

  1. 谈谈dom方式的用法
  2. 推荐10款连接类型实例教程
  3. XDocument函数定义与用法汇总
  4. 谈谈减少垃圾的现状、前景与机遇
  5. 浅谈选单连动实例
  6. 关于XML元素的10篇课程推荐
  7. 方式性能函数定义与用法汇总
  8. XML交互入门教程
  9. XmlTextWriter函数定义与用法汇总
  10. DTD详解的内容推荐