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每一帧画面的显示。

相关推荐
是阿建吖!5 分钟前
【Linux】线程池
android·linux·c语言·c++
影音小博士26 分钟前
分享几个高清无水印国外视频素材网站
经验分享·学习·音视频
Yang-Never1 小时前
Canvas->Bitmap绘制
android·java·开发语言·kotlin·android studio·idea
纪伊路上盛名在1 小时前
从视频中截取ppt,整理为pdf
笔记·学习·计算机视觉·pdf·powerpoint·音视频·学习方法
zhangphil2 小时前
Android adb shell GPU信息
android·adb
学习嵌入式的小羊~2 小时前
RV1126+FFMPEG推流项目(1)总体框架讲解
ffmpeg·音视频
Crossoads4 小时前
【汇编语言】外中断(三)—— 探秘汇编外中断:从安装新INT 9例程到指令系统总结
android·开发语言·汇编·stm32·单片机·嵌入式硬件·dubbo
_可乐无糖4 小时前
Appium:Android 和 iOS 的capabilities是否需要前缀?
android·ui·ios·appium·自动化
花生的酱4 小时前
mycat介绍与操作步骤
android·数据库·sql·mysql
molong9314 小时前
Android基于监听的事件处理机制
android