Android屏幕的刷新机制

View屏幕刷新

基础概念

在显示系统中,一般包含三个部分CPU、GPU,屏幕

CPU:执行View的绘制流程measure,layout.draw

GPU:进一步处理数据,对图形数据进行渲染并放到buffer缓冲区中缓存

屏幕:将buffer缓冲区的数据取出来填充屏幕像素点

CPU绘制后提交数据,GPU进一步处理和缓存数据、最后屏幕从缓冲区获取数据并显示。

img

屏幕刷新频率

一秒内屏幕刷新的次数也即显示了多少帧的图像,单位Hz。一般都是60Hz。该值取决于屏幕参数

逐行扫描

屏幕不是一次性进行画面显示,而是从左到右,从上到下的进行逐行扫描

帧率

GPU一秒内绘制操作的帧数。Android系统默认60fps

帧率是动态变化的。

丢帧

在下一个Vsync信号到来时,由于下一帧数据尚未准备就绪,缓存没有交换,此时显示的上一帧的数据。该情况就为丢帧(Jank)

丢帧

双缓冲(Double Buffer)

为了解决画面撕裂提出的概念

画面撕裂:在GPU向缓冲区写入数据的同时,屏幕也在从buffer缓冲区读取数据,导致屏幕显示了不同帧的画面,产生画面撕裂

由绘制和屏幕拥有各自的buffer缓冲区

GPU处理完数据后,将图形数据写入Back Buffer

屏幕Frame Buffer读取图形数据。

当屏幕刷新(Vsync信号到来)时,FrameBufferBackBuffer的数据进行交换(交换各自的内存地址),然后屏幕进行绘制。与屏幕刷新频率保持一个交换频率。

双缓冲示意

垂直同步(VSync)

通过屏幕硬件中断告诉系统应该什么时候刷新屏幕。

开启后GPU会等待显示器的VSync信号发出后再进行新的一帧渲染和缓冲区更新。

在显卡帧率大于屏幕帧率时有效解决显示问题。

配合双缓冲可以使CPU/GPU有充分时间处理数据,减少jank(丢帧)

VSync

每次收到VSync信号时,CPU开始处理各帧数据。

三缓冲(Triple Buffer)

双缓冲机制基础上增加了一个Graphic Buffer缓冲区,最大限度利用空闲时间,但是会多占用一个Graphic buffer缓冲区内存。

三缓存

  1. 第一个Jank时无可避免的,在第二个时间段,CPU/GPU使用第三个Graphic Buffer完成C帧的计算,避免Jank问题频发
  2. 在第三段时,A帧计算完成,需要到第四个Vsync信号才会显示。
  3. 第二段中,C帧需要在第四段才可以显示,相当于多了16ms延迟。

三缓冲有效利用等待vsync的时间,减少了jank,但是增加了延迟。

Graphic Buffer不是越多越好,一般还是两个,出现jank以后可以三个。

Project Buffer(黄油计划)

前面提到的VSYnc双缓冲/三缓冲都是Project Buffer的关键点,还有下面提到的Choreographer.

  • 核心关键:VSync实现定时中断
  • 双缓冲/三缓冲:一般情况下双缓冲足矣,当出现jank时,可以添加一块Graphic Buffer缓冲区,实现三缓冲
  • Choreographer:统一管理应用的绘制工作

Choreographer

View屏幕刷新-Choreographer

Android4.1 之后加入的Choreographer控制Input输入Animation动画Draw绘制三个UI操作。

每隔16.6ms,VSync信号到来时,马上开始下一帧的渲染,CPU和GPU立即开始计算把数据写入Buffer中。

img

入口

既然说ChoreographerView的显示有关,View的绘制过程起点位于ViewRootImpl.setView(),此处为Activity执行到onResume()后,window添加到Activity上。通过调用到ViewRootImpl.setView()开始绘制布局

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
//ActivityThread.java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason)
{
...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {//尚未添加window
a.mWindowAdded = true;
wm.addView(decor, l);//准备添加View
} 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);
}
}
...

}

//WindowManagerGlobal.java WindowManager实现类
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow)
{
...
ViewRootImpl root;
...
root = new ViewRootImpl(view.getContext(), display);
...
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
...
}

//ViewRootImpl.java
public void setView(View view /*DecorView*/, WindowManager.LayoutParams attrs, View panelParentView) {
...
requestLayout();//刷新布局
...
view.assignParent(this); //设置DecorView 父类为 ViewRootImpl,此时将ViewRootImpl与DecorView进行绑定
...
}
//View.java
void assignParent(ViewParent parent) {
if (mParent == null) {
mParent = parent;
} else if (parent == null) {
mParent = null;
} else {
throw new RuntimeException("view " + this + " being added, but"
+ " it already has a parent");
}
}

//ViewRootImpl.java
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}

根据上述源码可以得出以下结论:

  • Activity走完onResume()之后会进行window的添加
  • window添加过程中在ViewRootImpl.setView()中将DecorViewViewRootImpl进行绑定
  • ViewRootImplDecorView绑定后开始进行View的绘制任务

为什么onCreate()无法获取View宽高?

此时未执行到onResume()尚未开始绘制,也还没开始执行measure -> layout -> draw过程,也就无法获取。

以上只是Activity启动时相关的绘制过程,此外还有属性动画、View.invalidate()都会影响到UI变化

所有的UI变化都是走到ViewRootImpl.scheduleTraversals()

ViewRootImpl.scheduleTraversals()

UI变化最终都会走到此处。

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
//ViewRootImpl.java
final ViewRootHandler mHandler = new ViewRootHandler();

void scheduleTraversals() {
if (!mTraversalScheduled) {
//保证多次调用UI刷新,只走一次绘制流程
mTraversalScheduled = true;
//添加同步屏障,屏蔽同步消息,保证Vsync到来时优先绘制流程
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//使用到了 Choreographer
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
}

final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

void doTraversal() {
if (mTraversalScheduled) {
//执行任务时,恢复状态
mTraversalScheduled = false;
//移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
//开始View的绘制流程
performTraversals();

if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}

scheduleTraversals()主要有以下逻辑:

  1. 设置mTraversalScheduled)保证同时多次请求只会进行一次View刷新
  2. getLooper().getQueue()当前消息队列添加同步屏障,保证Vsync信号到来时,可以立即执行对应任务。暂时屏蔽掉同步消息的处理。
  3. 调用Choreographer.postCallback(,mTraversalRunnable,),在下一次VSync信号到来时,会执行doTraversal(),继续向下调用performTraversals()开始绘制流程。

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Choreographer.java
public static Choreographer getInstance() {
return sThreadInstance.get();
}

private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
//获取当前线程的Looper对象
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};

ChoreographerHandler中的Looper一致,都是每个线程持有一个Choreographer,通过ThreadLocal进行获取。

接下来是Choreographer的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Choreographer.java    
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
//创建Handler对象
mHandler = new FrameHandler(looper);
//接收Vsync信号
mDisplayEventReceiver = USE_VSYNC //USE_VSYNC在4.1以上默认 true,表示可以接收VSync信号
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
//上一次帧绘制的时间点
mLastFrameTimeNanos = Long.MIN_VALUE;
//每帧的差值,一般为16.6ms
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//初始化回调队列
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
// b/68769804: For low FPS experiments.
setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
}

Choreographer在构造时分别执行了以下几步:

  • 初始化FrameHandler(接收并处理消息)
  • 初始化FrameDisplayEventReceiver(接收VSync信号)
  • 初始化mLastFrameTimeNanos(上一次绘制帧时间点)mFrameIntervalNanos(帧率)
  • 初始化mCallbackQueues(回调队列)

FrameHandler

发送异步消息(设置了同步屏障)。有延迟的任务发送延迟消息,不在主线程的任务发到主线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
//执行绘制过程
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
//当需要执行绘制任务时,申请VSync信号
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
//执行需要延迟的任务
doScheduleCallback(msg.arg1);
break;
}
}
}

主要处理以下类型的消息:

  • MSG_DO_FRAME:开始绘制流程
  • MSG_DO_SCHEDULE_VSYNC:请求VSync信号
  • MSG_DO_SCHEDULE_CALLBACK:请求执行Callback

FrameDisplayEventReceiver

主要用来接收VSync信号,控制系统的同步操作

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
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable
{
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;

public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}

//此处接收 VSync信号
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
Log.d(TAG, "Received vsync from secondary display, but we don't support "
+ "this case yet. Choreographer needs a way to explicitly request "
+ "vsync for a specific display to ensure it doesn't lose track "
+ "of its scheduled vsync.");
scheduleVsync();
return;
}

long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}

if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
//VSync信号到来的时间
mTimestampNanos = timestampNanos;
mFrame = frame;
//构建异步消息,传入本身作为任务的执行者,需要执行的任务就是 run()
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}

//需要执行的任务
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}

接收到VSync信号后,回调到onVsync()方法,在其中构造一个异步消息,传入FrameDisplayEventReceiverrunnable,通过FrameHandler发送该消息,等到消息触发时就执行doFrame()

CallbackQueue

存储对应任务类型的队列,在执行任务时从对应队列中获取任务

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
private final class CallbackQueue {
private CallbackRecord mHead;

//当前是否有等待执行的任务
public boolean hasDueCallbacksLocked(long now) {
return mHead != null && mHead.dueTime <= now;
}

//获取队列任务
public CallbackRecord extractDueCallbacksLocked(long now) {
CallbackRecord callbacks = mHead;
if (callbacks == null || callbacks.dueTime > now) {
return null;
}

CallbackRecord last = callbacks;
CallbackRecord next = last.next;
while (next != null) {
if (next.dueTime > now) {
last.next = null;
break;
}
last = next;
next = next.next;
}
mHead = next;
return callbacks;
}

//添加消息
public void addCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
CallbackRecord entry = mHead;
if (entry == null) {
mHead = callback;
return;
}
if (dueTime < entry.dueTime) {
callback.next = entry;
mHead = callback;
return;
}
while (entry.next != null) {
if (dueTime < entry.next.dueTime) {
callback.next = entry.next;
break;
}
entry = entry.next;
}
entry.next = callback;
}

//删除消息
public void removeCallbacksLocked(Object action, Object token) {
CallbackRecord predecessor = null;
for (CallbackRecord callback = mHead; callback != null;) {
final CallbackRecord next = callback.next;
if ((action == null || callback.action == action)
&& (token == null || callback.token == token)) {
if (predecessor != null) {
predecessor.next = next;
} else {
mHead = next;
}
recycleCallbackLocked(callback);
} else {
predecessor = callback;
}
callback = next;
}
}
}

CallbackQueue存储的元素为CallbackRecord

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
public Object action; // Runnable or FrameCallback
public Object token;

public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
//执行了postFrameCallback()或 postFrameCallbackDelayed 执行此处
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
//否则执行 run
((Runnable)action).run();
}
}
}

根据源码CallbackRecord执行run()有两种情况:

  • token不为null且FRAME_CALLBACK_TOKEN

    执行doFrame(),实际这种情况只会执行postFrameCallback()postFrameCallbackDelayed()

    这两个方法在都会被调用到

  • token为其他

    执行run(),此时action对应的就是ViewRootImpl的mTraversalRunnable也就会开始执行绘制流程

设置任务-postCallback()

ViewRootImpl.scheduleTraversals()通过postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)添加绘制任务

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
//Choreographer.java 
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis)
{
...
synchronized (mLock) {
//当前时间
final long now = SystemClock.uptimeMillis();
//延迟时间
final long dueTime = now + delayMillis;
//将任务添加到回调队列
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

if (dueTime <= now) {
//任务立即开始执行
scheduleFrameLocked(now);
} else {
//封装异步消息等待执行
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}

private final class FrameHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
...
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}

void doScheduleCallback(int callbackType) {
synchronized (mLock) {
if (!mFrameScheduled) {
final long now = SystemClock.uptimeMillis();
if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now);
}
}
}
}

CallbackType表示回调任务的类型,目前分为4种类型

  • CALLBACK_INPUT:输入回调,接收到VSync信号时首先运行,如处理Move事件
  • CALLBACK_ANIMATION:动画回调
  • CALLBACK_TRAVERSAL:Traversal回调,执行measure->layout->draw
  • CALLBACK_COMMIT:Commit回调,处理帧绘制完成后的操作,如整理应用内存,属性动画起始时间调整

postCallback()最后都会执行到scheduleFrameLocked()

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
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {//当前是否有帧在执行
mFrameScheduled = true;
if (USE_VSYNC) {//支持VSync,默认true
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}

//当前运行在Looper所在的线程,立即执行申请VSync信号
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
//通过 mHandler发送异步消息到原线程,申请VSync信号
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {//不支持 VSync
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
//执行 doFrame()
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}

private final class FrameHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
...
}
}
}

void doScheduleVsync() {
synchronized (mLock) {
if (mFrameScheduled) {
scheduleVsyncLocked();
}
}
}

postCallback()主要执行了以下几步:

  1. 实际执行的为postCallbackDelayedInternal(),先将任务通过addCallbackLocked()添加到CallbackQueue
  2. 判断任务执行时间与当前时间的差值
    • 执行时间在当前时间之前:直接执行scheduleFrameLocked()
    • 执行时间在当前时间之后:将任务封装成异步消息,通过mHandler发送消息,且消息为MSG_CO_SCHEDULE_CALLBACK。到达执行时间之后,也是执行scheduleFrameLocked()
  3. 执行scheduleFrameLocked(),需要先判断mFrameSchduled,在执行跳过此次任务;未执行,继续判断是否支持VSync
    • 不支持VSync:封装异步消息,且消息为MSG_DO_FRAME,发送消息到主线程,执行doFrame()
    • 支持VSync:需要判断当前是否为UI线程
      • 是UI线程:立即执行scheduleVsyncLocked()
      • 非UI线程:封装异步消息,且消息为MSG_DO_SCHEDULE_VSYNC,发送消息到主线程,后执行scheduleVsyncLocked()
  4. 执行scheduleVsyncLocked()去申请Vsync信号

简单总结postCallback()

申请和接收信号-onVsync()

上一节调用的scheduleVsyncLocked()申请VSync信号

1
2
3
4
5
6
7
8
9
10
11
12
13
    private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}

//DisplayEventReceiver.java
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
+ "receiver has already been disposed.");
} else {
nativeScheduleVsync(mReceiverPtr);
}
}

nativeScheduleVsync()调用native方法申请VSync信号

1
2
3
4
5
6
//DisplayEventReceiver.java
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}

通过native调用dispatchVsync()回调onVsync()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Chorgegrapher.FrameDisplayEventReceiver.java
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable
{
...
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
...
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}

@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}

将本身作为runnable对象,执行的就是run(),最终执行的就是doFrame()

执行任务-doFrame()

最终在接收到VSync信号时,执行doFrame()

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
80
81
82
83
84
85
86
87
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {//
if (!mFrameScheduled) {//当前有任务在执行
return; // no work to do
}
...
//预期执行时间
long intendedFrameTimeNanos = frameTimeNanos;
//实际frame执行时间
startNanos = System.nanoTime();
//预期与实际时间差
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= mFrameIntervalNanos) {//时间差大于一帧执行时长,当前为16.6ms
final long skippedFrames = jitterNanos / mFrameIntervalNanos;//计算跳过的帧数
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {//默认30
//跳过的帧数超出了30时,打印日志
Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ "The application may be doing too much work on its main thread.");
}
//重新计算实际执行与当前时间的偏差值
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
+ "Skipping " + skippedFrames + " frames and setting frame "
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
//修正偏差值,方便后续同步工作
frameTimeNanos = startNanos - lastFrameOffset;
}

//当前时间小于上一次绘制时间,就等待下一次绘制时机到老
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ "previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}

if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
scheduleVsyncLocked();
return;
}
}

mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
//记录上一次绘制时间
mLastFrameTimeNanos = frameTimeNanos;
}

try {
//按类型顺序执行任务
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

mFrameInfo.markInputHandlingStart();
//输入
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

mFrameInfo.markAnimationsStart();
//动画
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

mFrameInfo.markPerformTraversalsStart();
//绘制
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
//遍历完成的提交操作
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}

if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took "
+ (endNanos - startNanos) * 0.000001f + " ms, latency "
+ (startNanos - frameTimeNanos) * 0.000001f + " ms.");
}
}

doFrame()主要执行了两步:

  1. 修正frame执行时间
  2. 按照顺序,从callbackQueue获取CallbackRecord执行
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
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
// in a following phase, such as an input event that causes an animation to start.
final long now = System.nanoTime();
//根据回调类型获取可执行回调(已到达执行时间)
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;

...
//属于 提交任务类型
if (callbackType == Choreographer.CALLBACK_COMMIT) {
final long jitterNanos = now - frameTimeNanos;
Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
if (jitterNanos >= 2 * mFrameIntervalNanos) {
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
+ mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
+ " ms which is more than twice the frame interval of "
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
+ "Setting frame time to " + (lastFrameOffset * 0.000001f)
+ " ms in the past.");
mDebugPrintNextFrameTimeDelta = true;
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
}
}
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
//迭代执行对应 callbackType队列的任务
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
//回调CallbackRecord的run()
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}

private static final class CallbackRecord {
...
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
//执行了postFrameCallback()或 postFrameCallbackDelayed 执行此处
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
//否则执行 run
((Runnable)action).run();
}
}
}

doCallbacks()主要执行了以下几步:

  1. extractDueCallbacksLocked(now/TimeUtils.NANOS_PER_MS)获取当前时间之前所有可执行的Callback,保存在单链表中。

  2. 关于CALLBACK_COMMIT的处理,如果当前frame渲染时间超出了两个Vsync间隔,将当前提交时间修正为上一次VSync信号发出时间。为了保证下一个frame的提交时间和当前frame的时间相差为1且不重复

    CALLBACK_COMMIT是为了解决属性动画的问题引入的,有时候可能因遍历时间或绘制时间过长,导致动画启动时间过长,发生跳帧,在此处修正动画的第一帧时间

    img

    修正了动画启动时间,保证动画执行时间的正确性。

  3. 最后取出CallbackRecord,执行run()

View刷新过程

Vsync申请和回调流程(Native)

申请Vsync信号

frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp

frameworks/native/libs/gui/DisplayEventDispatcher.cpp

nativeScheduleVsync()开始监听VSync信号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//DisplayEventReceiver.java
private static native void nativeScheduleVsync(long receiverPtr);

//初始化
public DisplayEventReceiver(Looper looper, int vsyncSource) {
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}

mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
vsyncSource);

mCloseGuard.open("dispose");
}

执行nativeInit()初始化并创建DisplayEventReceiver

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
//android_view_DisplayEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject messageQueueObj, jint vsyncSource, jint configChanged)
{
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//创建NAtiveDisplayEventReceiver,与SurfaceFlinger建立连接
sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
receiverWeak, messageQueue, vsyncSource, configChanged);
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize display event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}

receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}

NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
jint configChanged) :
DisplayEventDispatcher(messageQueue->getLooper(),
static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
static_cast<ISurfaceComposer::ConfigChanged>(configChanged)),
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mMessageQueue(messageQueue) {
ALOGV("receiver %p ~ Initializing display event receiver.", this);
}

新建完DisplayEventReceiver,由DisplayEventDispatcher进行后续操作

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
//DisplayEventReceiver.h
class DisplayEventDispatcher : public LooperCallback {
public:
explicit DisplayEventDispatcher(
const sp<Looper>& looper,
ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
ISurfaceComposer::ConfigChanged configChanged =
ISurfaceComposer::eConfigChangedSuppress)
;
...

private:
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
...

}


//DisplayEventDispatcher.cpp
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::ConfigChanged configChanged)
: mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//DisplayEventReceiver.cpp
DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::ConfigChanged configChanged) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr) {
//为客户端创建显示连接,通过该连接请求SurfaceFlinger发送及接收Vsync信号
mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged);
if (mEventConnection != nullptr) {
//创建BitTube
mDataChannel = std::make_unique<gui::BitTube>();
//通过Binder获取对应Connection的Socket
mEventConnection->stealReceiveChannel(mDataChannel.get());
}
}
}

createDisplayEventConnection

createDisplayEventConnection()是一个Binder IPC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//ISurfaceComposer.cpp
virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource,
ConfigChanged configChanged)
{
Parcel data, reply;
sp<IDisplayEventConnection> result;
int err = data.writeInterfaceToken(
ISurfaceComposer::getInterfaceDescriptor());
if (err != NO_ERROR) {
return result;
}
data.writeInt32(static_cast<int32_t>(vsyncSource));
data.writeInt32(static_cast<int32_t>(configChanged));
//请求SurfaceLinger处理 CREATE_DISPLAY_EVENT_CONNECTION
err = remote()->transact(
BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
data, &reply);
if (err != NO_ERROR) {
ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing "
"transaction: %s (%d)", strerror(-err), -err);
return result;
}
result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
return result;
}

onTransact()处理发过来的CREATE_DISPLAY_EVENT_CONNECTION

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//ISurfaceComposer.cpp
status_t BnSurfaceComposer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{
...
case CREATE_DISPLAY_EVENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32());
auto configChanged = static_cast<ISurfaceComposer::ConfigChanged>(data.readInt32());

sp<IDisplayEventConnection> connection(
createDisplayEventConnection(vsyncSource, configChanged))
;
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
...
}

通过SurfaceFlinger处理请求

1
2
3
4
5
6
7
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged)
{
const auto& handle =
vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;

return mScheduler->createDisplayEventConnection(handle, configChanged);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//EventThread.cpp
sp<EventThreadConnection> Scheduler::createConnectionInternal(
EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged)
{
return eventThread->createEventConnection([&] { resync(); }, configChanged);
}

sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged)
{
RETURN_IF_INVALID_HANDLE(handle, nullptr);
return createConnectionInternal(mConnections[handle].thread.get(), configChanged);
}

sp<EventThreadConnection> EventThread::createEventConnection(
ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged)
const
{
return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
configChanged);
}

最后生成EventConnection对象,主要有两个作用:

  • 处理客户的的Vsync申请请求
  • 向客户端发送事件(Vsync)
1
2
3
4
5
6
7
8
//EventThread.cpp
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
ResyncCallback resyncCallback,
ISurfaceComposer::ConfigChanged configChanged)
: resyncCallback(std::move(resyncCallback)),
mConfigChanged(configChanged),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}

BitTube是一个Socket pair,主要有两个作用:

  • 封装用于显示时间的Socket通信
  • 跨进程传递Socket文件描述符(fd)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void EventThreadConnection::onFirstRef() {
// NOTE: mEventThread doesn't hold a strong reference on us
mEventThread->registerDisplayEventConnection(this);
}

status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
std::lock_guard<std::mutex> lock(mMutex);

// this should never happen
auto it = std::find(mDisplayEventConnections.cbegin(),
mDisplayEventConnections.cend(), connection);
if (it != mDisplayEventConnections.cend()) {
ALOGW("DisplayEventConnection %p already exists", connection.get());
mCondition.notify_all();
return ALREADY_EXISTS;
}
//添加连接到集合中
mDisplayEventConnections.push_back(connection);
mCondition.notify_all();
return NO_ERROR;
}

EventThreadEventThreadConnection采用观察者模式,当有显示事件发生时,EventThreadEventThreadConnection传递事件。

stealReceiveChannel

通过一系列操作得到EventConnection,在向下执行到stealReceiveChannel()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class BpDisplayEventConnection : public SafeBpInterface<IDisplayEventConnection> {
...
status_t stealReceiveChannel(gui::BitTube* outChannel) override {
return callRemote<decltype(
&IDisplayEventConnection::stealReceiveChannel)>(Tag::STEAL_RECEIVE_CHANNEL,
outChannel);
}
...
}

status_t BnDisplayEventConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags)
{
if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
return BBinder::onTransact(code, data, reply, flags);
}
auto tag = static_cast<Tag>(code);
switch (tag) {
case Tag::STEAL_RECEIVE_CHANNEL:
return callLocal(data, reply, &IDisplayEventConnection::stealReceiveChannel);
...
}
}

监听mReceivcer所获的文件句柄,一旦有数据到来,回调给thisDisplayEventDispatcherhandleEvent()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
status_t DisplayEventDispatcher::initialize() {
status_t result = mReceiver.initCheck();
if (result) {
ALOGW("Failed to initialize display event receiver, status=%d", result);
return result;
}

if (mLooper != nullptr) {
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
if (rc < 0) {
return UNKNOWN_ERROR;
}
}

return OK;
}

DisplayEventReceiver#scheduleVsync

DisplayEventReceiver初始化完毕后,继续执行scheduleVsync()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//libs/androidfw/DisplayEventDispatcher.cpp
status_t DisplayEventDispatcher::scheduleVsync() {
if (!mWaitingForVsync) {
ALOGV("dispatcher %p ~ Scheduling vsync.", this);

status_t status = mReceiver.requestNextVsync();
if (status) {
ALOGW("Failed to request next vsync, status=%d", status);
return status;
}

mWaitingForVsync = true;
}
return OK;
}

回调到DisplayEventReceiver

1
2
3
4
5
6
7
8
//frameworks/native/libs/gui/DisplayEventReceiver.cpp
status_t DisplayEventReceiver::requestNextVsync() {
if (mEventConnection != NULL) {
mEventConnection->requestNextVsync();
return NO_ERROR;
}
return NO_INIT;
}

mEventConnection指向了EventThreadConnection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp
void EventThreadConnection::requestNextVsync() {
ATRACE_NAME("requestNextVsync");
mEventThread->requestNextVsync(this);
}

void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
if (connection->resyncCallback) {
connection->resyncCallback();
}

std::lock_guard<std::mutex> lock(mMutex);

if (connection->vsyncRequest == VSyncRequest::None) {
connection->vsyncRequest = VSyncRequest::Single;
mCondition.notify_all();
}
}

调用mCondition.notify_all()唤醒了等待的EventThread

就去获取一次Vsync信号

回调Vsync信号

收到Vsync信号后,回调到DisplayEventDispatcher.handleEvent()

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
int DisplayEventDispatcher::handleEvent(int, int events, void*) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
"events=0x%x",
events);
return 0; // remove the callback
}

if (!(events & Looper::EVENT_INPUT)) {
ALOGW("Received spurious callback for unhandled poll event. "
"events=0x%x",
events);
return 1; // keep the callback
}

// Drain all pending events, keep the last vsync.
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
", displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",
this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
mWaitingForVsync = false;
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
}

return 1; // keep the callback
}

回调到handleEvent()在向下执行到dispatchVsync()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//android_view_DisplayEventReceiver.cpp
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
uint32_t count)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();

ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
env->CallVoidMethod(receiverObj.get(),
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}

mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}

此处调用到DisplayEventReceiver.dispatchVsync()

SurfaceFlinger监听Vsync信号

上面讲到的都是从SurfaceFlinger去监听到Vsync信号,但是SurfaceFlinger的Vsync信号又是从哪里来的?

Android-SurfaceFlinger解析

Handler异步消息与同步屏障

ViewRootImpl.schdeuleTraversals()执行mHandler.getLooper().getQueue().postSyncBarrier()添加同步屏障,在doTraversal()执行removeSyncBarrier()移除同步屏障

同步屏障:为了提高异步消息优先级,保证Vsync信号和绘制的同步。

Handler机制源码解析

总结

总结

丢帧:这一帧的内容延迟显示,因为只有收到VSync信号才会进行Buffer交换。主要原因一般都是:布局层级较多或主线程耗时导致CPU/GPU执行时间变长,超出16.6ms就会导致丢帧

一般屏幕的固定刷新率是60Hz,换算就是60帧,即每16.6ms切换一帧。

屏幕内容的绘制也是如此,没有绘制任务(没执行scheduleTraversals())就不会执行绘制流程,但是底层仍然会每隔16.6ms切换下一帧画面,只不过一直显示相同的内容。当有绘制任务时,执行完measure->layout->draw流程后,依然需要等待收到VSync信号界面才会刷新。

VSync信号发生在扫描完一个屏幕后,需要从最下面回到第一行继续循环,此时会发出该信号保证双缓冲(CPU/GPU)数据交换

在同一时间多次调用requestLayout()/invalidate()不会导致多次页面刷新,由于mTraversalScheduled的设置,当存在任务的时候,就会过滤重复请求,因为最后的请求都会执行到ViewRootImpl.scheduleTraversals(),只要一次绘制就可以刷新所有View

Choreographer主要为了在VSync信号到来时开始处理消息即CPU/GPU绘制

其他

其他

  1. 利用Choreographer.postFrameCallback(frameCallback)统计丢帧状况

    postFrameCallback()会在每次frame渲染的时候回调一次,然后执行frameCallback.doFrame(),在doFrame()可以获取每一帧的渲染时间然后判断是否发生丢帧

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Choreographer.getInstance().postFrameCallback(new TestFrameCallback())

    public class TestFrameCallback implements Choreographer.FrameCallback {
    @Override
    public void doFrame(long frameTimeNanos){
    ...
    //计算帧率 or others

    //注册下一帧回调
    Choreographer.getInstance().postFrameCallback(this);
    }
    }
  2. Choreographer.CALLBACK_INPUT使用场景?

参考链接

View的工作原理

Choreographer原理

Android Code Search

Android-Choreographer

Android与SurfaceFlinger建立连接过程


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!