Gralloc模块分析

Linux内核提供了统一的framebuffer显示驱动。Framebuffer是内核系统提供的图形硬件的抽象描述,称为buffer是因为它也占用了系统存储空间的一部分,是一块包含屏幕显示信息的缓冲区。Framebuffer借助于Linux文件系统向上层应用提供了统一而高效的操作接口,让用户空间运行的程序比较容易地适配多种显示设备。

Android系统中,每个显示屏被抽象为一个帧缓冲区,注册到FrameBuffer模块中,并在/dev/graphics目录下创建对应的fbX设备,framebuffer提供的设备节点为/dev/graphics/fb或者/dev/fb,Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。用户空间的应用程序在使用帧缓冲区之间,首先要加载Gralloc模块,并且获得一个gralloc设备和一个fb设备。有了gralloc设备之后,用户空间中的应用程序就可以申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间来,以便可以向里面写入要绘制的画面的内容。

Android 硬件抽象库的加载简介

Android系统,为了隐藏各厂家自身特定硬件驱动实现细节,在用户空间定义了一套硬件抽象层,各厂商在Android的硬件抽象层实现特定硬件的操作细节,编译成动态库,以库的形式提供给用户使用。

hardware/libhardware/include/hardware/hardware.h 头文件中定义一个代表模块的结构体 (hw_module_t),其中包含模块的版本、名称和作者等元数据。Android系统 会根据这些元数据来找到并正确加载 HAL 模块。

typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;
    uint16_t module_api_version;
    uint16_t hal_api_version;
    const char *id;
    const char *name;
    const char *author;
    struct hw_module_methods_t* methods;
    void* dso;
#ifdef __LP64__
    uint64_t reserved[32-7];
#else
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
#endif
} hw_module_t;

hw_module_t 结构体还包含指向另一个结构体 hw_module_methods_t 的指针,后面这个结构体包含指向相应模块的 open 函数的指针。此 open 函数用于与相关硬件(此 HAL 是其抽象形式)建立通信。每个硬件专用 HAL 通常都会使用该特定硬件的附加信息来扩展通用的 hw_module_t 结构体。例如,在相机 HAL 中,camera_module_t 结构体包含一个 hw_module_t 结构体以及相机专用的其他函数指针:

typedef struct camera_module {
    hw_module_t common;
    int (*get_number_of_cameras)(void);
    int (*get_camera_info)(int camera_id, struct camera_info *info);
} camera_module_t;

实现 HAL 并创建模块结构体时,您必须将其命名为 HAL_MODULE_INFO_SYM,以下是 Nexus 9 音频 HAL 的示例:

struct audio_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
        .hal_api_version = HARDWARE_HAL_API_VERSION,
        .id = AUDIO_HARDWARE_MODULE_ID,
        .name = "NVIDIA Tegra Audio HAL",
        .author = "The Android Open Source Project",
        .methods = &hal_module_methods,
    },
};

HAL 设备

设备是产品硬件的抽象表示。例如,一个音频模块可能包含主音频设备、USB 音频设备或蓝牙 A2DP 音频设备。

设备由 hw_device_t 结构体表示。与模块类似,每类设备都定义了一个通用 hw_device_t 的详细版本,其中包含指向特定硬件功能的函数指针。例如,audio_hw_device_t 结构体类型会包含指向音频设备操作的函数指针:

struct audio_hw_device {
    struct hw_device_t common;

    /**
     * used by audio flinger to enumerate what devices are supported by
     * each audio_hw_device implementation.
     *
     * Return value is a bitmask of 1 or more values of audio_devices_t
     */
    uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);
  ...
};
typedef struct audio_hw_device audio_hw_device_t;

如何加载硬件抽象层的动态库?

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}

参数为模块的ID,最终会返回一个hw_module_t的结构体保存在参数module中。
每个硬件抽象层模块都必须定义HAL_MODULE_INFO_SYM符号,并且有自己唯一的ID。

hw_get_module会遍历规定的几个目录来查找名称对应的动态库,找到库的路径后,会调用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 结构是一个全局结构。

每个硬件抽象层必须有自己的ID以及HAL_MODULE_INFO_SYM符号,Gralloc也不例外

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

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

hw_get_module硬件加载方法根据gralloc的ID, 查找到gralloc模块定义的HAL_MODULE_INFO_SYM并返回给hw_module_t结构,但是HAL_MODULE_INFO_SYM是private_module_t结构类型,如何赋值呢?

Gralloc模块数据结构分析

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; //一个互斥锁,用来保护结构体private_module_t的并行访问
    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; //用来描述显示屏的刷新频率
};

private_module_t负责管理显示驱动framebuffer相关的信息,包括framebuffer的fd, 有多少个缓存,系统帧缓冲区使用情况,动态可变的信息,固定属性的信息,显示屏的宽高,刷新率等信息。
private_module_t 第一个变量是gralloc_module_t结构。

typedef struct gralloc_module_t {
    struct hw_module_t common;
   //映射一块图形缓冲区到一个进程的地址空间去
    int (*registerBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);
   //取消映射到一个进程的地址空间去的图形缓冲区
    int (*unregisterBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);
    //锁定一个指定的图形缓冲区
    int (*lock)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            void** vaddr);
   //解锁一个指定的图形缓冲区
    int (*unlock)(struct gralloc_module_t const* module,
            buffer_handle_t handle);
    int (*perform)(struct gralloc_module_t const* module,
            int operation, ... );
    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);

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

    int (*unlockAsync)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int* fenceFd);

    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 负责管理gralloc模块相关的操作,其第一个是属性是硬件抽象层规定的hw_module_t结构,其他都是关于gralloc模块图像buffer处理的相关操作方法。

hw_module_t结构如下:

/**
 * 任何一个硬件模块都必须有一个名称为 HAL_MODULE_INFO_SYM的数据结构
 * 并且这个数据结构必须以hw_module_t为第一个元素,其后再跟随这个模块特有的信息
 */
typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag; //标签
    uint16_t module_api_version; //模块主设备号
    uint16_t hal_api_version; //模块从设备号
    const char *id; //模块ID
    const char *name; //名称
    const char *author; //作者
    struct hw_module_methods_t* methods; //操作模块的方法
    void* dso; //模块首地址

    uint64_t reserved[32-7]; //保留信息

} hw_module_t;

typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;

硬件抽象层hw_module_t结构描述了硬件抽象层库相关的信息。如版本号,id, 名称,相关的操作方法等。
其中还定义了模块的打开模块的操作方法open.

根据以上的三个结构我们可以画出结构图如下:


gralloc数据结构

回到上面问题,为什么private_module_t可以赋值给hw_module_t呢?这样看就很简单了,private_module_t的第一个变量就是gralloc_module_t, 而gralloc_module_t的数据第一个元素就是hw_module_t。private_module_t的首地址和hw_module_t的首地址是一样的,所以可以直接赋值过去。

除了hw_module_t的数据结构外,gralloc模块还定义了两种设备相关的数据结构:

1: framebuffer_device_t 用来描述系统帧缓冲区的信息

typedef struct framebuffer_device_t {
    struct hw_device_t common;
    const uint32_t  flags;//用来记录系统帧缓冲区的标志
    const uint32_t  width;//用来描述设备显示屏的宽度
    const uint32_t  height;//用来描述设备显示屏的高度
    const int       stride;//用来描述设备显示屏的一行有多少个像素点
    const int       format;//用来描述系统帧缓冲区的像素格式
    const float     xdpi;//用来描述设备显示屏在宽度上的密度
    const float     ydpi;//用来描述设备显示屏在高度上的密度
    const float     fps;//用来描述设备显示屏的刷新频率
    const int       minSwapInterval;//用来描述帧缓冲区交换前后两个图形缓冲区的最小时间间隔
    const int       maxSwapInterval;//用来描述帧缓冲区交换前后两个图形缓冲区的最大时间间隔
    int reserved[8];//保留
    //用来设置帧缓冲区交换前后两个图形缓冲区的最小和最大时间间隔
    int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);
    //用来设置帧缓冲区的更新区域
    int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);
    //用来将图形缓冲区buffer的内容渲染到帧缓冲区中去
    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
    //用来通知fb设备,图形缓冲区的组合工作已经完成
    int (*compositionComplete)(struct framebuffer_device_t* dev);
    void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);
    int (*enableScreen)(struct framebuffer_device_t* dev, int enable);
    //保留
    void* reserved_proc[6];

2:alloc_device_t 用于描述图像分配相关的信息

typedef struct alloc_device_t {
    struct hw_device_t common;
    //用于分配一块图形缓冲区
    int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);
    //用于释放指定的图形缓冲区
    int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);
    void (*dump)(struct alloc_device_t *dev, char *buff, int buff_len);
    void* reserved_proc[7];
} alloc_device_t;

Gralloc设备打开过程分析

从上一节数据结构分析的过程中可知,设备打开的方法是在hw_module_t结构中定义的,定义打开的方法为

struct private_module_t HAL_MODULE_INFO_SYM = {
    .base = {
        .common = {
            ...
            .methods = &gralloc_module_methods
        },
        ....
    },
   ...
};

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

gralloc_device_open方法用来打开设备
参数hw_module_t为硬件抽象层加载得到的结构体
name 为打开目标设备的类型,分为两种

  • 1:GRALLOC_HARDWARE_FB0 "fb0"
    打开framebuffer_device_t, 负责将图像缓冲区的内容渲染到帧缓冲区,显示到屏幕上
  • 2:GRALLOC_HARDWARE_GPU0 "gpu0"
    打开alloc_device_t,负责图像缓冲区的分配和释放

参数hw_device_t为打开的设备保存的结构,返回给调用者

分别分析下打开两种设备的过程

1:打开GRALLOC_HARDWARE_FB0的过程

gralloc_device_open根据参数的不同来打开不同的设备,打开设备GRALLOC_HARDWARE_FB0,调用了fb_device_open方法

struct fb_context_t {
    framebuffer_device_t  device;
};


int fb_device_open(hw_module_t const* module, const char* name,
        hw_device_t** device)
{
    int status = -EINVAL;
    //判断设备名称是否是GRALLOC_HARDWARE_FB0,如果不是的直接返回打开失败
    if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
        //初始化设备framebuffer的上下文结构
        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
        memset(dev, 0, sizeof(*dev));

        //初始化设备相关的变量
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        //初始化fb相关的操作函数
        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;
        //将fb映射到当前进程的地址空间
        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<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;
}

这个函数创建了一个fb_context_t的数据结构, 并对其进行初始化,fb_context_t的device变量就是framebuffer_device_t,用来描述fb设备的。
同时还注册了操作fb设备的几个函数, 其中fb_post函数比较关键,负责将图形缓冲区的内容渲染到Framebuffer的显存中。
然后使用mapFrameBuffer函数来获取帧缓冲区的信息,然后将信息保存到framebuffer_device_t结构中,并将fb设备映射到当前进程。

再看下mapFrameBuffer做了什么操作?

int mapFrameBufferLocked(struct private_module_t* module)
{
    // framebuffer设备已经初始化则直接返回
    if (module->framebuffer) {
        return 0;
    }
   //从"/dev/graphics/和/dev/目录查找fb设备,并打开
    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;

    //获取framebuffer设备的不可变的信息
    struct fb_fix_screeninfo finfo;
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
        return -errno;

    //获取framebuffer设备的可变信息
    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;

   //fb_var_screeninfo的成员变量xres和yres用来描述显示屏的可视分辨率,而成员变量xres_virtual和 
   yres_virtual用来描述显示屏的虚拟分辨率。
   //将虚拟分辨率的高度值设置为可视分辨率的高度值的NUM_BUFFERS倍
   //当前声明为双缓存
   info.yres_virtual = info.yres * NUM_BUFFERS;

   //默认为双缓冲,如果不支持,则移除双缓冲的标志flag
    uint32_t flags = PAGE_FLIP;
#if USE_PAN_DISPLAY
    if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {
        ALOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
#else
    if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
        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)
        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;

   //再次通过IO控制命令FBIOGET_FSCREENINFO来获得系统帧缓冲区的固定信息
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
        return -errno;

    if (finfo.smem_len <= 0)
        return -errno;

    //得到的系统帧缓冲区的其它信息来初始化参数module所描述的一个private_module_t结构体
    module->flags = flags;
    module->info = info;
    module->finfo = finfo;
    module->xdpi = xdpi;
    module->ydpi = ydpi;
    module->fps = fps;

    //整个系统帧缓冲区的大小=虚拟分辨率的高度值info.yres_virtual * 每一行所占用的字节数finfo.line_length,并将整个系统帧缓冲区的大小对齐到页面边界
    int err;
    size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
   //创建一个private_handle_t,用来描述整个系统帧缓冲区的信息
    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;
    }
   //系统帧缓冲区在当前进程的地址空间中的起始地址保存到private_handle_t的域base中
    module->framebuffer->base = intptr_t(vaddr);
    //清空缓冲区的内存空间
    memset(vaddr, 0, fbSize);
    return 0;
}

mapFrameBuffer函数做了几件事情
1:打开fb设备,获取fb驱动的相关信息
2:设置fb的 yres_virtual为双缓冲大小
3:计算像素密度
4:计算双缓冲大小,并将其映射到当前进程,将缓冲区起始地址宝尊在framebuffer_device_t的base属性中。

至此FB设备打开过程就分析完了,FB设备打开过程做了什么事情?

打开fb设备,根据fb设备初始化相关的显示信息,并把fb设备显存映射到当前进程方便访问,同时还注册了几个操作fb设备的方法。

打开GRALLOC_HARDWARE_GPU0的过程

gralloc设备使用结构体alloc_device_t来描述。结构体alloc_device_t有两个成员函数alloc和free,分别用来分配和释放图形缓冲区。

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

首先创建了一个gralloc_context_t的上下文,gralloc_context_t的device就是alloc_device_t, 对其进行初始化 ,同时注册了几个操作alloc_device_t设备的函数, gralloc_alloc和gralloc_free用于分配和释放图形缓冲区。

什么地方打开了这两种设备?

分析了两种设备打开的过程, 但是什么时候会打开这两种设备呢?
1:FB设备打开时机

// Load and prepare the FB HAL, which uses the gralloc module.  Sets mFbDev.
int HWComposer::loadFbHalModule()
{
    hw_module_t const* module;

    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    if (err != 0) {
        ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
        return err;
    }

    return framebuffer_open(module, &mFbDev);
}

FB设备打开时机实在HWCompser构造函数中打开的,说明HWCompser会操作fb设备,渲染图像缓冲区到显示缓冲区, 具体在分析HWCompser的时候在进行分析。
2:gralloc设备打开时机

GraphicBufferAllocator::GraphicBufferAllocator()
    : mAllocDev(0)
{
    hw_module_t const* module;
    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(module, &mAllocDev);
    }
}

gralloc设备用于管理GraphicBuffer图形缓冲区,是在GraphicBufferAllocator中打开的,GraphicBufferAllocator负责图形缓冲区的分配和释放。后续在做详细分析
文章参考:Android图形显示之硬件抽象层Gralloc

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,694评论 0 3
  • 本文涉及的源代码基于 Android-7.1.1r。 一、Android GUI 框架 SurfaceFlinge...
    seraphzxz阅读 4,094评论 1 59
  • Android系统对硬件设备的支持是分两层的。一层实现在内核空间中(只有内核空间才有特权操作硬件设备),另一层实现...
    passerbywhu阅读 648评论 0 0
  • 小记 本书的六篇序言里,各位大咖都从自己独特的视角出发,结合自己的人生体验,将书中的思想加以内化和理解,我想这本身...
    雕兄_KYP阅读 659评论 0 0
  • 两个同样温和的人在一起很是默契,结婚多年,生活如每日都喝的玉米粥,平淡却养胃。 有一天,她翻看旧物,看到他大学里读...
    故事汇阅读 293评论 0 0