[TOC]

文章转自:https://source.android.google.cn/devices/graphics

文章转自:https://juejin.cn/post/6944960866404007944

概述

Surface可以简单的理解成一块画布,在Android的Activity中,UI的显示就是通过把图形绘制在Surface对象上完成的。每个Surface对象在SurfaceFlinger中都有对应的图像层(Layer),SurfaceFlinger会把所有图像层混合在一起并输出到Framebuffer中,这样在屏幕上就看到最后合成的图像。

应用开发中很少直接使用Surface,因为每个Activity中已经创建好了各自的Surface对象,通常只有一些特殊的应用才需要在Activity之外再去创建Surface,例如照相机应用、视频播放应用。通常这些应用也是通过创建SurfaceView来使用Surface。在应用中不能直接去创建一个可用的Surface对象,或者说直接创建出来的Surface对象也没有实际的用途,因为这样创建出的Surface对象和SurfaceFlinger之间没有关联。

无论开发者使用什么渲染 API,一切内容都会渲染到 Surface 上。Surface 表示缓冲区队列中的生产方,而缓冲区队列通常会被 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 Surface 提供支持。所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕。

下图显示了关键组件如何协同工作:

img

主要组件如下所述:

图像流生产方

图像流生产方可以是生成图形缓冲区以供消耗的任何内容。例如 OpenGL ES、Canvas 2D 和 mediaserver 视频解码器。

图像流消耗方

图像流的最常见消耗方是 SurfaceFlinger,该系统服务会消耗当前可见的 Surface,并使用窗口管理器中提供的信息将它们合成到屏幕。SurfaceFlinger 是可以修改所显示部分内容的唯一服务。SurfaceFlinger 使用 OpenGL 和 Hardware Composer 来合成一组 Surface。

其他 OpenGL ES 应用也可以消耗图像流,例如相机应用会消耗相机预览图像流。非 GL 应用也可以是使用方,例如 ImageReader 类。

硬件混合渲染器

显示子系统的硬件抽象实现。SurfaceFlinger 可以将某些合成工作委托给硬件混合渲染器,以分担 OpenGL 和 GPU 上的工作量。SurfaceFlinger 只是充当另一个 OpenGL ES 客户端。因此,在 SurfaceFlinger 将一个或两个缓冲区合成到第三个缓冲区中的过程中,它会使用 OpenGL ES。这会让合成的功耗比通过 GPU 执行所有计算时更低。

Surface

官网对Surface的描述是:A surface is an interface for a producer to exchange buffers with a consumer.

Surface构造函数

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
/**
* 代码位于:frameworks/base/core/java/android/view/Surface.java
* Create an empty surface, which will later be filled in by readFromParcel().
* @hide
*/
@UnsupportedAppUsage
public Surface() {
}

/**
* 代码位于:frameworks/base/core/java/android/view/Surface.java
*
* @param from The SurfaceControl to associate this Surface with
*/
public Surface(@NonNull SurfaceControl from) {
copyFrom(from);
}

/**
* 代码位于:frameworks/base/core/java/android/view/Surface.java
*/
public Surface(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
throw new IllegalArgumentException("surfaceTexture must not be null");
}
mIsSingleBuffered = surfaceTexture.isSingleBuffered();
synchronized (mLock) {
mName = surfaceTexture.toString();
setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
}
}

ActivityUI显示为例:

  • 生产者的任务就是把图形绘制在Surface对象上
    • 比较出名的生产者就是SurfaceView组件了
  • SurfaceFlinger作为消费者会把所有Surface对应的图像层混合在一起
  • 最后消费者将其输出到FrameBuffer中,这样在屏幕上就看到最后合成的图像了

下面我们从Java层开始分析Surface

WMS的Surafce的创建

此处要从ActivityonResume()生命周期说起

我们已经知道,当AMS触发onResume()生命周期时会调用到ActivityThread类的handleResumeActivity()方法,代码如下:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;

// TODO Push resumeArgs into the activity for consideration
// skip below steps for double-resume and r.mFinish = true case.
// 此处会触发 onResume 声明周期回调
if (!performResumeActivity(r, finalStateRequest, reason)) {
return;
}
if (mActivitiesToBeDestroyed.containsKey(r.token)) {
// Although the activity is resumed, it is going to be destroyed. So the following
// UI operations are unnecessary and also prevents exception because its token may
// be gone that window manager cannot recognize it. All necessary cleanup actions
// performed below will be done while handling destruction.
return;
}
// 获取需要Resume的Activity
final Activity a = r.activity;

if (localLOGV) {
Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity
+ ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);
}

final int forwardBit = isForward
? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

// ......
if (r.window == null && !a.mFinished && willBeVisible) {
// 获取当前Actiivty的Window
r.window = r.activity.getWindow();
// 从当前Activity的Window获取decorView
View decor = r.window.getDecorView();
// 然后让DecorView显示
decor.setVisibility(View.INVISIBLE);
// 获取activity的WindowManager
ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
// ......
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 往WindowManager里面添加decorView
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}

// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}

// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r, false /* force */);
// ......

r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}

从方法中可以看到,执行完onResume()后调用了ViewManageraddView(decor, l)方法.

这里提一个小知识点,onResume方法调用后才真正进行View的添加

具体WindowManagerh执行addView的逻辑,我们在这里不再详细赘述:

具体参见:Android之WindowManager基础学习