Android Display 之 HAL Gralloc

1.前言

之前分析过Android HAL层关于hal库是如何加载的一个小框架,源于笔者需要分析Android display框架,Android display HAL层最重要的就是Gralloc和Framebuffer。在《深入理解Android内核设计思想》一书中,有提到:Android终端显示设备的”化身“–Gralloc与Framebuffer。
在Android系统中,Framebuffer提供的设备文件节点是/dev/graphics/fb*。
Framebuffer容易理解,那Gralloc是个什么东西。
Android的各个子系统通常不会直接使用内核驱动,而是由HAL层来间接引用底层架构。
显示系统也是同样如此–它借助HAL层来操作帧缓冲区,而完成这一中介任务的就是Gralloc。

2.正文

gralloc hal库源码位于hardware/libhardware/modules/gralloc/
主要包括:Android.mk framebuffer.cpp gralloc.cpp gralloc_priv.h gr.h mapper.cpp
加粗的则是最重要的三个实现文件
先看gralloc的加载,可以参照之前的blog。
通过之前分析到的hw_get_module即可加载对应的hal库,这里即是gralloc库。
可以看到在gralloc.h中hardware/libhardware/include/hardware/gralloc.h

/**
 * The id of this module
 */
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"

关于GRALLOC_HARDWARE_MODULE_ID根据注释大致可以判断出来就是module ID,也就是struct hw_module_t里面必须的ID。现在来验证下:
有一点不需质疑,该ID肯定在gralloc.c中使用

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,
};

没错,确实在C文件中找到了,但初始化是在struct private_module_t中base 的common里。有趣的来了,要想知道为啥会是这个结果,先从源头找起,private_module_t是个什么东西,看名称大致是私有的module?
该结构图定义在gralloc_priv.h中

struct private_module_t {
    gralloc_module_t base;

    private_handle_t* framebuffer;
    uint32_t flags;
    uint32_t numBuffers;
    uint32_t bufferMask;
    pthread_mutex_t lock;
    buffer_handle_t currentBuffer;
    int pmem_master;
    void* pmem_master_base;

    struct fb_var_screeninfo info;
    struct fb_fix_screeninfo finfo;
    float xdpi;
    float ydpi;
    float fps;
};

可以看到base是gralloc_module_t类型的。gralloc_module_t在哪定义的?这个应该很简单,大致是在gralloc.h

/**
 * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
typedef struct gralloc_module_t {
    struct hw_module_t common;			//hw_module_t 类型	
    
    /*
     * (*registerBuffer)() must be called before a buffer_handle_t that has not
     * been created with (*alloc_device_t::alloc)() can be used.
     * 
     * This is intended to be used with buffer_handle_t's that have been
     * received in this process through IPC.
     * 
     * This function checks that the handle is indeed a valid one and prepares
     * it for use with (*lock)() and (*unlock)().
     * 
     * It is not necessary to call (*registerBuffer)() on a handle created 
     * with (*alloc_device_t::alloc)().
     * 
     * returns an error if this buffer_handle_t is not valid.
     */
    int (*registerBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);

    /*
     * (*unregisterBuffer)() is called once this handle is no longer needed in
     * this process. After this call, it is an error to call (*lock)(),
     * (*unlock)(), or (*registerBuffer)().
     * 
     * This function doesn't close or free the handle itself; this is done
     * by other means, usually through libcutils's native_handle_close() and
     * native_handle_free(). 
     * 
     * It is an error to call (*unregisterBuffer)() on a buffer that wasn't
     * explicitly registered first.
     */
    int (*unregisterBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);
    
    /*
     * The (*lock)() method is called before a buffer is accessed for the 
     * specified usage. This call may block, for instance if the h/w needs
     * to finish rendering or if CPU caches need to be synchronized.
     * 
     * The caller promises to modify only pixels in the area specified 
     * by (l,t,w,h).
     * 
     * The content of the buffer outside of the specified area is NOT modified
     * by this call.
     *
     * If usage specifies GRALLOC_USAGE_SW_*, vaddr is filled with the address
     * of the buffer in virtual memory.
     *
     * Note calling (*lock)() on HAL_PIXEL_FORMAT_YCbCr_*_888 buffers will fail
     * and return -EINVAL.  These buffers must be locked with (*lock_ycbcr)()
     * instead.
     *
     * THREADING CONSIDERATIONS:
     *
     * It is legal for several different threads to lock a buffer from 
     * read access, none of the threads are blocked.
     * 
     * However, locking a buffer simultaneously for write or read/write is
     * undefined, but:
     * - shall not result in termination of the process
     * - shall not block the caller
     * It is acceptable to return an error or to leave the buffer's content
     * into an indeterminate state.
     *
     * If the buffer was created with a usage mask incompatible with the
     * requested usage flags here, -EINVAL is returned. 
     * 
     */
    
    int (*lock)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            void** vaddr);

    
    /*
     * The (*unlock)() method must be called after all changes to the buffer
     * are completed.
     */
    
    int (*unlock)(struct gralloc_module_t const* module,
            buffer_handle_t handle);


    /* reserved for future use */
    int (*perform)(struct gralloc_module_t const* module,
            int operation, ... );

    /*
     * The (*lock_ycbcr)() method is like the (*lock)() method, with the
     * difference that it fills a struct ycbcr with a description of the buffer
     * layout, and zeroes out the reserved fields.
     *
     * If the buffer format is not compatible with a flexible YUV format (e.g.
     * the buffer layout cannot be represented with the ycbcr struct), it
     * will return -EINVAL.
     *
     * This method must work on buffers with HAL_PIXEL_FORMAT_YCbCr_*_888
     * if supported by the device, as well as with any other format that is
     * requested by the multimedia codecs when they are configured with a
     * flexible-YUV-compatible color-format with android native buffers.
     *
     * Note that this method may also be called on buffers of other formats,
     * including non-YUV formats.
     *
     * Added in GRALLOC_MODULE_API_VERSION_0_2.
     */

    int (*lock_ycbcr)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            struct android_ycbcr *ycbcr);

    /*
     * The (*lockAsync)() method is like the (*lock)() method except
     * that the buffer's sync fence object is passed into the lock
     * call instead of requiring the caller to wait for completion.
     *
     * The gralloc implementation takes ownership of the fenceFd and
     * is responsible for closing it when no longer needed.
     *
     * Added in GRALLOC_MODULE_API_VERSION_0_3.
     */
    int (*lockAsync)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            void** vaddr, int fenceFd);

    /*
     * The (*unlockAsync)() method is like the (*unlock)() method
     * except that a buffer sync fence object is returned from the
     * lock call, representing the completion of any pending work
     * performed by the gralloc implementation.
     *
     * The caller takes ownership of the fenceFd and is responsible
     * for closing it when no longer needed.
     *
     * Added in GRALLOC_MODULE_API_VERSION_0_3.
     */
    int (*unlockAsync)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int* fenceFd);

    /*
     * The (*lockAsync_ycbcr)() method is like the (*lock_ycbcr)()
     * method except that the buffer's sync fence object is passed
     * into the lock call instead of requiring the caller to wait for
     * completion.
     *
     * The gralloc implementation takes ownership of the fenceFd and
     * is responsible for closing it when no longer needed.
     *
     * Added in GRALLOC_MODULE_API_VERSION_0_3.
     */
    int (*lockAsync_ycbcr)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            struct android_ycbcr *ycbcr, int fenceFd);

    /* reserved for future use */
    void* reserved_proc[3];
} gralloc_module_t;

gralloc_module_t看着很长,其实嘛,被注释占了太多空间了,这里我们先仅仅关注common这个变量。它就是struct hw_module_t类型的。那就没错了,我们猜想是对的。
在具体加载hal库的时候,HAL作了这样的事。
hw_module_t 被 gralloc_module_t 继承,然后 gralloc_module_t 被 private_module_t 继承。
这应该是为了区分不同厂商对应的hal库所采取的对应措施。
这样一来,在gralloc库编译出来后,会通过hardware中的hw_get_module方式去加载(通过匹配ID值的方式。上面跟踪的ID就是这个)。
分析完gralloc.default.so库的具体加载。既然知道Android系统中是通过这个库来操作fb,那么来看看它提供的一些接口

Gralloc提供的接口

Gralloc.c本身提供的接口应该就一个了。可以看到之前hardware中struct hw_module_methods_t必须注册的一个函数–open
在这里即是gralloc_device_open

static struct hw_module_methods_t gralloc_module_methods = {
        .open = 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设备
    	...
    } else {
        status = fb_device_open(module, name, device);//打开fb设备
    }
    return status;
}

可以看到这里即是gralloc会根据设备名判断是打开什么(gralloc设备还是fb设备)
另外可以看到,上面提到的gralloc_module_t里面除了继承了struct hw_module_t的变量common,同时还有一些接口函数。
registerBuffer,unregisterBuffer,loc和unlock。它们分别在gralloc.c中以gralloc_register_buffer,gralloc_unregister_buffer,gralloc_lock和gralloc_unlock注册实现。根据函数名可大致得到这些应该是针对buffer做一些操作的。
那趁热打铁,先看看gralloc模块对gralloc设备的打开过程:

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; //分配alloc_device_t (用gralloc_context_t 包装起来) 空间,这是一个“壳”
        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(module);
        dev->device.common.close = gralloc_close;

        dev->device.alloc   = gralloc_alloc; 
        dev->device.free    = gralloc_free;//从提供的接口来看,gralloc主要负责图形缓冲区“分配和释放”的操作

        *device = &dev->device.common;
        status = 0;
    } else {
       ......
    }
    return status;
}
struct gralloc_context_t {
    alloc_device_t  device;
    /* our private data here */
};

接下来看看fb设备的打开流程,相对gralloc设备的打开流程要稍许复杂:
谈到fb设备的打开流程,就要联系到framebuffer.cpp了。
既然在gralloc模块中是通过fb_device_open进行操作。

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)); //同上面gralloc设备打开类似,这里fb_context_t是包装了framebuffer_device_t结构体,framebuffer_device_t是framebuffer中内部类,声明在fb.h中,后面单独分析
        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(module);
        dev->device.common.close = fb_close;	//fb_close,fb_setSwapInterval,fb_post这几个接口是fb设备的核心
        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)
                         ? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : HAL_PIXEL_FORMAT_RGBX_8888)
                         : HAL_PIXEL_FORMAT_RGB_565;
            const_cast(dev->device.flags) = 0;
            const_cast(dev->device.width) = m->info.xres;
            const_cast(dev->device.height) = m->info.yres;
            const_cast(dev->device.stride) = stride;
            const_cast(dev->device.format) = format;
            const_cast(dev->device.xdpi) = m->xdpi;
            const_cast(dev->device.ydpi) = m->ydpi;
            const_cast(dev->device.fps) = m->fps;
            const_cast(dev->device.minSwapInterval) = 1;
            const_cast(dev->device.maxSwapInterval) = 1;
            *device = &dev->device.common; //“壳”与“核心”的关系
        }
    }
    return status;
}

struct fb_context_t {
    framebuffer_device_t  device;
};

一个标准的fb设备通常要提供一些“标准”的接口,这些接口声明在fb.h中framebuffer_device_t结构体中。

typedef struct framebuffer_device_t {
    /**
     * Common methods of the framebuffer device.  This *must* be the first member of
     * framebuffer_device_t as users of this structure will cast a hw_device_t to
     * framebuffer_device_t pointer in contexts where it's known the hw_device_t references a
     * framebuffer_device_t.
     */
    struct hw_device_t common;

    /* flags describing some attributes of the framebuffer */
    const uint32_t  flags;

    /* dimensions of the framebuffer in pixels */
    const uint32_t  width;
    const uint32_t  height;

    /* frambuffer stride in pixels */
    const int       stride;

    /* framebuffer pixel format */
    const int       format;

    /* resolution of the framebuffer's display panel in pixel per inch*/
    const float     xdpi;
    const float     ydpi;

    /* framebuffer's display panel refresh rate in frames per second */
    const float     fps;

    /* min swap interval supported by this framebuffer */
    const int       minSwapInterval;

    /* max swap interval supported by this framebuffer */
    const int       maxSwapInterval;

    /* Number of framebuffers supported*/
    const int       numFramebuffers;

    int reserved[7];

    /*
     * requests a specific swap-interval (same definition than EGL)
     *
     * Returns 0 on success or -errno on error.
     */
    int (*setSwapInterval)(struct framebuffer_device_t* window,
            int interval);

    /*
     * This hook is OPTIONAL.
     *
     * It is non NULL If the framebuffer driver supports "update-on-demand"
     * and the given rectangle is the area of the screen that gets
     * updated during (*post)().
     *
     * This is useful on devices that are able to DMA only a portion of
     * the screen to the display panel, upon demand -- as opposed to
     * constantly refreshing the panel 60 times per second, for instance.
     *
     * Only the area defined by this rectangle is guaranteed to be valid, that
     * is, the driver is not allowed to post anything outside of this
     * rectangle.
     *
     * The rectangle evaluated during (*post)() and specifies which area
     * of the buffer passed in (*post)() shall to be posted.
     *
     * return -EINVAL if width or height <=0, or if left or top < 0
     */
    int (*setUpdateRect)(struct framebuffer_device_t* window,
            int left, int top, int width, int height);

    /*
     * Post  to the display (display it on the screen)
     * The buffer must have been allocated with the
     *   GRALLOC_USAGE_HW_FB usage flag.
     * buffer must be the same width and height as the display and must NOT
     * be locked.
     *
     * The buffer is shown during the next VSYNC.
     *
     * If the same buffer is posted again (possibly after some other buffer),
     * post() will block until the the first post is completed.
     *
     * Internally, post() is expected to lock the buffer so that a
     * subsequent call to gralloc_module_t::(*lock)() with USAGE_RENDER or
     * USAGE_*_WRITE will block until it is safe; that is typically once this
     * buffer is shown and another buffer has been posted.
     *
     * Returns 0 on success or -errno on error.
     */
    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);


    /*
     * The (*compositionComplete)() method must be called after the
     * compositor has finished issuing GL commands for client buffers.
     */

    int (*compositionComplete)(struct framebuffer_device_t* dev);

    /*
     * This hook is OPTIONAL.
     *
     * If non NULL it will be caused by SurfaceFlinger on dumpsys
     */
    void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);

    /*
     * (*enableScreen)() is used to either blank (enable=0) or
     * unblank (enable=1) the screen this framebuffer is attached to.
     *
     * Returns 0 on success or -errno on error.
     */
    int (*enableScreen)(struct framebuffer_device_t* dev, int enable);

    void* reserved_proc[6];

} framebuffer_device_t;

这里可以看到,该结构体中包含了(继承了)结构体struct hw_device_t。这个是之前在hardware.h中提到的的三个重要结构体之一。该结构体包含了设备的一些信息。如fb0这里就包含了width,height等信息,同时还提供了上面提到的一些“标准”的接口。

    /*
     * requests a specific swap-interval (same definition than EGL)
		请求特定的交换间隔(与EGL相同的定义)
     * Returns 0 on success or -errno on error.
     */
    int (*setSwapInterval)(struct framebuffer_device_t* window,
            int interval); //设置两个缓冲区交换的时间间隔
    /*
	这个钩子是可选的。
  	它是非NULL如果帧缓冲驱动程序支持“按需更新”,则给定的矩形是在(* post)()期间更新的屏幕区域。
  	这对于能够根据需要仅将屏幕的一部分DMA显示到显示面板的设备非常有用 - 例如,与每秒60次不断刷新面板相反。仅此矩形定义的区域保证 是有效的,也就是说,不允许司机在这个矩形之外张贴任何东西。
 	 在(* post)()期间评估的矩形,并指定要传递的缓冲区的哪个区域(* post)()。
     *
     * return -EINVAL if width or height <=0, or if left or top < 0
     */
    int (*setUpdateRect)(struct framebuffer_device_t* window,
            int left, int top, int width, int height); //设置刷新区域,需要framebuffer驱动支持“update-on-demand”,也就是说,在这个区域外的数据很可能被认为无效
    /*
	将发布到显示屏上(在屏幕上显示)必须使用GRALLOC_USAGE_HW_FB使用标志分配缓冲区。 缓冲区必须与显示屏的宽度和高度相同,不得锁定。
	缓冲区在下一个VSYNC期间显示。
	如果再次发布相同的缓冲区(可能在一些其他缓冲区之后),post()将阻塞直到第一个帖子完成。在内部,post()应该锁定缓冲区,以便后续调用gralloc_module_t ::(* 锁定)()USAGE_RENDER或USAGE _ * _ WRITE将阻塞,直到它安全为止; 通常一旦显示此缓冲区并且已发布另一个缓冲区。
     * Returns 0 on success or -errno on error.
     */
    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer); //将buffer数据post到显示屏上。要求buffer必须与屏幕尺寸一致,并且没有被locked。这样buffer内容将在下一次VSYNC中被显示出来。

这里再来分析下framebuffer_device_t中比较重要的成员变量。

变量 描述
const uint32_t flags; 标志位,指示framebuffer的属性配置
const uint32_t width;const uint32_t height; framebuffer的宽和高,以像素为单位
const uint32_t flags; 标志位,指示framebuffer的属性配置
const int format; framebuffer的像素格式,比如:HAL_PIXEL_FORMAT_RGBA_8888HAL_PIXEL_FROMAT_RGBX_8888 HAL_PIXEL_FORMAT_RGB_888 HAL_PIXEL_RGB_565等
const float xdpi;const float ydpi; x和y轴的密度(dot per inch)
const float fps; 屏幕的每秒刷新率。假如无法从设备获取这个值,Android系统会默认设置为60Hz
const int minSwapInterval;const int maxSwapInterval; 该framebuffer支持的最小和最大缓冲交换时间

刚刚在分析fb设备打开流程中有重点注释到一个函数mapFrameBuffer();这个函数即是Android系统如何打开Kernel层的fb设备以及如何对fb设备进行配置的。

Android系统如何打开kernel层的fb设备以及如何对fb进行配置。

源码前熟悉:
在应用程序中,操作/dev/fb的一般步骤如下:
1.打开/dev/fb设备文件。
2.用 ioctrl 操作取得当前显示屏幕的参数,如屏幕分辨率,每个像素点的比特数。根据屏幕参数可计算屏幕缓冲区的大小。
3.将屏幕缓冲区映射到用户空间(mmap)。
4.映射后就可以直接读写屏幕缓冲区,进行绘图和图片显示了。

static int mapFrameBuffer(struct private_module_t* module)
{
    pthread_mutex_lock(&module->lock); //线程上锁
    int err = mapFrameBufferLocked(module);  //实际调用了这个
    pthread_mutex_unlock(&module->lock);//线程解锁
    return err;
}
int mapFrameBufferLocked(struct private_module_t* module)
{
    // already initialized...
    if (module->framebuffer) { //确保module buffer是否存在
        return 0;
    }
        
    char const * const device_template[] = { //kernel fb设备的路径
            "/dev/graphics/fb%u",
            "/dev/fb%u",
            0 };

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

    while ((fd==-1) && device_template[i]) { //循环打开device_template,即kernel中fb设备可能存在的路径
        snprintf(name, 64, device_template[i], 0);
        fd = open(name, O_RDWR, 0); //读写方式打开
        i++;
    }
    if (fd < 0)	//可能存在的路径,没有一个能打开的,直接返回
        return -errno;

	//FBIOGET_VSCREENINFO:获取framebuffer可变信息参数,比如屏幕分辨率,像素格式等。
    //FBIOPUT_VSCREENINFO:设置framebuffer的分辨率,像素格式
    //FBIOGET_FSCREENINFO:获取framebuffer固定信息参数,包括显存起始物理地址、显存大小和行间距等。
    struct fb_fix_screeninfo finfo;
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)		//获取fb_var_screeninfo结构的信息,在linux/include/linux/fb.h定义。 存储在 finfo
        return -errno;

    struct fb_var_screeninfo info;
    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)		//获取fb_fix_screeninfon结构的信息。在linux/include/linux/fb.h定义。 存储在 info
        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)  请求NUM_BUFFERS个屏幕(页面翻转至少2个)
     */
    info.yres_virtual = info.yres * NUM_BUFFERS;


    uint32_t flags = PAGE_FLIP;
#if USE_PAN_DISPLAY	//USE_PAN_DISPLAY为0
    if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {
        ALOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
#else
    if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { //走这  设置framebuffer的分辨率,像素格式
        ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
#endif
        info.yres_virtual = info.yres;
        flags &= ~PAGE_FLIP;
    }

    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) //获取fb_fix_screeninfon结构的信息。
        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) */
    // 请注意,info.pixclock在仿真时可能为0,因此请避免在此处进行0分频(ARM上的SIGFPE)
    int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;

    if (refreshRate == 0) {  //默认刷新率为60Hz
        // 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)	//获取framebuffer固定信息参数,包括显存起始物理地址、显存大小和行间距等
        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;
}

注意:mapFrameBuffer/mapFrameBufferLocked 除了打开fb设备和配置fb设备。还有个重要任务就是为fb设备做内存映射。
从mapFrameBufferLocked中截选

    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);

由上述代码可知,映射地址保存在 module->framebuffer->base。变量module对应的是前面hw_get_module(GRALLOC_HARDWARE_MODULE_ID,&module)得到的hw_module_t(被强制类型转换为private_module_t)
即:module->framebuffer->base ==》 private_module_t->private_handle_t*->uint64_t base attribute((aligned(8)));

总结

关于Android系统中HAL层是如何打开配置操作fb,总结下大概作了这些事。
编译生成gralloc.default.so.上层通过该库调用module必须注册的open方法进行打开操作,打开操作根据设备名判断打开gralloc(gpu0)设备还是fb设备。
gralloc(gpu0)设备中管理着图形缓冲区的分配和释放。
fb设备中对fb设备有着post、setSwapInterval、setUpdateRect等操作。

参考

Linux的帧缓冲设备
framebuffer缓冲帧/dev/fb0学习
FBIOPAN_DISPLAY和MSMFB_DISPLAY_COMMIT刷屏流程
android display框架与数据流

你可能感兴趣的:(android)