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,如需转载请自行联系原作者
目录
相关文章
|
1天前
|
存储 Android开发
android launcher总体分析
android launcher总体分析
|
3天前
|
编解码 缓存 安全
Android SELinux 参数语法介绍及基础分析
Android SELinux 参数语法介绍及基础分析
9 0
|
3天前
|
Java 物联网 Linux
Android硬件通信之 串口通信
Android硬件通信之 串口通信
7 0
|
17天前
|
存储 安全 文件存储
Android OTA升级后输入法异常和应用丢失的分析
Android OTA升级后输入法异常和应用丢失的分析
20 1
|
17天前
|
存储 Java Shell
Android系统 实现低内存白名单防LMK原理分析
Android系统 实现低内存白名单防LMK原理分析
32 0
|
开发工具 Android开发
Android 7.1 使用mmm编译模块失败
Android 7.1 使用mmm编译模块失败
225 0
|
Android开发
Android不编译某个模块
Android 5.1 源码,编译相关的文件一般在build目录下build/target/product 放了很多mk文件;一般不同的产品会有不同的目录 假设我不想编译OpenWnn,在build目录下grep一下“OpenWnn”target/product/full_base.
1375 0
|
7天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。
|
10天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
11天前
|
监控 Java Android开发
安卓应用开发:打造高效用户界面的五大策略
【4月更文挑战第29天】 在安卓应用开发的世界中,构建一个既美观又高效的用户界面(UI)对于吸引和保留用户至关重要。本文将深入探讨五种策略,这些策略可以帮助开发者优化安卓应用的UI性能。我们将从布局优化讲起,逐步过渡到绘制优化、内存管理、异步处理以及最终的用户交互细节调整。通过这些实践技巧,你将能够为用户提供流畅而直观的体验,确保你的应用在竞争激烈的市场中脱颖而出。