Android中图像缓冲区的分配是由单例类GraphicBufferAllocator实现的。
[frameworks/native/include/ui/GraphicBufferAllocator.h] #ifndef ANDROID_BUFFER_ALLOCATOR_H #define ANDROID_BUFFER_ALLOCATOR_H #include <stdint.h> #include <cutils/native_handle.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/threads.h> #include <utils/Singleton.h> #include <ui/PixelFormat.h> #include <hardware/gralloc.h> namespace android { class String8; class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator> { public: enum { USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER, //0x00000000 USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY, //0x00000002 USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN, //0x00000003 USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK, //0x0000000F USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER, //0x00000000 USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY, //0x00000020 USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN, //0x00000030 USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK, //0x000000F0 USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK, USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE, //0x00000100 USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER, //0x0000020 USAGE_HW_2D = GRALLOC_USAGE_HW_2D, //0x00000400 USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK //0x00071F00 }; //获取单例实例。 static inline GraphicBufferAllocator& get() { return getInstance(); } status_t alloc(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, buffer_handle_t* handle, uint32_t* stride); status_t free(buffer_handle_t handle); void dump(String8& res) const; static void dumpToSystemLog(); private: struct alloc_rec_t { uint32_t width; uint32_t height; uint32_t stride; PixelFormat format; uint32_t usage; size_t size; }; //静态变量 static Mutex sLock; static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList; //父类声明为友元类,原因是?不清楚。 friend class Singleton<GraphicBufferAllocator>; //构造和析构函数均为private。 GraphicBufferAllocator(); ~GraphicBufferAllocator(); alloc_device_t *mAllocDev; }; }; // namespace android #endif // ANDROID_BUFFER_ALLOCATOR_H具体的实现思路是: 1. 在构造函数中打开gralloc模块,在析构函数中关闭打开的gralloc文件描述符;
GraphicBufferAllocator::GraphicBufferAllocator() : mAllocDev(0) { hw_module_t const* module; /* GRALLOC_HARDWARE_MODULE_ID值为字符串"gralloc",在hardware/gralloc.h中定义。 */ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err == 0) { /* gralloc_open与gralloc_close的实现位于hardware/gralloc.h中。*/ gralloc_open(module, &mAllocDev); } } GraphicBufferAllocator::~GraphicBufferAllocator() { gralloc_close(mAllocDev); } alloc()函数执行成功后,会插入到GraphicBufferAllocator类的静态变量sAllocList中,每次操作需要加锁sLock。在free时,会删除Key为handle的Key-Value对。 [frameworks/native/libs/ui/GraphicBufferAllocator.cpp] Mutex GraphicBufferAllocator::sLock; KeyedVector<buffer_handle_t, GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList; status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, buffer_handle_t* handle, uint32_t* stride) { ATRACE_CALL(); // make sure to not allocate a N x 0 or 0 x N buffer, since this is // allowed from an API stand-point, allocate a 1x1 buffer instead. if (!width || !height) width = height = 1; // we have a h/w allocator and h/w buffer is requested status_t err; // Filter out any usage bits that should not be passed to the gralloc module usage &= GRALLOC_USAGE_ALLOC_MASK; int outStride = 0; err = mAllocDev->alloc(mAllocDev, static_cast<int>(width), static_cast<int>(height), format, static_cast<int>(usage), handle, &outStride); *stride = static_cast<uint32_t>(outStride); ALOGW_IF(err, "alloc(%u, %u, %d, x, ...) failed %d (%s)", width, height, format, usage, err, strerror(-err)); if (err == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); uint32_t bpp = bytesPerPixel(format); alloc_rec_t rec; rec.width = width; rec.height = height; rec.stride = *stride; rec.format = format; rec.usage = usage; rec.size = static_cast<size_t>(height * (*stride) * bpp); list.add(*handle, rec); } return err; } status_t GraphicBufferAllocator::free(buffer_handle_t handle) { ATRACE_CALL(); status_t err; err = mAllocDev->free(mAllocDev, handle); ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err)); if (err == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); list.removeItem(handle); } return err; }