Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析(1)

简介:

 前面在介绍Android系统的开机画面时提到,Android设备的显示屏被抽象为一个帧缓冲区,而Android系统中的SurfaceFlinger服务就是通过向这个帧缓冲区写入内容来绘制应用程序的用户界面的。Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。本文将详细分析Gralloc模块的实现,为后续分析SurfaceFlinger服务的实现打下基础。

        在前面 Android系统的开机画面显示过程分析 一文中提到,Linux内核在启动的过程中会创建一个类别和名称分别为“graphics”和“fb0”的设备,用来描述系统中的第一个帧缓冲区,即第一个显示屏,其中,数字0表示从设备号。注意,系统中至少要存在一个显示屏,因此,名称为“fb0”的设备是肯定会存在的,否则的话,就是出错了。Android系统和Linux内核本身的设计都是支持多个显示屏的,不过,在Android目前的实现中,只支持一个显示屏。
        在前面 Android系统的开机画面显示过程分析 一文中还提到,init进程在启动的过程中,会启动另外一个进程ueventd来管理系统的设备文件。当ueventd进程启动起来之后,会通过netlink接口来Linux内核通信,以便可以获得内核中的硬件设备变化通知。而当ueventd进程发现内核中创建了一个类型和名称分别为“graphics”和“fb0”的设备的时候,就会这个设备创建一个/dev/graphics/fb0设备文件。这样,用户空间的应用程序就可以通过设备文件/dev/graphics/fb0来访问内核中的帧缓冲区,即在设备的显示屏中绘制指定的画面。注意,用户空间的应用程序一般是通过内存映射的方式来访问设备文件/dev/graphics/fb0的。
        Android系统定义了硬件抽象层模块的编写规范,具体可以参考 Android硬件抽象层(HAL)概要介绍和学习计划 一文。本文假设读者已经熟悉Android系统的硬件抽象层编写规范,因此,我们将按照帧缓冲区的使用情景以及硬件抽象层编写规范来介绍Gralloc模块的实现。
        用户空间的应用程序在使用帧缓冲区之间,首先要加载Gralloc模块,并且获得一个gralloc设备和一个fb设备。有了gralloc设备之后,用户空间中的应用程序就可以申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间来,以便可以向里面写入要绘制的画面的内容。最后,用户空间中的应用程序就通过fb设备来将前面已经准备好了的图形缓冲区渲染到帧缓冲区中去,即将图形缓冲区的内容绘制到显示屏中去。相应地,当用户空间中的应用程序不再需要使用一块图形缓冲区的时候,就可以通过gralloc设备来释放它,并且将它从地址空间中解除映射。接下来,我们就按照上述使用情景来分析Gralloc模块的实现。
       1. Gralloc模块的加载过程。
        每一个HAL模块都有一个ID值,以这些ID值为参数来调用硬件抽象层提供的函数hw_get_module就可以将指定的模块加载到内存来,并且获得一个hw_module_t接口来打开相应的设备。
        Gralloc模块的ID值定义在hardware/libhardware/include/hardware/gralloc.h文件中,如下所示:
  1. #define GRALLOC_HARDWARE_MODULE_ID "gralloc"  
        函数hw_get_module实现在hardware/libhardware/hardware.c文件中,如下所示:
  1. /** Base path of the hal modules */  
  2. #define HAL_LIBRARY_PATH1 "/system/lib/hw"  
  3. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"  
  4.   
  5. /** 
  6.  * There are a set of variant filename for modules. The form of the filename 
  7.  * is "<MODULE_ID>.variant.so" so for the led module the Dream variants  
  8.  * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: 
  9.  * 
  10.  * led.trout.so 
  11.  * led.msm7k.so 
  12.  * led.ARMV6.so 
  13.  * led.default.so 
  14.  */  
  15.   
  16. static const char *variant_keys[] = {  
  17.     "ro.hardware",  /* This goes first so that it can pick up a different 
  18.                        file on the emulator. */  
  19.     "ro.product.board",  
  20.     "ro.board.platform",  
  21.     "ro.arch"  
  22. };  
  23.   
  24. static const int HAL_VARIANT_KEYS_COUNT =  
  25.     (sizeof(variant_keys)/sizeof(variant_keys[0]));  
  26.   
  27. ......  
  28.   
  29. int hw_get_module(const char *id, const struct hw_module_t **module)  
  30. {  
  31.     int status;  
  32.     int i;  
  33.     const struct hw_module_t *hmi = NULL;  
  34.     char prop[PATH_MAX];  
  35.     char path[PATH_MAX];  
  36.   
  37.     /* 
  38.      * Here we rely on the fact that calling dlopen multiple times on 
  39.      * the same .so will simply increment a refcount (and not load 
  40.      * a new copy of the library). 
  41.      * We also assume that dlopen() is thread-safe. 
  42.      */  
  43.   
  44.     /* Loop through the configuration variants looking for a module */  
  45.     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {  
  46.         if (i < HAL_VARIANT_KEYS_COUNT) {  
  47.             if (property_get(variant_keys[i], prop, NULL) == 0) {  
  48.                 continue;  
  49.             }  
  50.   
  51.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
  52.                     HAL_LIBRARY_PATH1, id, prop);  
  53.             if (access(path, R_OK) == 0) break;  
  54.   
  55.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
  56.                      HAL_LIBRARY_PATH2, id, prop);  
  57.             if (access(path, R_OK) == 0) break;  
  58.         } else {  
  59.             snprintf(path, sizeof(path), "%s/%s.default.so",  
  60.                      HAL_LIBRARY_PATH1, id);  
  61.             if (access(path, R_OK) == 0) break;  
  62.         }  
  63.     }  
  64.   
  65.     status = -ENOENT;  
  66.     if (i < HAL_VARIANT_KEYS_COUNT+1) {  
  67.         /* load the module, if this fails, we're doomed, and we should not try 
  68.          * to load a different variant. */  
  69.         status = load(id, path, module);  
  70.     }  
  71.   
  72.     return status;  
  73. }  
        函数hw_get_module依次在目录/system/lib/hw和/vendor/lib/hw中查找一个名称为"<MODULE_ID>.variant.so"的文件,其中,<MODULE_ID>是一个模块ID,而variant表示"ro.hardware"、"ro.product.board"、"ro.board.platform"和"ro.arch"四个系统属性值之一。例如,对于Gralloc模块来说,函数hw_get_module依次在目录/system/lib/hw和/vendor/lib/hw中检查是否存在以下四个文件:
 
       gralloc.<ro.hardware>.so
       gralloc.<ro.product.board>.so
       gralloc.<ro.board.platform>.so
       gralloc.<ro.arch>.so
      
       只要其中的一个文件存在,  函数hw_get_module就会停止查找过程,并且调用另外一个函数load来将这个文件加载到内存中来。另一方面,如果在/system/lib/hw和/vendor/lib/hw中均不存这些文件,那么函数hw_get_module就会在目录/system/lib/hw中查找是否存在一个名称为gralloc.default.so的文件。如果存在的话,那么也会调用函数load将它加载到内存中来。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/967056,如需转载请自行联系原作者
目录
相关文章
|
4月前
|
缓存 API Android开发
Android经典实战之Kotlin Flow中的3个数据相关的操作符:debounce、buffer和conflate
本文介绍了Kotlin中`Flow`的`debounce`、`buffer`及`conflate`三个操作符。`debounce`过滤快速连续数据,仅保留指定时间内的最后一个;`buffer`引入缓存减轻背压;`conflate`仅保留最新数据。通过示例展示了如何在搜索输入和数据流处理中应用这些操作符以提高程序效率和用户体验。
54 6
|
4月前
|
编解码 网络协议 前端开发
如何实现Android平台GB28181设备接入模块按需打开摄像头并回传数据
后台采集摄像头,如果想再进一步扩展,可以把android平台gb28181的camera2 demo,都移植过来,实现功能更强大的国标设备侧,这里主要是展示,收到国标平台侧的回传请求后,才打开摄像头,才开始编码打包,最大限度的减少资源的占用
|
4月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
4月前
|
监控 Java 开发工具
如何快速对接Android平台GB28181接入模块(SmartGBD)
大牛直播SDK推出的Android平台GB28181接入SDK(SmartGBD),可实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景,可能是业内为数不多功能齐全性能优异的商业级水准GB28181接入SDK。
|
4月前
|
编解码 开发工具 Android开发
Android平台RTMP直播推送模块技术接入说明
大牛直播SDK跨平台RTMP直播推送模块,始于2015年,支持Windows、Linux(x64_64架构|aarch64)、Android、iOS平台,支持采集推送摄像头、屏幕、麦克风、扬声器、编码前、编码后数据对接,功能强大,性能优异,配合大牛直播SDK的SmartPlayer播放器,轻松实现毫秒级的延迟体验,满足大多数行业的使用场景。RTMP直播推送模块数据源,支持编码前、编码后数据对接
|
4月前
|
监控 开发工具 Android开发
结合GB/T28181规范探讨Android平台设备接入模块心跳实现
本文介绍了GB28181标准中的状态信息报送机制,即心跳机制,用于监控设备与服务器间的连接状态。根据国标GB/T28181-2016,设备在异常时需立即发送状态信息,在正常状态下则按固定间隔(默认60秒)定期发送。若连续三次(默认值)未收到心跳,则视为离线。文章展示了在Android平台的GB28181设备接入模块(SmartGBD)中,如何调整心跳间隔为20秒及超时次数为3次,并给出了心跳消息的示例和异常处理代码片段。对于希望深入了解或遇到问题的开发者,作者提供了进一步交流的机会。
|
4月前
|
编解码 API 开发工具
Android平台轻量级RTSP服务模块二次封装版调用说明
本文介绍了Android平台上轻量级RTSP服务模块的二次封装实践,旨在简化开发流程,让开发者能更专注于业务逻辑。通过`LibPublisherWrapper`类提供的API,可在应用中轻松初始化RTSP服务、配置视频参数(如分辨率、编码类型)、启动与停止RTSP服务及流发布,并获取RTSP会话数量。此外,还展示了如何处理音频和视频数据的采集与推送。最后,文章提供了从启动服务到销毁资源的完整示例,帮助开发者快速集成实时流媒体功能。
|
4月前
|
编解码 开发工具 Android开发
Android平台轻量级RTSP服务模块技术接入说明
为满足内网无纸化/电子教室等内网超低延迟需求,避免让用户配置单独的服务器,大牛直播SDK在推送端发布了轻量级RTSP服务SDK。 轻量级RTSP服务解决的核心痛点是避免用户或者开发者单独部署RTSP或者RTMP服务,实现本地的音视频数据(如摄像头、麦克风),编码后,汇聚到内置RTSP服务,对外提供可供拉流的RTSP URL,轻量级RTSP服务,适用于内网环境下,对并发要求不高的场景,支持H.264/H.265,支持RTSP鉴权、单播、组播模式,考虑到单个服务承载能力,我们支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数。
|
7月前
|
编解码 调度 Android开发
Android音频框架之一 详解audioPolicy流程及HAL驱动加载与配置
Android音频框架之一 详解audioPolicy流程及HAL驱动加载与配置
712 0
|
7月前
|
Android开发
Android 集成vendor下的模块
Android 集成vendor下的模块
64 0