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

简介:
      5. 图形缓冲区的释放过程
        前面提到,用户空间的应用程序用到的图形缓冲区是由Gralloc模块中的函数gralloc_free来释放的,这个函数实现在文件hardware/libhardware/modules/gralloc/gralloc.cpp中,如下所示:
  1. static int gralloc_free(alloc_device_t* dev,  
  2.         buffer_handle_t handle)  
  3. {  
  4.     if (private_handle_t::validate(handle) < 0)  
  5.         return -EINVAL;  
  6.   
  7.     private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);  
  8.     if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {  
  9.         // free this buffer  
  10.         private_module_t* m = reinterpret_cast<private_module_t*>(  
  11.                 dev->common.module);  
  12.         const size_t bufferSize = m->finfo.line_length * m->info.yres;  
  13.         int index = (hnd->base - m->framebuffer->base) / bufferSize;  
  14.         m->bufferMask &= ~(1<<index);  
  15.     } else {  
  16.         gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(  
  17.                 dev->common.module);  
  18.         terminateBuffer(module, const_cast<private_handle_t*>(hnd));  
  19.     }  
  20.   
  21.     close(hnd->fd);  
  22.     delete hnd;  
  23.     return 0;  
  24. }  

        要释放的图形缓冲区使用参数handle来描述。前面提到,从Gralloc模块中分配的图形缓冲区是使用private_handle_t结构体来描述的,因此,这里的参数handle应该指向一个private_handle_t结构体,这是通过调用private_handle_t类的静态成员函数validate来验证的。private_handle_t类的静态成员函数validate的实现可以参考前面第1部分的内容。
 
        要释放的图形缓冲区有可能是在系统帧缓冲区分配的,也有可能是在内存中分配的,这可以通过检查它的标志值flags的PRIV_FLAGS_FRAMEBUFFER位是否等于1来确认。
        如果要释放的图形缓冲区是在系统帧缓冲区中分配的,那么首先要知道这个图形缓冲区是系统帧缓冲区的第index个位置,接着再将变量m所描述的一个private_module_t结构体的成员变量bufferMask的第index位重置为0即可。我们只需要将要释放的图形缓冲区的开始地址减去系统帧缓冲区的基地址,再除以一个图形缓冲区的大小,就可以知道要释放的图形缓冲区是系统帧缓冲区的第几个位置。这个过程刚好是在系统帧缓冲区中分配图形缓冲区的逆操作。
        如果要释放的图形缓冲区是内存中分配的,那么只需要调用另外一个函数terminateBuffer来解除要释放的图形缓冲区在当前进程的地址空间中的映射。
        最后,这个函数还会将用来描述要释放的图形缓冲区的private_handle_t结构体所占用的内存释放掉,并且将要要释放的图形缓冲区所在的系统帧缓冲区或者匿名共享内存的文件描述符关闭掉。
       函数terminateBuffer实现在文件hardware/libhardware/modules/gralloc/mapper.cpp中,如下所示:
  1. int terminateBuffer(gralloc_module_t const* module,  
  2.         private_handle_t* hnd)  
  3. {  
  4.     if (hnd->base) {  
  5.         // this buffer was mapped, unmap it now  
  6.         gralloc_unmap(module, hnd);  
  7.     }  
  8.   
  9.     return 0;  
  10. }  
       它通过调用另外一个函数gralloc_unmap来解除参数hnd所描述的一个图形缓冲区在当前进程的地址空间中的映射。后面在分析图形缓冲区的注销过程时,我们再详细分析函数gralloc_unmap的实现。
 
       至此,图形缓冲区的释放过程就分析完成了,接下来我们继续分析图形缓冲区的注册过程。
       6. 图形缓冲区的注册过程
       前面提到,在Android系统中,所有的图形缓冲区都是由SurfaceFlinger服务分配的,而当一个图形缓冲区被分配的时候,它会同时被映射到请求分配的进程的地址空间去,即分配的过程同时也包含了注册的过程。但是对用户空间的其它的应用程序来说,它们所需要的图形缓冲区是在由SurfaceFlinger服务分配的,因此,当它们得到SurfaceFlinger服务分配的图形缓冲区之后,还需要将这块图形缓冲区映射到自己的地址空间来,以便可以使用这块图形缓冲区。这个映射的过程即为我们接下来要分析的图形缓冲区注册过程。
       前面还提到,注册图形缓冲区的操作是由Gralloc模块中的函数gralloc_register_buffer来实现的,这个函数实现在文件hardware/libhardware/modules/gralloc/mapper.cpp中,如下所示:
  1. int gralloc_register_buffer(gralloc_module_t const* module,  
  2.         buffer_handle_t handle)  
  3. {  
  4.     if (private_handle_t::validate(handle) < 0)  
  5.         return -EINVAL;  
  6.   
  7.     // if this handle was created in this process, then we keep it as is.  
  8.     int err = 0;  
  9.     private_handle_t* hnd = (private_handle_t*)handle;  
  10.     if (hnd->pid != getpid()) {  
  11.         void *vaddr;  
  12.         err = gralloc_map(module, handle, &vaddr);  
  13.     }  
  14.     return err;  
  15. }  
       这个函数首先验证参数handle指向的一块图形缓冲区的确是由Gralloc模块分配的,方法是调用private_handle_t类的静态成员函数validate来验证,即如果参数handle指向的是一个private_handle_t结构体,那么它所指向的一块图形缓冲区就是由Gralloc模块分配的。
 
       通过了上面的检查之后,函数gralloc_register_buffer还需要检查当前进程是否就是请求Gralloc模块分配图形缓冲区hnd的进程。如果是的话,那么当前进程在请求Gralloc模块分配图形缓冲区hnd的时候,就已经将图形缓冲区hnd映射进自己的地址空间来了,因此,这时候就不需要重复在当前进程中注册这个图形缓冲区。
       真正执行注册图形缓冲区的操作是由函数gralloc_map来实现的,这个函数也是实现文件hardware/libhardware/modules/gralloc/mapper.cpp中,如下所示:
  1. static int gralloc_map(gralloc_module_t const* module,  
  2.         buffer_handle_t handle,  
  3.         void** vaddr)  
  4. {  
  5.     private_handle_t* hnd = (private_handle_t*)handle;  
  6.     if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {  
  7.         size_t size = hnd->size;  
  8.         void* mappedAddress = mmap(0, size,  
  9.                 PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);  
  10.         if (mappedAddress == MAP_FAILED) {  
  11.             LOGE("Could not mmap %s", strerror(errno));  
  12.             return -errno;  
  13.         }  
  14.         hnd->base = intptr_t(mappedAddress) + hnd->offset;  
  15.         //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",  
  16.         //        hnd->fd, hnd->offset, hnd->size, mappedAddress);  
  17.     }  
  18.     *vaddr = (void*)hnd->base;  
  19.     return 0;  
  20. }  
       由于在系统帧缓冲区中分配的图形缓冲区只在SurfaceFlinger服务中使用,而SurfaceFlinger服务在初始化系统帧缓冲区的时候,已经将系统帧缓冲区映射到自己所在的进程中来了,因此,函数gralloc_map如果发现要注册的图形缓冲区是在系统帧缓冲区分配的时候,那么就不需要再执行映射图形缓冲区的操作了。
 
       如果要注册的图形缓冲区是在内存中分配的,即它的标志值flags的PRIV_FLAGS_FRAMEBUFFER位等于1,那么接下来就需要将它映射到当前进程的地址空间来了。由于要注册的图形缓冲区是在文件描述符hnd->fd所描述的一块匿名共享内存中分配的,因此,我们只需要将文件描述符hnd->fd所描述的一块匿名共享内存映射到当前进程的地址空间来,就可以将参数hnd所描述的一个图形缓冲区映射到当前进程的地址空间来。
       由于映射文件描述符hnd->fd得到的是一整块匿名共享内存在当前进程地址空间的基地址,而要注册的图形缓冲区可能只占据这块匿名共享内存的某一小部分,因此,我们还需要将要注册的图形缓冲区的在被映射的匿名共享内存中的偏移量hnd->offset加上被映射的匿名共享内存的基地址hnd->base,才可以得到要注册的图形缓冲区在当前进程中的访问地址,这个地址最终又被写入到hnd->base中去。
       注册图形缓冲区的过程就是这么简单,接下来我们再分析图形缓冲区的注销过程。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/967092,如需转载请自行联系原作者
目录
相关文章
|
2月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
236 4
|
2月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
2月前
|
缓存 Java 数据库
Android的ANR原理
【10月更文挑战第18天】了解 ANR 的原理对于开发高质量的 Android 应用至关重要。通过合理的设计和优化,可以有效避免 ANR 的发生,提升应用的性能和用户体验。
131 56
|
1月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
33 8
|
3月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
101 15
Android 系统缓存扫描与清理方法分析
|
2月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
55 1
|
Linux API Android开发
Android HAL(硬件抽象层)介绍以及调用
Android 的 HAL(Hardware Abstract Layer硬件抽象层)是Google因应厂商「希望不公开源码」的要求下,所推出的新观念,其架构如下图。
2238 0
|
2月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
1月前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
57 19
|
1月前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
65 14