When the usage bit is not set to GRALLOC_USAGE_HW_FB or the system cannot support double buffering, we have to allocate the buffer from system memory using gralloc_alloc_buffer. Let's look at the implementation of 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);
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<gralloc_module_t*>(
dev->common.module);
err = mapBuffer(module, hnd);
if (err == 0) {
*pHandle = hnd;
}
}
ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
return err;
}
In gralloc_alloc_buffer, it rounds up the buffer size to the page size first. Then it creates an anonymous shared memory region using ashmem_create_region. It creates a new private_handle_t instance to represent this shared memory region.
This shared memory region is described as a file descriptor. To use it, we need to map it to the current process address space. This is done with the mapBuffer function:
int mapBuffer(gralloc_module_t const* module,
private_handle_t* hnd)
{
void* vaddr;
return gralloc_map(module, hnd, &vaddr);
}
mapBuffer calls to another function, gralloc_map, to do the memory mapping:
static int gralloc_map(gralloc_module_t const* /*module*/,
buffer_handle_t handle,
void** vaddr)
{
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
size_t size = hnd->size;
void* mappedAddress = mmap(0, size,
PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
if (mappedAddress == MAP_FAILED) {
ALOGE("Could not mmap %s", strerror(errno));
return -errno;
}
hnd->base = uintptr_t(mappedAddress) + hnd->offset;
//ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
// hnd->fd, hnd->offset, hnd->size, mappedAddress);
}
*vaddr = (void*)hnd->base;
return 0;
}
In grallo_map, if the file descriptor in private_handle_t is a framebuffer device, we don't have to do the mapping again, since the framebuffer is initialized and mapped to the SurfaceFlinger address space in fb_device_open, as we analyzed before.
If it is a shared memory region, it needs to be mapped to the current process address space using the mmap system function.