一、什么是SurfaceFlinger
SurfaceFlinger 是 Android 系统的核心系统服务之一,负责合成和显示所有图形界面内容。它作为系统级图形合成引擎,接收来自各个应用和系统组件的图形缓冲区(如 SurfaceView、TextureView、系统UI等),通过 GPU 硬件加速 将这些独立的图形层合成为最终的屏幕显示图像,并精确控制帧率同步(VSync)、窗口层级管理、动画渲染和多屏显示等关键功能,确保整个系统的流畅、无撕裂的视觉体验。
二、SurfaceFlinger服务启动和初始化
当系统内核启动第一个用户空间进程init进程后,init进程解析init.rc文件来启动一些必要的系统服务,其中包含:
...
on boot
...
class_start core
...class_start core表示启动所有类别属于core的服务,那我们在看下surfaceflinger.rc文件:
service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc
capabilities SYS_NICE
onrestart restart --only-if-running zygote
task_profiles HighPerformance我们可以看到 class core animation,说明surfaceflinger属于系统核心组同时也属于动画服务组,所以这里我们就可以知道init进程会在系统启动的时候启动core组成员之一的surfaceflinger服务。
那么我们来看下SurfaceFlinger进程对应的类的入口在哪里,怎么看呢,我们可以找到AOSP中SurfaceFlinger模块,找到模块中的frameworks/native/services/surfaceflinger/Android.bp这个文件:
...
filegroup {
// 看命名可以知道是surfaceflinger二进制文件对应的源码文件
name: "surfaceflinger_binary_sources",
srcs: [
":libsurfaceflinger_sources",
// 入口在这个文件中
"main_surfaceflinger.cpp",
],
}
...SurfaceFlinger被编译生成的二进制文件对应的源码上面说的很清楚了,所以我们知道进程的启动入口就是在类main_surfaceflinger.cpp文件中的main()函数:

int main() {
// 对于SIGPIPE信号,选择忽略(SIG_ING)
// SIGPIPE信号可能是连接surfaceflinger的APP异常退出的时候系统发出此信号
// 这里选择忽略,避免surfaflinger服务被影响kill掉
signal(SIGPIPE, SIG_IGN);
//
hardware::configureRpcThreadpool(1 /* maxThreads */,
false /* callerWillJoin */);
// 核心流程1:
startGraphicsAllocatorService();
// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);
// Set uclamp.min setting on all threads, maybe an overkill but we want
// to cover important threads like RenderEngine.
SurfaceFlinger::setSchedAttr(true, __func__);
// The binder threadpool we start will inherit sched policy and priority
// of (this) creating thread. We want the binder thread pool to have
// SCHED_FIFO policy and priority 1 (lowest RT priority)
// Once the pool is created we reset this thread's priority back to
// original.
int newPriority = 0;
int origPolicy = sched_getscheduler(0);
struct sched_param origSchedParam;
int errorInPriorityModification = sched_getparam(0, &origSchedParam);
if (errorInPriorityModification == 0) {
int policy = SCHED_FIFO;
newPriority = sched_get_priority_min(policy);
struct sched_param param;
param.sched_priority = newPriority;
errorInPriorityModification = sched_setscheduler(0, policy, ¶m);
}
// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
// Reset current thread's policy and priority
if (errorInPriorityModification == 0) {
errorInPriorityModification = sched_setscheduler(0, origPolicy, &origSchedParam);
} else {
ALOGE("Failed to set SurfaceFlinger binder threadpool priority to SCHED_FIFO");
}
// 核心流程2:
// instantiate surfaceflinger
sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
// Set the minimum policy of surfaceflinger node to be SCHED_FIFO.
// So any thread with policy/priority lower than {SCHED_FIFO, 1}, will run
// at least with SCHED_FIFO policy and priority 1.
if (errorInPriorityModification == 0 &&
!FlagManager::getInstance().disable_sched_fifo_sf_binder()) {
flinger->setMinSchedulerPolicy(SCHED_FIFO, newPriority);
}
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
set_sched_policy(0, SP_FOREGROUND);
// 核心流程3:
// initialize before clients can connect
flinger->init();
// 核心流程4:
// publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
// publish gui::ISurfaceComposer, the new AIDL interface
sp<SurfaceComposerAIDL> composerAIDL = sp<SurfaceComposerAIDL>::make(flinger);
if (FlagManager::getInstance().misc1() &&
!FlagManager::getInstance().disable_sched_fifo_composer()) {
composerAIDL->setMinSchedulerPolicy(SCHED_FIFO, newPriority);
}
// 核心流程5:
sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
startDisplayService(); // dependency on SF getting registered above
SurfaceFlinger::setSchedFifo(true, __func__);
// 核心流程6:
flinger->run();
}核心流程步骤:
- startGraphicsAllocatorService();启动图形内存分配服务,是Android图形系统中的核心服务,负责分配缓存图片帧的内存
,首先通过读取系统配置属性判断是否禁用服务,若禁用直接返回,然后通过Passthrough的模式(独立进程,不依赖于SurfaceFlinger)开始注册Gralloc V3.0服务(HIDL服务),若失败则降级注册V2.0服务:
static status_t startGraphicsAllocatorService() {
using android::hardware::configstore::getBool;
using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
// 读取系统配置属性,是否禁用图形内存分配服务,如果禁用直接返回
if (!android::sysprop::start_graphics_allocator_service(false)) {
return OK;
}
// 通过Passthrough的模式注册Gralloc V3.0服务
status_t result = hardware::registerPassthroughServiceImplementation<
android::hardware::graphics::allocator::V3_0::IAllocator>();
if (result == OK) {
return OK;
}
// 如果Gralloc V3.0注册失败,降级为注册Gralloc V2.0服务
result = hardware::registerPassthroughServiceImplementation<
android::hardware::graphics::allocator::V2_0::IAllocator>();
if (result != OK) {
ALOGE("could not start graphics allocator service");
return result;
}
return OK;
}
Gralloc服务就是位于硬件抽象层(HAL)提供给上层(SurfaceFlinger等)封装好统一管理图形缓存内存的接口,对于不同硬件其不同的实现对上层隔离,是图形系统中重要的一环,在初始化SurfaceFlinger的时候先注册好Gralloc服务做好准备工作(因为后续的处理图像都需要依赖这个服务分配实际的内存空间)。
- surfaceflinger::createSurfaceFlinger();
sp<SurfaceFlinger> createSurfaceFlinger() {
static DefaultFactory factory;
return sp<SurfaceFlinger>::make(factory);
}通过工厂类SurfaceFlingerFactory实例化一个SurfaceFlinger对象。
- flinger->init();

设计特点
异步初始化 :大量使用异步操作避免阻塞主线程
错误处理 :关键步骤使用 LOG_ALWAYS_FATAL_IF 确保初始化失败时系统崩溃
性能优化 :预加载着色器、异步属性设置
分层架构 :RenderEngine、HWComposer、Scheduler等组件解耦
实时性保证 :渲染线程设置为实时优先级
这个init()函数完成了从GPU初始化到显示设备配置,从VSync调度到电源管理的全方位系统初始化,使SurfaceFlinger成为功能完整的系统服务。
- sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
- sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
这里为什么添加两个服务到ServiceManager中呢?这里主要是考虑新老版本的兼容问题,对于老的版本还是通过手动写binder通信(第一种方式),需要将flinger服务添加进去,对于新的支持使用API更丰富的AIDL的方式调用(第二种)。AOSP中已经将一些旧的手动binder重构成AIDL的方式,下面我们看一些AOSP中常用模块这两者的占比情况的统计数据:
模块 | AIDL使用 | 手动Binder | 主要原因 |
SurfaceFlinger | 20% | 80% | 性能关键 |
AudioFlinger | 30% | 70% | 实时音频 |
CameraService | 40% | 60% | 复杂数据结构 |
SystemServer | 90% | 10% | 系统服务 |
看的出来一些模块AOSP已经在往新的AIDL这种形式迁移,但是在有些场景还是需要手动写Binder通信,比如对性能要求高,需要修改通信过程中的细节,有些复杂数据结构参数需要传递,AIDL还不能做的得用手动的方式。举个不恰当的例子:AOSP中的IPC像一辆精心调校的赛车——AIDL是自动挡,手动Binder是手动挡,在不同场景选择最合适的档位才能发挥最佳性能和最佳开发效率。
- flinger->run();
void Scheduler::run() {
while (true) {
waitMessage();
}
}void MessageQueue::waitMessage() {
do {
IPCThreadState::self()->flushCommands();
int32_t ret = mLooper->pollOnce(-1);
switch (ret) {
case Looper::POLL_WAKE:
case Looper::POLL_CALLBACK:
continue;
case Looper::POLL_ERROR:
ALOGE("Looper::POLL_ERROR");
continue;
case Looper::POLL_TIMEOUT:
// timeout (should not happen)
continue;
default:
// should not happen
ALOGE("Looper::pollOnce() returned unknown status %d", ret);
continue;
}
} while (true);
}这里看起来比较有意思,居然有两个嵌套的死循环。为什么会这么写?读者也可以思考一下,本人的一点看法是第一个死循环是保证Scheduler这个线程能一直跟随系统存活(作为图形系统关键的一环),第二个死循环是消息事件的业务逻辑,保证一直能监听到事件消息,当前看起来外层的Scheduler的死循环是冗余的,因为去掉Scheduler的循环,由于waitMessage中会开启死循环,也能保证Scheduler线程持续存活。这里可能是历史代码问题,又或者是一种保护设计,万一后面waitMessage函数的业务逻辑不再是无限循环而影响图形系统的调度模块Scheduler的存活。大家也可以发表下对于这里为什么使用两个嵌套的死循环的看法。
三、SurfaceFlinger合成过程
前面的一篇文章中也略微讲过合成的过程,这里从SurfaceFlinger启动开始来理一下这个逻辑过程。当Scheduler开启死循环监听事件消息后,具备监听Vsync信号的能力。当Vsync-sf信号到来时,MessageQueue.cpp中的vsyncCallback()函数:
void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
SFTRACE_CALL();
// Trace VSYNC-sf,相当与可以可视化VSync信号,0-1交替变化
mVsync.value = (mVsync.value + 1) % 2;
// 记录vsync发生的时间
const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime);
{
std::lock_guard lock(mVsync.mutex);
mVsync.lastCallbackTime = expectedVsyncTime;
mVsync.scheduledFrameTimeOpt.reset();
}
// 每一次Vsync生成一个唯一的ID
const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
{targetWakeupTime, readyTime, vsyncTime})};
// 将Vync的时间和ID分发下去
mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
}mHandler->dispatchFrame(vsyncId, expectedVsyncTime);通过MessageQueue.cpp中的Handler分发:
void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) {
if (!mFramePending.exchange(true)) {
mVsyncId = vsyncId;
mExpectedVsyncTime = expectedVsyncTime;
mQueue.mLooper->sendMessage(sp<MessageHandler>::fromExisting(this), Message());
}
}通过Looper发送消息,触发waitMessage中的阻塞监听消息被唤醒(有消息要处理),looper调用handleMessage函数,继续调用到mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime);mQueue的实现为Scheduler.cpp,所以调到:
void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
TimePoint expectedVsyncTime) {
...
ftl::NonNull<const Display*> pacesetterPtr = pacesetterPtrLocked();
pacesetterPtr->targeterPtr->beginFrame(beginFrameArgs, *pacesetterPtr->schedulePtr);
{
...
// 合成准备阶段,将本帧所有的信息提交给合成器
if (!compositor.commit(pacesetterPtr->displayId, targets)) {
if (FlagManager::getInstance().vrr_config()) {
compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
}
mSchedulerCallback.onCommitNotComposited();
return;
}
}
...
// 实际进行合成操作的入口
const auto resultsPerDisplay = compositor.composite(pacesetterPtr->displayId, targeters);
compositor.sample();
for (const auto& [id, targeter] : targeters) {
...
targeter->endFrame(*resultOpt);
}
}compositor.commit(pacesetterPtr->displayId, targets),commit函数的主要工作:
- 收集和整理本帧所有需要显示的内容(比如每个 Layer 的缓冲区、变换、透明度等)。
- 将这些内容传递给合成引擎(CompositionEngine),为后续的合成做准备。
- 可能会进行一些前置检查,比如判断哪些 Layer 需要合成、哪些可以跳过、是否有内容变化等。
- 为后续的合成(composite)做准备,比如分配合成缓冲区、设置合成参数等。
为什么先commit呢?
- 分离准备和执行:commit 主要是“准备”阶段,收集和锁定所有本帧需要用到的资源和数据,确保在真正合成(composite)时不会被其他线程或事务打断。
- 保证一致性:在多线程环境下,commit阶段可以保证所有Layer的状态在本帧合成时是原子一致的。
- 性能优化:有些 Layer 可能没有变化,commit 阶段可以提前判断,减少不必要的合成操作。
就是把本帧所有要显示的内容和目标,提交给合成器,为后续的实际合成(composite)做准备。
它是 VSYNC 驱动的 SurfaceFlinger 合成流程中的“准备阶段”核心入口。
compositor.composite(pacesetterPtr->displayId, targeters),这里的compositor的实现就是SurfaceFlinger,在SurfaceFlinger的composite函数中实际是通过调用CompositionEngine->present()函数:
void CompositionEngine::present(CompositionRefreshArgs& args) {
SFTRACE_CALL();
ALOGV(__FUNCTION__);
// 1、合成前预处理
preComposition(args);
{
// latchedLayers is used to track the set of front-end layer state that
// has been latched across all outputs for the prepare step, and is not
// needed for anything else.
LayerFESet latchedLayers;
// 2、遍历调用各output(输出设备)的prepare,确定各输出设备的图层Z-Order顺序
for (const auto& output : args.outputs) {
output->prepare(args, latchedLayers);
}
}
// Offloading the HWC call for `present` allows us to simultaneously call it
// on multiple displays. This is desirable because these calls block and can
// be slow.
// 3、负载卸载到异步线程处理多输出设备场景
offloadOutputs(args.outputs);
ui::DisplayVector<ftl::Future<std::monostate>> presentFutures;
for (const auto& output : args.outputs) {
// 4、合成的核心操作
presentFutures.push_back(output->present(args));
}
{
SFTRACE_NAME("Waiting on HWC");
for (auto& future : presentFutures) {
// TODO(b/185536303): Call ftl::Future::wait() once it exists, since
// we do not need the return value of get().
future.get();
}
}
// 5、释放缓存
postComposition(args);
}1、首先调用preComposition函数进行合成前的预处理动作
具体到函数里面会遍历所有的图层layer,调用layer->onPreComposition()函数在即将合成前做一次检查,判断是否有新内容更新,如果有新内容更新就停止当前不必要的合成动作,避免浪费资源。
根据调用链来跟进源码:
CompositionEngine::present()
└─ preComposition()
└─ layer->onPreComposition() [LayerFE层]
└─ 检查hasReadyFrame状态
void CompositionEngine::preComposition(CompositionRefreshArgs& args) {
SFTRACE_CALL();
ALOGV(__FUNCTION__);
bool needsAnotherUpdate = false;
mRefreshStartTime = args.refreshStartTime;
for (auto& layer : args.layers) {
if (layer->onPreComposition(args.updatingOutputGeometryThisFrame)) {
needsAnotherUpdate = true;
}
}
mNeedsAnotherUpdate = needsAnotherUpdate;
}bool LayerFE::onPreComposition(bool) {
return mSnapshot->hasReadyFrame;
}hasReadyFrame来自复杂的状态判断链:
bool RequestedLayerState::hasReadyFrame() const {
return hasFrameUpdate() || changes.test(Changes::SidebandStream) || autoRefresh;
}三个条件满足其一即为true:
- hasFrameUpdate: 新的纹理内容更新或者背景的颜色更新
- changes.test(Changes::SidebandStream):有新的sideBand流更新(视频帧更新)
- autoRefresh:动画更新
2、output->prepare(args, latchedLayers);
确定各输出设备的图层序列,
void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
LayerFESet& geomSnapshots) {
SFTRACE_CALL();
ALOGV(__FUNCTION__);
rebuildLayerStacks(refreshArgs, geomSnapshots);
uncacheBuffers(refreshArgs.bufferIdsToUncache);
}rebuildLayerStacks函数发起图层序列栈的重建工作,根据Z-Order的顺序。
uncacheBuffers函数清理不再使用的缓冲区,避免内存浪费
3、offloadOutputs(args.outputs);负载卸载压力
offload 可以理解为给主线程卸载部分压力到异步线程处理,具体到本函数的场景中,针对多输出屏幕设备的场景,判断输出设备是否具备硬件加速以及多线程present的条件,使用多线程卸载主线程的压力,进行多线程并发present操作。这个函数通过这些判断来标记是否支持offload。
设计核心思想和优化收益:
- 并发性能优化
问题: HWC的present调用是阻塞的,多显示器顺序处理延迟高
解决方案: 将不同显示器的present操作并行化
收益: 显著减少多显示器场景下的总延迟 - 智能资源管理
主线程保留策略: 避免主线程空闲,实现真正并发而非简单的任务分发
工作线程复用: HwcAsyncWorker在帧间保留,避免频繁创建销毁
按需分配: 只在需要时创建异步工作线程 - 兼容性保证
全有或全无策略: 确保所有显示器都支持多线程present
能力检查: 区分HWC和客户端合成,针对性优化
特性开关: 通过multithreaded_present()标志控制功能启用 - 安全的异步设计
每帧重置: mOffloadPresent每帧重置,避免状态泄露
Future同步: 使用ftl::Future确保所有异步操作完成异常安全: 异步操作的异常会传播到主线程
4、多线程执行present操作
ui::DisplayVector<ftl::Future<std::monostate>> presentFutures;
for (const auto& output : args.outputs) {
// 4、合成的核心操作
presentFutures.push_back(output->present(args));
}这里的ftl::Future是专门为Android系统高性能异步操作设计的,这里就可以根据Output是否支持offload进行异步执行,加快执行的速度。
当循环执行的时候,
- 立即启动所有present操作:每次output->present(args)调用都会立即开始该显示器的present流程
- 收集Future句柄:将每个操作的Future对象保存到presentFutures容器中
- 混合处理模式:根据mOffloadPresent标志决定同步还是异步执行
核心实现机制:
ftl::Future<std::monostate> future;
const bool flushEvenWhenDisabled = !refreshArgs.bufferIdsToUncache.empty();
if (mOffloadPresent) {
future = presentFrameAndReleaseLayersAsync(flushEvenWhenDisabled);
mOffloadPresent = false;
} else {
presentFrameAndReleaseLayers(flushEvenWhenDisabled);
future = ftl::yield<std::monostate>({});
}并发执行时序分析:

Future模式的关键设计优势
- 统一的返回接口,无论是异步还是同步
- 非阻塞启动模式,循环中所有的启动几乎同时开启
延迟同步点:分离启动和等待,先启动所有操作再统一等待,最优等待时间≈max(各显示器present的时间)
{
SFTRACE_NAME("Waiting on HWC");
for (auto& future : presentFutures) {
future.get();
}
}以上是针对使用Future模式的一些分析,具体到执行单个输出设备的present操作:
ftl::Future<std::monostate> Output::present(
const compositionengine::CompositionRefreshArgs& refreshArgs) {
// 1. 更新颜色配置
updateColorProfile(refreshArgs);
// 2. 更新合成状态
updateCompositionState(refreshArgs);
// 3. 规划合成策略
planComposition();
// 4. 写入合成状态到HWC
writeCompositionState(refreshArgs);
// 5. 设置颜色变换
setColorTransform(refreshArgs);
// 6. 开始帧合成前的判断,是否有脏区域(内容变化)以及是否图层不为空并且上一次合成的时候图层也不是空
// 以上条件均满足的时候合成,否则不做合成
beginFrame();
// 7. 准备帧(决策GPU vs HWC合成)
if (predictCompositionStrategy) {
result = prepareFrameAsync();
} else {
prepareFrame();
}
// 8. 完成帧GPU合成
finishFrame(std::move(result));
// 9. HWC合成+混合+提交到显示器并释放资源
if (mOffloadPresent) {
future = presentFrameAndReleaseLayersAsync(flushEvenWhenDisabled);
} else {
presentFrameAndReleaseLayers(flushEvenWhenDisabled);
future = ftl::yield<std::monostate>({});
}
return future;
}GPU合成帧的关键操作在finishFrame()函数,其逻辑流程如下:

presentFrameAndReleaseLayers执行HWC合成和提交帧,流程如下所示:

小结:
CompositionEngine::present()
├── preComposition() // 预处理
├── output->prepare() // 准备输出
├── offloadOutputs() // 多线程卸载
├── output->present() // 呈现输出
│ ├── updateColorProfile() // 更新颜色配置
│ ├── updateCompositionState() // 更新合成状态
│ ├── planComposition() // 规划合成
│ ├── writeCompositionState() // 写入状态
│ ├── setColorTransform() // 设置颜色变换
│ ├── beginFrame() // 开始帧
│ ├── prepareFrame() // 准备帧
│ ├── finishFrame() // 完成帧
│ └── presentFrameAndReleaseLayers() // 呈现帧并释放层
│ ├── presentFrame() // 呈现帧
│ │ ├── impl::Output::presentFrame() // 基类实现
│ │ └── hwc.presentAndGetReleaseFences() //HWC调用
│ └── onPresentDisplayCompleted() // 呈现完成通知
└── postComposition() // 后处理四、总结
SurfaceFlinger如同Android图形的“交响乐指挥家”,以VSync为节拍器,调度GPU/HWC多乐器协奏。其精妙的异步架构、双循环线程模型、Future并发控制,共同奏响了60FPS流畅体验的乐章。每一次像素点亮背后,都是对实时性、原子性、高效性的极致追求——这,就是Android图形系统的灵魂所在。
最后给大家上一波整个图形子系统的分层设计,本文基于最新AOSP源码分析,


3516

被折叠的 条评论
为什么被折叠?



