0%

Android图像系统之一

基于Android P源码分析,深入理解Android GUI的框架。

前言

Android图像系统框架比较复杂,涉及WindowManager、SurfaceFlinger、ActivityManager、InputManager等模块。因为笔者此前从事过底层显示驱动相关工作,期望通过梳理Android显示系统的框架构建完整的知识体系。

它们之间的关系如下:
GUI

图形框架

参考 https://source.android.com/devices/graphics

Android框架提供各种 2D 和 3D 图形渲染的 API,应用开发者可以通过 Canvas、OpenGL ES 和 Vulkan 三种方式将图像绘制到屏幕上。但无论开发者使用什么渲染 API,最终都会渲染到 Surface。Surface 表示缓冲队列中的生产者,每个 Window 都对应者一个或多个 Surface,而缓冲队列的消费者通常是 SurfaceFlinger,用以合成到显示部分,比如自身屏幕或者扩展屏幕。

Surface

  • IMAGE STREAM PRODUCERS: 可以生成图形缓冲区以供消耗的任何内容,比如OpenGL ES、Canvas 2D 和 mediaserver 视频解码器。

  • IMAGE STREAM CONSUMERS: 最常见的消费者就是 SurfaceFlinger,它是可以修改所显示部分内容的唯一服务,使用 OpenGL 和 Hardware Composer 来合成一组 Surface. 还有其他应用也可以作为消费者,比如相机应用和 ImageReader.

  • Hardware Composer: 作为显示子系统的硬件抽象层,完成SurfaceFlinger 合成显示的部分任务,以分担 OpenGL 和 GPU 的消耗。同时需要支持 Vsync Event 和 HDMI 的热插拔。

  • Gralloc HAL: 用来分配图像生产者所请求的内存。

数据处理

BufferQueue

左侧黄色部分为图像缓冲区的生产者,比如状态栏、菜单栏和主界面等。SurfaceFlinger 完成 Surface 的合成,Hardware Composer 操作硬件控制器显示。

BufferQueue

BufferQueue 是 Android 图像系统的重要组成部分,是缓冲区和队列结合的数据结构,通过Binder IPC在进程间传递。

BufferQueue2

上图描述了图像生产者和消费者的操作流程:

  • 生产者请求队列中空闲的缓冲区:dequeueBuffer()
  • 生产者填充缓冲区并添加到队列:queueBuffer()
  • 消费者从队列中获取缓冲区:acquireBuffer()
  • 消费者使用完毕返回给队列:releaseBuffer()

对应类图的关系如下:
BufferQueue3

SurfaceFlinger

SurfaceFlinger 是一个本地系统服务,用来合成应用绘制的 Surface,借助 Hardware Composer 显示到屏幕上。

[surfaceflinger.rc]

1
2
3
4
5
6
7
8
service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc
onrestart restart zygote
writepid /dev/stune/foreground/tasks
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0 socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s

[main_surfaceflinger.cpp]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
int main(int, char**) {
signal(SIGPIPE, SIG_IGN);

hardware::configureRpcThreadpool(1 /* maxThreads */,
false /* callerWillJoin */);

startGraphicsAllocatorService();

// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);

// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();

// instantiate surfaceflinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();

setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);

set_sched_policy(0, SP_FOREGROUND);

// Put most SurfaceFlinger threads in the system-background cpuset
// Keeps us from unnecessarily using big cores
// Do this after the binder thread pool init
if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);

// initialize before clients can connect
flinger->init();

// publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);

// publish GpuService
sp<GpuService> gpuservice = new GpuService();
sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);

startDisplayService(); // dependency on SF getting registered above

struct sched_param param = {0};
param.sched_priority = 2;
if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
ALOGE("Couldn't set SCHED_FIFO");
}

// run surface flinger in this thread
flinger->run();

return 0;
}

SurfaceFlinger 类继承于 BnSurfaceComposer,实现 ISurfaceComposer 本地接口。Android P 版本从 SurfaceFlinger 类中拆分出 SurfaceFlingerBE,实现前后端分离,前端和上层进行交互,后端 SurfaceFlingerBE 和底层硬件合成进行交互。

1
2
3
4
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback

具体的类图关系如下图:

后面我们将以 SurfaceFlinger 为主线,结合源代码进行情景分析,梳理整个图像系统。

  • WindowManager: 首先需要知道 Surface 是由谁创建的?是如何绘制和更新的,窗口的动画切换是怎样做的?窗口的显示和隐藏是如何控制的?
  • SurfaceFlinger: Surface 使用的图像缓冲区是什么时候创建、管理和销毁的?多个 Surface 是如何合成的?如何实现多屏显示的?
  • Activity: Activity 的生命周期是怎样的?
  • InputManager: 底层按键事件是如何上报到Android系统的,又是如何到具体的窗口进行处理的?