当前位置: 首页 > article >正文

Android显示系统(01)- 架构分析

一、前言:

Android是基于Linux的,而显示设备的驱动也都是和Linux普通设备一样去管理,也就是说归根结底还是要按照Linux的方式组织数据送给LCD,因此,我们理解Android设计的这一套复杂的显示系统时候,一定要提醒自己目的地在哪儿!

二、显示系统逻辑:

这儿先画个很简单的逻辑图,帮助大家理解:

在这里插入图片描述

  • APP不断生产数据到内存的FrameBuffer中,CPU控制FrameBuffer中的数据定期送给LCD即可;
  • LCD上的一个像素在FrameBuffer中用两个字节描述,比如LCD要显示1920*1080大小图片,那么FrameBuffer分配的大小就应该是1920*1080*2字节;

大家不妨思考两分钟,这个系统最大的问题在哪儿?

…Two minutes later…

最大问题就是只有一个FrameBuffer,朋友请你想一想,APP和LCD同时在访问同一个FrameBuffer,这不就相当于你当着用户的面明目张胆地画图吗?用户火气大一点,你设备都得被摔稀碎。这样就会导致:

  • 如果你APP写得快,LCD读的慢,这样就有可能会跳帧,比如:原来的画面是123,APP写完1之后LCD显示了,当APP写完2的时候LCD还没来读,APP写完3的时候LCD又来读了,因此,LCD显示出来的是13;
  • 如果APP写得太慢,LCD读的太快,同理,就是卡帧,因此你太慢了;
  • 如果APP写得刚好等于LCD读的速度,那么不会有问题,可实际场景中,这种理想化场景几乎不可能一直保持;

那么,怎么改进呢?

就是采用多个FrameBuffer,如下图所示:

在这里插入图片描述

  • 当APP写FrameBuffer1的时候,LCD在读取FrameBuffer2

  • 完成之后,会将FrameBuffer1FrameBuffer2进行swap(交换);

  • 然后App写FrameBuffer2,LCD读FrameBuffer1

一直这样循环即可大功告成!!!

二、Layer:

想象下,如果每个APP都跑去绘图会有什么问题?比如你在小窗口刷视频网站,此时,最顶端的状态栏,最下端的导航栏,以及视频播放窗口这三个都不停去送显,但是状态栏和导航栏几乎是不变的,只有APP的自己视频窗口内容一直在变,他们三个都送显会浪费系统资源。因此,引入Layer(图层)的概念,比如我们可以将状态栏和导航栏打包成一个Layer,让SystemUI进程去负责刷新,APP单独一个Layer去刷新数据,这样,每个Layer在底层都有自己的FrameBuffer,上层只管往里写,最终通过SurfaceFlinger控制HWC去合成为一张图片送显。

三、APP到SurfaceFlinger:

上面了解了一个很潦草的框架图,下面就详细分析下数据怎么准备的,又是最终怎么送给FrameBuffer的。

整个显示系统可以用一个很关键的模块串起来,那就是大名鼎鼎的SurfaceFlinger(下文可能会因为懒,写成SF),它的主要作用就是对多个App的,我们先看一个架构图:
在这里插入图片描述

这个图我的重点是在App给SurfaceFlinger送的数据是如何准备的:

  • 每个APP都有1到多个buffer,这个buffer是从SF申请来的,SF传给APP的是fd,APP进行mmap即可获得对应buffer;
  • APP拿到buffer之后,可以直接往buffer写数据,可以通过2D引擎库(比如skia)或者3D引擎库(OpenGL ES)去准备数据(就是渲染);
  • 准备好数据之后写入到Surface当中(其实上面说的buffer由surface在管理);
  • 这样,每个APP都写好了自己的Surface,Android会将这多个Surface通过Z-Order(前后顺序)结合Layout(布局)进行合成为一张图片;
  • 当然SF并不是啥都自己干,它可以通过Gralloc去管理内存,可以通过HWC去合成Surface,也可以调用OpenGL ES去合成;

四、SurfaceFlinger:

SurfaceFlinger作为Android显示系统的核心管理者,涉及的模块特别多,我们先理清楚几个关键模块之间的关系,否则,会只见树木不见森林。

在这里插入图片描述

  • 主要模块:

    • SurfaceFlinger:将Surface合成起来,管理着两个驱动程序ashmem和frameBuffer;

    • Ashmem:匿名内存模块;

    • Gralloc:负责帧buffer的分配和释放;

    • EGL:为了保证OpenGL ES的平台无关性,封装EGL;

    • OpenGL ES:OpenGL不是一个库,是一种接口协议,如果有gpu会加载gpu对应的libhgl库,如果没有gpu,也可以加载libagl这个纯软件库,通过cpu去完成,具体应该加载软件还是硬件库,会在egl.cfg这个配置文件中配置好;

    • FramebufferNaitveWindow:OpenGL ES是平台无关的,因此,需要在不同的平台系统上进行“本地化”,Android上就是通过FramebufferNaitveWindow这个中介将Android本地的窗口和OpenGL ES的窗口关联起来;

    • HWCComposer:进行Layer合成和负责Vsync信号的产生和控制;

      • 一般情况下芯片都支持硬件HWC;

      • 如果不支持HWC,或者大于支持的Layer个数上限,都使用软件(OpenGL ES)进行合成;

      • 无论是硬件或者软件合成,都必须遵守EGL接口;

    • 也可以使用OpenGL库进行合成;

      • 如果有GPU,那么加载对应的so,编写sharde程序去用GPU(硬件)合成;
      • 没有GPU那么使用纯软件的libGLES_android这个纯软件库去合成;
  • Buffer申请:

    • 每个App都有自己的界面,需要将界面数据绘制到1个或者多个buffer里面;

    • 那么,这些buffer哪儿来呢?如果APP自己申请buffer,填充好数据,再通过socket发送给SF,效率非常低,因此,通过让SF自己分配了,然后通过mmap映射出来,这样APP和SF操作同一块内存,APP写入数据SF会马上可以读到;

    • SF里面会调用HAL层的Gralloc模块进行buffer申请;

    • Gralloc模块又会通过驱动层的ashmem申请匿名内存,然后返回句柄fd给HAL,再传递给SF;

    • SF再通过Binder系统将fd传给App;

    • App往buffer里面写好数据之后,通过SurfaceFlinger交给FrameBuffer,才可以显示数据;

五、总结:

本文主要从框架层面对Android显示系统进行了介绍,里面最重要的就是SurfaceFlinger,它管理者众多模块完成了Android每一帧画面的显示。


http://www.kler.cn/a/411944.html

相关文章:

  • 基于SpringBoot的工程教育认证的计算机课程管理系统【附源码】
  • Kubeadm 安装 Kubernetes 高可用集群 v1.30.0
  • Easyexcel(7-自定义样式)
  • 《白帽子讲Web安全》13-14章
  • android-studio-4.2下载 、启动
  • 【FPGA】Verilog:利用 4 个串行输入- 串行输出的 D 触发器实现 Shift_register
  • Leetcode3206:交替组 I
  • 实现List接口的三类-ArrayList -Vector -LinkedList
  • zabbix 图形中文显示乱码问题
  • 前半有序的排序及有序游标
  • 【SpringBoot】Spring Data Redis的环境搭建(win10)
  • 3D建筑模型的 LOD 规范
  • 非协议默认端口的:NAT alg需配置port-mapping
  • 在vue中,根据后端接口返回的文件流实现word文件弹窗预览
  • mydocker
  • 使用Setup Factory将C#的程序打包成安装包
  • WordCloud去掉停用词(fit_words+generate)的2种用法
  • LSTM原理解读与实战
  • 麒麟系统x86安装达梦数据库
  • uniapp中使用Mescroll实现下拉刷新与上拉加载项目实战
  • Win11 22H2/23H2系统11月可选更新KB5046732发布!
  • JAVA实现将PDF转换成word文档
  • 【Z2400011】基于Java+SpringBoo+mysql实现的自习室预订系统
  • <javascript><html>在两个html页面间跳转时使用浏览器本地存储localStorage传递共享参数
  • C# 调用系统级方法复制、移动和删除等操作界面
  • STM32 外设简介