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

相关推荐
百锦再20 分钟前
Android Studio开发 SharedPreferences 详解
android·ide·android studio
青春给了狗32 分钟前
Android 14 修改侧滑手势动画效果
android
CYRUS STUDIO39 分钟前
Android APP 热修复原理
android·app·frida·hotfix·热修复
火柴就是我2 小时前
首次使用Android Studio时,http proxy,gradle问题解决
android
limingade2 小时前
手机打电话时电脑坐席同时收听对方说话并插入IVR预录声音片段
android·智能手机·电脑·蓝牙电话·电脑打电话
浩浩测试一下2 小时前
计算机网络中的DHCP是什么呀? 详情解答
android·网络·计算机网络·安全·web安全·网络安全·安全架构
青春给了狗4 小时前
Android 14 系统统一修改app启动时图标大小和圆角
android
pengyu4 小时前
【Flutter 状态管理 - 柒】 | InheritedWidget:藏在组件树里的"魔法"✨
android·flutter·dart
居然是阿宋6 小时前
Kotlin高阶函数 vs Lambda表达式:关键区别与协作关系
android·开发语言·kotlin
凉、介6 小时前
PCI 总线学习笔记(五)
android·linux·笔记·学习·pcie·pci