☰
Android显示系统架构详解:从SurfaceFlinger到VSYNC的完整链路
2026/10/3 1:29:18 网站建设 项目流程

搞明白Android显示系统这件事,我一直觉得是Android开发进阶路上最难啃但又最值得啃的硬骨头。很多人写了好几年应用,遇到卡顿问题只会盲目优化布局,遇到黑屏闪烁只能上网搜各种玄学解法,根源就在于对屏幕上一帧画面到底是怎么从代码变成像素这件事没有整体认知。这篇我打算把这套框架从头到尾梳理一遍,给后面的系列开个头。

Android的显示图形栈(Display Graphics)涉及应用绘制、跨进程传输、系统合成、硬件扫描输出这么几个大环节,每个环节都有专门组件在干活。本文适合已经开始写Android代码、但想深入理解系统机制的开发同学阅读,也适合做性能优化、系统定制、甚至ROM开发的人用来建立完整知识地图。

1. 显示系统的复杂程度,远超你想象

1.1 为什么Android需要一套专门的显示框架

很多人会有个疑问:我写个App,往界面上放几个控件,系统把像素画出来不就行了?为什么还要搞出SurfaceFlinger、BufferQueue、HWC这么一堆听起来就头大的东西?

答案是Android的显示链路天然要面对三个棘手问题。

第一个问题是多窗口多进程并发显示。同一块屏幕上,状态栏是一个进程在画,桌面是一个进程,你的App是另一个进程,还有输入法、悬浮窗、通知栏这些可能同时在更新。大家都往一块物理屏幕上写像素,没有统一调度中枢的话,画面一定会互相覆盖、闪烁撕裂。Android的核心思路是让每个应用各自画各自的,最后由系统统一合成再输出。

第二个问题是性能瓶颈极其敏感。屏幕刷新率是固定的,60Hz意味着每16.6ms就要出一帧,90Hz是11.1ms,120Hz是8.3ms。这么短的时间里要完成应用UI绘制、渲染、跨进程传递、系统合成、硬件提交这一整套动作,任何一个环节超时用户马上就能感觉到掉帧。所以显示链路的每个组件设计几乎都围绕"降低延迟、减少拷贝、提升吞吐"这三个目标展开。

第三个问题是硬件差异巨大。不同手机的屏幕分辨率不同,GPU方案不同(高通Adreno、Mali、PowerVR、桌面级核显),有没有独立显示芯片也不一样。Android必须搞一套中间层把上层逻辑和底层硬件解耦,让应用开发者面对统一的接口,让OEM厂商能接入各自的硬件实现。

这套框架的本质,就是一个多生产者、单消费者、带硬件接口的生产线。理解了这个比喻,后面每一个组件你都能找到它在这条线上的位置。

1.2 一条完整的显示链路是什么样子

我先画一条最简链路,后面所有章节都在为这条链路上的各个节点做深入解释。

第一步,应用的UI线程通过测量、布局、绘制生成显示列表,RenderThread通过OpenGL ES或Vulkan把绘制指令真正渲染到一块内存区域上,这块区域叫Surface。

第二步,渲染完成后的Buffer(图像缓冲区)通过BufferQueue机制从应用进程传递给系统进程中的SurfaceFlinger。

第三步,SurfaceFlinger拿到所有应用传来的Buffer,加上状态栏、导航栏这些系统UI的Buffer,按照Z轴顺序做图层合成。合成可以用GPU做,也可以交给硬件合成器HWC做。

第四步,合成结果提交给显示控制器(Display Controller),最终通过HDMI、DP、MIPI-DSI等接口输出到物理屏幕面板上。

整个过程里,硬件Vsync信号负责统一节奏,让应用绘制、系统合成、屏幕扫描三者保持同步。

一句话总结:每个应用画自己的图层,系统统一叠图层并输出。这个"分层合成"模型就是Android图形系统最核心的设计哲学。iPhone其实也是类似的思路,只不过实现细节不同。

2. 分层架构拆解:每一层都在解决什么问题

2.1 应用层的Surface与View体系

先从我们最熟悉的层面说起。你在Activity里写了一个布局,里面放了TextView、Button,这套View体系到底是怎么变成最终屏幕上像素的?

Android的UI框架是这么设计的:View负责决定画什么、画在哪里,但负责真正执行绘制的是RenderThread。当View调用了invalidate()之后,系统并不会立刻重绘,而是记录一个脏区域,等到下一个Vsync信号到来,Choreographer回调doFrame(),才开始走measure、layout、draw这套流程。

draw阶段做的事情用一句话概括:遍历View树,把每个View的绘制指令(比如画一个圆、画一段文字)记录到一个DisplayList里。DisplayList经过一系列编译优化后,变成GPU能理解的渲染指令,由RenderThread提交给GPU执行,最终把像素画到Surface对应的Buffer里。

这里有个特别关键的概念:Surface不等于屏幕上的一个窗口,它更像是一块"画布+缓冲区"的组合体。每个Window(对应一个Activity或Dialog)都持有自己的Surface,这块Surface背后有多个Buffer循环使用。你看到的App界面,其实只是SurfaceFlinger拿着这块画布去做合成的一个输入源。

还有一个细节经常被忽视:RenderThread和UI线程是分开的。UI线程负责执行View的生命周期和measure/layout,RenderThread负责把DisplayList真正渲染成GPU指令。这俩线程通过同步屏障机制协同工作,目的就是让UI线程尽快结束、尽快处理下一个输入事件,渲染耗时被挪到后台线程去消化。这也是为什么新版本Android上即使布局稍微复杂一点,UI线程也不太容易ANR的一个底层原因。

2.2 Framework层的WindowManager与WMS

在应用进程内部,WindowManager负责管理窗口;在系统进程里,WindowManagerService(WMS)负责所有进程窗口的全局调度。这俩协同实现了窗口的添加、删除、层级调整、焦点管理这些功能。

每个窗口对应应用侧的一个Surface,WMS会给每个Surface分配一个Z轴顺序,这个顺序直接决定了后续SurfaceFlinger合成时谁在上谁在下。状态栏的Z轴顺序通常最高,所以它永远盖在普通应用上方。

WMS还负责一件事:把窗口的尺寸、位置、变换矩阵这些元数据同步给SurfaceFlinger。SurfaceFlinger合成时不光要拿Buffer里的像素,还要知道每个图层应该放大多少、偏移多少、旋转多少。这些信息放在一个叫LayerState的结构里,每次窗口属性变化,WMS就会通过Binder调用更新到SurfaceFlinger。

从整个链路上看,WMS只负责"窗口应该长什么样、在哪、谁在上面"这件事,不碰真正的像素数据。像素数据的传递完全走BufferQueue那条独立通道。这种职责分离让窗口管理和图形传输可以各自独立演进、独立优化。

2.3 系统服务层:SurfaceFlinger的核心定位

SurfaceFlinger是Android显示系统的大脑,运行在system_server进程里,所有应用Surface的合成操作都得经它调度。它是从Android 1.0时代就存在的元老级组件,地位怎么强调都不过分。

SurfaceFlinger的核心工作可以拆成四件事:

第一,接收所有进程的Surface。应用创建Surface时,需要通过SurfaceFlinger创建对应的Layer对象。这个Layer在SurfaceFlinger这边就代表一个输入图层。

第二,根据Vsync信号统一合成。收到硬件Vsync后,SurfaceFlinger遍历所有可见Layer,判断哪些Layer有新Buffer提交,哪些可以沿用旧Buffer,然后决定合成策略——是用GPU合成,还是把大部分图层直接交给HWC硬件合成。

第三,版本管理。SurfaceFlinger维护一个全局的"合成版本号"(可以通俗理解为帧号),每次合成都会递增。这个版本号会回调给客户端,客户端根据它来判断自己提交的Buffer是否被消耗掉了、可不可以去拿新Buffer来画。

第四,与HAL层协作。SurfaceFlinger不直接操作屏幕硬件,所有和显示硬件相关的操作都通过HWC接口转交。这个设计让手机厂商可以在不修改上层逻辑的情况下,用自己的硬件实现来优化合成效率。

2.4 HAL层:HWC与Gralloc的分工合作

HWC(Hardware Composer)是显示硬件能力抽象层。它的核心价值是把一部分图层合成功耗从GPU卸载到显示硬件上。

举个例子,现在屏幕上有三个图层:游戏画面、状态栏、一个悬浮窗。传统方案是把三个图层都用GPU合成一张大图,再整体送给屏幕。但HWC的做法更聪明:它把图层信息直接发给显示控制器,让硬件在扫描输出的过程中实时叠加这三个图层。这样一来,GPU只需要处理真正需要合成的内容(甚至什么都不用处理),性能和功耗都能大幅优化。

Gralloc则是图形缓冲区分配器。它负责分配和管理所有的GraphicBuffer内存,这个名字是Graphics + Allocator的组合。它干的事包括:分配Buffer、做内存加锁解锁(lock/unlock)、处理Buffer的格式转换。

Gralloc一个容易踩坑的地方是内存格式(PixelFormat)。RGB565、RGBA8888、YUV420这些格式的内存排布完全不同,Buffer从生产者到消费者如果格式不匹配,轻则显示颜色怪异,重则直接花屏或者Crash。我见过不少人自定义相机预览流程时在格式上栽跟头,后面实战篇可以专门写一次。

用一张表来总结这几个核心组件的分工:

组件所在进程核心职责关键词
View/DisplayListApp进程描述界面内容测量、布局、绘制指令
Surface/BufferQueueApp/SF进程跨进程传递图像Buffer生产者、消费者、Buffer复用
WindowManagerServiceSystemServer管理窗口元数据与Z序窗口层级、焦点
SurfaceFlingerSystemServer图层合成与全局调度Vsync、合成、Layer
HWCHAL层硬件合成与显示输出显示器、合成器
GrallocHAL层图形缓冲区分配管理内存分配、格式

3. 核心机制详解:BufferQueue与VSYNC如何协同工作

3.1 BufferQueue的生产者/消费者模型

BufferQueue是Android图形栈里最精巧的设计之一,理解它基本就理解了Android图形传输的整个逻辑。

它是一个标准的生产者-消费者队列。生产者是应用侧的渲染线程,消费者是SurfaceFlinger,但这里有个很多人忽略的细节:队列本身是跨进程共享的。Buffer的Buffer句柄通过Binder传递,但Buffer对应的内存是一块共享内存(通过ashmem或ION分配),生产者和消费者访问的是同一块物理内存,因此不需要整块Buffer的拷贝。

BufferQueue的正常流程是这样的:生产者向队列请求一个空闲Buffer,拿到后把图形内容渲染进去,渲染完成就入队(queueBuffer)。消费者从队列里取出一个Buffer,读取内容去合成,用完了再归还给队列(releaseBuffer)。这套流程循环往复,Buffer在生产者、消费者之间周而复始地流转。

这个设计最妙的地方在于Buffer复用。正常情况下,队列里只有2到3个Buffer在循环使用,应用不是每次绘制都重新分配内存,而是循环利用已有Buffer。这样一来,内存分配和释放的开销被压到最低,内存碎片问题也大大缓解。

BufferQueue另一个关键特性是阻塞和丢弃策略。生产者在没有可用Buffer时会阻塞等待(这叫dequeueBuffer超时);消费者处理不过来时,BufferQueue会丢弃最旧的那个Buffer,保证显示的永远是最近一帧画面。这个丢弃策略对防止卡顿累积至关重要,它确保系统在重负载下会自动降低帧率而不是无限积压导致界面彻底卡死。

我在实际调试中经常看到的一个现象是:游戏帧率忽高忽低,用systrace一抓,发现BufferQueue在大量丢帧。这通常说明游戏侧每帧的生产速度已经超过SurfaceFlinger的消费能力,常见原因是合成功耗过大或GPU渲染超时,这时候优化点应该放在减少过度绘制和降低渲染分辨率上,而不是盲目调帧率。

3.2 VSYNC:整个显示系统的节拍器

没有节奏的协作就是混乱。屏幕扫描输出是有固定频率的,如果应用随便什么时候往Buffer里写数据,画面很可能出现撕裂——上一半是旧帧,下一半是新帧。VSYNC机制就是来解决这个问题的。

VSYNC(Vertical Synchronization,垂直同步)是显示屏扫描到一帧末尾时发出的脉冲信号,它标志着现在可以安全地切换显示内容了。Android的SurfaceFlinger会监听这个信号,并把它作为一个全局同步节拍广播出去。

这个同步节拍会影响三个环节:

应用侧,Choreographer收到VSYNC之后,才会回调doFrame(),触发新一轮的measure/layout/draw。这样保证了所有应用绘制动作都在同一个节奏上启动,不会有人在屏幕扫描的一半突然改画面。

合成侧,SurfaceFlinger收到VSYNC后,集中处理收到的所有新Buffer,统一提交合成。合成结果赶在下一个VSYNC到来之前送出,正好赶上屏幕的下一帧扫描。

渲染侧,GPU的渲染指令提交也会尽量对齐VSYNC,避免渲染结果在屏幕扫描中途才完成。

这套机制保证了所有工作都是"屏幕上显示完第N帧之后,大家才开始动手准备第N+1帧"。有人会担心VSYNC会限制性能,比如游戏明明能跑200帧,却被锁在60帧。实际情况是Android有一套动态刷新率管理机制,高帧率模式下系统会使用更短的VSYNC周期,游戏如果能持续产出高帧率,系统并不会强行卡在60Hz。

3.3 为什么要搞三重缓冲

很多做性能优化的人一聊到三重缓冲就只知道"减少卡顿",但具体怎么减少、为什么需要第三块Buffer,很多人说不清楚。

用场景来解释最方便。先假设我们只有双缓冲:Buffer A和Buffer B。屏幕显示的是A,应用正在往B里渲染。如果应用在A还被屏幕占着的时候就渲染完了B,它必须等屏幕释放A才能继续画,这个等待时间就是空闲。在VSYNC节奏下,应用在VSYNC到来时才能swap——交换显示Buffer,于是中间必然出现一个VSYNC周期的空档期,也就是掉一帧。

三重缓冲加了一块Buffer C。应用在B渲染完后,如果A还被屏幕占着,它可以继续往C里渲染。正常情况下这么一来,屏幕在A结束后可以立刻切到B,应用刚好画完了C,整个管线一直有活干,不出现空闲。理论上讲,三重缓冲把"一次偶发的慢帧"吸收掉了,避免它变成"连续两帧的掉帧"。

但三重缓冲不是万能的。它本质上只能吸收"应用渲染偶尔慢了一次"的抖动,如果应用每帧的渲染耗时都超过VSYNC周期,就算有十重缓冲也无济于事,系统只会稳定掉帧到某个低帧率。而且三重缓冲会增加Buffer内存占用,大分辨率下三块Buffer的内存开销是实打实的,系统不太可能在所有场景都无脑开三重缓冲。Android的做法是根据屏幕刷新率和应用的实际帧率动态调整Buffer数量,SurfaceFlinger侧对没有性能需求的窗口会倾向于减少缓冲数来省内存。

4. 实操:从现实角度观测显示链路

4.1 开发者选项里的GPU渲染分析怎么用

很多人知道开发者选项里有"GPU渲染分析"这个功能,但真正用好的不多。这个工具用柱状图直观展示每帧渲染耗时,是快速定位卡顿因素的第一把手术刀。

开启路径是:设置 → 开发者选项 → 调试GPU过度绘制/GPU渲染分析。用Profile GPU Rendering里的"在屏幕上显示为条形图"选项,界面上每根柱状图代表一帧,不同颜色代表不同阶段。通常来说:

深蓝色是测量/布局时间,浅蓝色是绘制DisplayList的时间,红色是RenderThread等待GPU执行的时间,橙色是提交Buffer到SurfaceFlinger排队的时间。

如果红色特别高,说明应用渲染指令过于复杂,GPU负载太大,需要优化shader或者减少绘制元素。如果橙色特别高,说明SurfaceFlinger那边处理不过来,可能是合成图层太多或者系统整体负载高。

这个工具最大的价值是帮你判断瓶颈在应用侧还是系统侧。我遇到很多人一卡顿就怀疑是自家代码有问题,各种优化布局缓存列表,结果用这个工具一试发现深蓝和浅蓝都正常,红色超高,其实是GPU密集型效果太多导致的。方向错了,怎么优化都白搭。

4.2 使用dumpsys SurfaceFlinger分析图层状态

想要更精细地观察图层合成情况,最硬核的方式是直接dump SurfaceFlinger状态。打开终端执行:

adb shell dumpsys SurfaceFlinger

这条命令会输出大量系统图形状态信息,重点看这几个部分。

Display Device段落会列出当前有哪几个显示设备,分辨率、刷新率各是多少。如果做过模拟显示或投屏,这里能看到多个DisplayDevice。

Layer列表是最核心的,它列出每个窗口图层的名称、类型、Z序、区域大小、Transform变化等。检查这个列表可以快速确认某个窗口有没有异常地跑到屏幕外、或者Z序被错误地抬高导致遮挡。

BufferQueue状态部分能看每个队列的当前Buffer数、是否满、是否在等待,判断生产者和消费者协作是否正常。

实际排查案例:一次遇到某App打开后整个系统界面都变卡,先用dumpsys SurfaceFlinger发现一个异常Layer尺寸非常大且带有半透明效果,Z序还特别高,显然这个App每帧都要做超大面积的透明混合。定位到它后,让App方修复了绘制区域控制问题,流畅度立刻恢复。这就是这个命令的实战价值。

4.3 用Systrace抓取完整帧链路

如果要看一帧从应用到合成的完整时间线,Systrace(新版本叫Perfetto)是标准工具。抓取时需要带上graphics相关的tag:

python systrace.py --time=10 -a 你的应用包名 -b 16384 gfx view wm am res dalvik hal idle sched freq

抓完之后,在Perfetto UI里打开trace文件,重点看这几个关键时间点:

App侧的Choreographer#doFrame标记说明UI线程开始处理帧;DrawFrames里RenderThread的工作段标注了渲染耗时;BufferQueue的queueBuffer调用点标注了生产者提交时间;SurfaceFlinger侧的onMessageReceived和composite标注了合成耗时;再往后的HWC present则代表已经提交给硬件扫描了。

把这几个时间点在时间线上对齐之后,就能清楚判断一帧的时间到底花费在哪个环节。如果发现App RunFrame到queueBuffer间隔很大,说明App自己渲染慢;如果queueBuffer之后到SF composite间隔很大,说明跨进程传输或者SF调度慢;如果composite到present间隔大,说明HWC或屏幕硬件处理慢。

这套方法定位过很多疑难杂症。印象最深的一次:某App在低端机上掉帧特别严重,从trace里看App侧渲染时间很正常,但每个frame在SF合成前都要等大概20ms,后来发现是因为该App创建了大量小图层,SF每次都要遍历几百个Layer做可见性判断。优化方案是让该App合并图层,掉帧问题直接消失。

4.4 SurfaceView与TextureView的取舍

写到这里,必须提一下SurfaceView这个特殊的存在。它和普通View最大的区别是:SurfaceView的Surface不参与App进程的View绘制,而是走独立通道直达BufferQueue。

这意味着SurfaceView的内容不需要经历UI线程的measure/layout/draw流程,也不需要通过DisplayList,它直接由App自己创建的渲染线程往Buffer里画,效率极高。所以视频播放、相机预览、游戏画面这些对性能和延迟敏感的场景,几乎都用SurfaceView。

但SurfaceView有个麻烦:它的Surface在WindowManager那边的层级比较特殊,做动画、加圆角、加阴影这些View体系的能力在SurfaceView上都不能直接用。TextureView就是为了解决这个限制出现的,它能像普通View一样做变换,但代价是CPU拷贝开销更大,性能不如SurfaceView。

选型建议很直接:需要频繁更新的视频/相机内容用SurfaceView,需要做复杂动画的内容用TextureView,普通列表界面用普通View体系就足够了。这三者选错了,很容易出现要么卡顿掉帧、要么功能受限的问题。

5. 显示相关的经典问题排查思路

5.1 画面撕裂与VSYNC异常

画面撕裂是最直观的显示异常:屏幕上出现一条水平分界线,线上方和下方的内容不一样,通常是画面在滚动或游戏中特别明显。

传统原因是VSYNC没有生效或应用自己关闭了垂直同步设置。在Android高版本上,系统强制所有窗口都走VSYNC合成,所以应用层的撕裂已经很少见了。如果你还是遇到撕裂,大概率是视频播放器或游戏用的Surface在HWC层路径有异常,可能和HWC的合成策略、Buffer分配格式不匹配有关。

App侧的排查方向是检查有没有自定义的Surface分配逻辑,确认Buffer格式(format)和SurfaceFlinger期望的格式一致。系统侧的排查方向是dumpsys SurfaceFlinger看是否有Layer缺失VSYNC回调,这种问题多见于深度定制ROM的驱动适配不完整,需要走HAL层排查。

5.2 黑屏和闪烁:让无数人崩溃的问题

黑屏的成因太多了,最常见的有这几类:

应用侧动画卡死导致黑屏——通常是因为View在动画过程中频繁操作Surface,触发了Surface的destroy/relayout。解决思路是检查代码里是否在动画过程中调用了setVisibility或者尺寸变化,有时候一个View的if (isAttachedToWindow())判断就能避免大量问题。

SurfaceView全屏切换闪黑——这是SurfaceView的天然特性,因为它的Surface在窗口切换时会经历detach/attach过程,中间会黑一帧。业界通行做法是使用带有黑色背景的View掩盖这个过渡过程,或者使用TextureView来彻底避免这个切换闪烁问题。

应用侧导致系统级黑屏——这个问题比较棘手,表现是某个App启动瞬间整个系统黑屏一下。通常是因为这个App在某些系统版本上创建了带特殊标志(FLAG_SECURE)的窗口,或者Surface合成时出现Fence同步问题。遇到这种情况,先抓取kernel log,重点查MSM/DPU/HDMI驱动的warning信息。

闪烁有时候会给人"坏屏"的错觉,但逻辑排查之后大部分还是软件问题。一个容易忽略的地方是刷新率切换。部分手机在低亮度、低刷新率切换时会短暂闪烁,这种通常属于硬件特性,正常使用不会太影响体验,但如果高频触发,就要考虑系统显示栈是否频繁在切换显示模式了。

5.3 过度绘制:最常见的性能杀手

过度绘制(Overdraw)是指屏幕上同一个像素在多个图层间被重复绘制了很多次。系统开发者选项里自带"调试GPU过度绘制"的开关,开启后界面会变色,颜色从蓝、绿、淡红到深红代表过度绘制逐渐严重。

定位过度绘制主要靠UI层级分析:一个Activity里嵌套多层的FrameLayout、半透明背景层层叠加、ImageView没做圆角裁剪还带半透明遮罩,这些都是重灾区。

解决思路通常几板斧:去掉嵌套布局中冗余的背景色(这是最立竿见影的),用ViewStub懒加载非首屏内容,统一窗口背景色而不是每个View都设背景,复杂圆角场景直接考虑用GPU离屏渲染代替多层View叠加。

但也不建议把过度绘制看成绝对的罪恶。有些效果(如模糊、阴影、渐变)天然就需要多层绘图,强行干掉反而得不偿失。正确标准是"正常区域不发红",而不是追求全屏蓝色。

5.4 掉帧问题排查速查表

真实项目里排查掉帧问题,先按表格快速对号入座,大多数情况能省不少时间:

现象优先排查方向常用工具
列表滑动掉帧列表项布局复杂度过高、图片加载频繁Profile GPU Rendering、Perfetto
动画过程掉帧UI线程被耗时操作阻塞、动画频繁触发重绘Choreographer帧数统计
游戏场景掉帧GPU负载过高、BufferQueue排队过深dumpsys SurfaceFlinger、GPU profiler
多窗口分屏掉帧图层数量过多、HWC合成压力大dumpsys SurfaceFlinger
视频播放卡顿Surface格式不匹配、解码器输出帧率不足dumpsys media.player、Perfetto
随机偶发掉帧系统服务抖动、App其他线程抢占CPUPerfetto长时抓取

6. 理解这套框架之后,能带来什么实际价值

学习这套显示框架最直接的好处就是:遇到问题不再靠玄学,做方案不再凭感觉。

性能优化的时候,你知道了卡顿瓶颈要么在App自己的渲染阶段,要么在BufferQueue排队,要么在SurfaceFlinger合成,要么在HWC提交,四段定位下来目标就很明确。比如你之前可能只会盯着内存和CPU看,现在你知道了还有一个组成合成功耗的大头。

代码设计的时候,你知道了某些效果适合用View实现,某些适合用Canvas离屏绘制,某些干脆该用GPU Shader。这种判断力是做过深度优化的人和普通开发者的分水岭。

做Framework或者系统定制的时候,你知道了每个显示组件的边界在哪,什么改动会牵动什么模块。改SurfaceFlinger的合成策略之前你会先掂量掂量HWC那边能不能接得住。

我自己当年啃这块内容的时候,最大的感受是资料多而杂,动不动就陷到某个HAL函数或者某段驱动代码里出不来。后来转变思路,先建立完整架构图,再逐个击破细节,效率明显提升。这个系列第一篇就是为了给还没入门的同学搭起这张架构图,后续会按实际经验的优先级慢慢拆。

下一篇文章我打算重点写BufferQueue的源码级解析,把dequeue/queue/acquire/release这条主流程彻底讲透,因为几乎所有显示性能问题的根源都能追溯到队列状态异常上。这块吃透了,再看SurfaceFlinger合成和HWC就顺理成章了。

如果你正在学Android图形栈,建议先别急着看源码,把我这篇文章里提到的组件和它们之间的调用关系在纸上画一遍,画不完整的部分就是你需要优先补课的地方。把整体框架刻在脑子里之后,再去看任何一篇深入分析某组件的文章,你都能知道它在整个链路里处于什么位置、要解决什么问题。这才是学显示系统最正确的姿势。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询