基础概念 在显示系统中,一般包含三个部分CPU、GPU,屏幕
。
CPU
:执行View的绘制流程measure,layout.draw
GPU
:进一步处理数据,对图形数据进行渲染并放到buffer缓冲区
中缓存
屏幕
:将buffer缓冲区
的数据取出来填充屏幕像素点
CPU绘制后提交数据,GPU进一步处理和缓存数据、最后屏幕从缓冲区获取数据并显示。
屏幕刷新频率
一秒内屏幕刷新的次数也即显示了多少帧的图像,单位Hz
。一般都是60Hz。该值取决于屏幕参数
逐行扫描
屏幕不是一次性进行画面显示,而是从左到右,从上到下的进行逐行扫描
。
帧率
GPU一秒内绘制操作的帧数。 Android系统默认60fps
帧率是动态变化的。
丢帧
在下一个Vsync
信号到来时,由于下一帧数据尚未准备就绪,缓存没有交换,此时显示的上一帧的数据。该情况就为丢帧(Jank)
双缓冲(Double Buffer
)
为了解决画面撕裂
提出的概念
画面撕裂:在GPU向缓冲区写入数据的同时,屏幕也在从buffer缓冲区
读取数据,导致屏幕显示了不同帧的画面,产生画面撕裂
。
由绘制和屏幕拥有各自的buffer缓冲区
:
GPU
处理完数据后,将图形数据写入Back Buffer
。
屏幕
从Frame Buffer
读取图形数据。
当屏幕刷新(Vsync信号到来)时,FrameBuffer
与BackBuffer
的数据进行交换(交换各自的内存地址 ),然后屏幕进行绘制。与屏幕刷新频率
保持一个交换频率。
垂直同步(VSync
)
通过屏幕硬件中断告诉系统应该什么时候刷新屏幕。
开启后GPU会等待显示器的VSync信号发出后再进行新的一帧渲染和缓冲区更新。
在显卡帧率大于屏幕帧率时有效解决显示问题。
配合双缓冲
可以使CPU/GPU
有充分时间处理数据,减少jank(丢帧)
每次收到VSync
信号时,CPU开始处理各帧数据。
三缓冲(Triple Buffer
)
在双缓冲
机制基础上增加了一个Graphic Buffer
缓冲区,最大限度利用空闲时间,但是会多占用一个Graphic buffer
缓冲区内存。
第一个Jank
时无可避免的,在第二个时间段,CPU/GPU使用第三个Graphic Buffer
完成C帧
的计算,避免Jank
问题频发
在第三段时,A帧
计算完成,需要到第四个Vsync
信号才会显示。
第二段中,C帧
需要在第四段才可以显示,相当于多了16ms延迟。
三缓冲 有效利用等待vsync
的时间,减少了jank
,但是增加了延迟。
Graphic Buffer
不是越多越好,一般还是两个,出现jank
以后可以三个。
Project Buffer(黄油计划) 前面提到的VSYnc
、双缓冲/三缓冲
都是Project Buffer
的关键点,还有下面提到的Choreographer
.
核心关键:VSync 实现定时中断
双缓冲/三缓冲
:一般情况下双缓冲
足矣,当出现jank
时,可以添加一块Graphic Buffer
缓冲区,实现三缓冲
Choreographer
:统一管理应用的绘制工作
Choreographer
Android4.1 之后加入的Choreographer
控制Input输入
、Animation动画
,Draw绘制
三个UI操作。
每隔16.6ms,VSync
信号到来时,马上开始下一帧的渲染,CPU和GPU立即开始计算把数据写入Buffer中。
入口 既然说Choreographer
与View
的显示有关,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 public void handleResumeActivity (IBinder token, boolean finalStateRequest, boolean isForward, String reason) { ... if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true ; wm.addView(decor, l); } else { a.onWindowAttributesChanged(l); } } ... } 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) { if (index >= 0 ) { removeViewLocked(index, true ); } throw e; } ... } public void setView (View view , WindowManager.LayoutParams attrs, View panelParentView) { ... requestLayout(); ... view.assignParent(this ); ... } 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" ); } } @Override public void requestLayout () { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true ; scheduleTraversals(); } }
根据上述源码可以得出以下结论:
Activity走完onResume()
之后会进行window的添加
window添加
过程中在ViewRootImpl.setView()
中将DecorView
与ViewRootImpl
进行绑定
ViewRootImpl
与DecorView
绑定后开始进行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 final ViewRootHandler mHandler = new ViewRootHandler(); void scheduleTraversals () { if (!mTraversalScheduled) { mTraversalScheduled = true ; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); 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" ); } performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false ; } } }
scheduleTraversals()
主要有以下逻辑:
设置mTraversalScheduled)
保证同时多次请求只会进行一次View刷新
在getLooper().getQueue()当前消息队列
添加同步屏障 ,保证Vsync信号
到来时,可以立即执行对应任务。暂时屏蔽掉同步消息
的处理。
调用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 public static Choreographer getInstance () { return sThreadInstance.get(); } private static final ThreadLocal<Choreographer> sThreadInstance = new ThreadLocal<Choreographer>() { @Override protected Choreographer initialValue () { 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; } };
Choreographer
和Handler
中的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 private Choreographer (Looper looper, int vsyncSource) { mLooper = looper; mHandler = new FrameHandler(looper); mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null ; mLastFrameTimeNanos = Long.MIN_VALUE; mFrameIntervalNanos = (long )(1000000000 / getRefreshRate()); mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1 ]; for (int i = 0 ; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); } 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: 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); } @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 ; } mTimestampNanos = timestampNanos; mFrame = 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); } }
接收到VSync信号
后,回调到onVsync()
方法,在其中构造一个异步消息
,传入FrameDisplayEventReceiver
为runnable
,通过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; public Object token; public void run (long frameTimeNanos) { if (token == FRAME_CALLBACK_TOKEN) { ((FrameCallback)action).doFrame(frameTimeNanos); } else { ((Runnable)action).run(); } } }
根据源码CallbackRecord
执行run()
有两种情况:
设置任务-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 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) { if (DEBUG_FRAMES) { Log.d(TAG, "Scheduling next frame on vsync." ); } if (isRunningOnLooperThreadLocked()) { scheduleVsyncLocked(); } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true ); mHandler.sendMessageAtFrontOfQueue(msg); } } else { 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." ); } 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()
主要执行了以下几步:
实际执行的为postCallbackDelayedInternal()
,先将任务通过addCallbackLocked()
添加到CallbackQueue
中
判断任务执行时间与当前时间的差值
执行时间在当前时间之前:直接执行scheduleFrameLocked()
执行时间在当前时间之后:将任务封装成异步消息
,通过mHandler
发送消息,且消息为MSG_CO_SCHEDULE_CALLBACK
。到达执行时间之后,也是执行scheduleFrameLocked()
执行scheduleFrameLocked()
,需要先判断mFrameSchduled
,在执行跳过此次任务;未执行,继续判断是否支持VSync
不支持VSync
:封装异步消息,且消息为MSG_DO_FRAME
,发送消息到主线程,执行doFrame()
支持VSync
:需要判断当前是否为UI线程
是UI线程:立即执行scheduleVsyncLocked()
非UI线程:封装异步消息,且消息为MSG_DO_SCHEDULE_VSYNC
,发送消息到主线程,后执行scheduleVsyncLocked()
执行scheduleVsyncLocked()
去申请Vsync信号
。
简单总结postCallback()
申请和接收信号-onVsync() 上一节调用的scheduleVsyncLocked()
申请VSync信号
1 2 3 4 5 6 7 8 9 10 11 12 13 private void scheduleVsyncLocked () { mDisplayEventReceiver.scheduleVsync(); } 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 @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 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 ; } ... long intendedFrameTimeNanos = frameTimeNanos; startNanos = System.nanoTime(); final long jitterNanos = startNanos - frameTimeNanos; if (jitterNanos >= mFrameIntervalNanos) { final long skippedFrames = jitterNanos / mFrameIntervalNanos; if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { 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()
主要执行了两步:
修正frame
执行时间
按照顺序,从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) { 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]); 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)); } 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) { ((FrameCallback)action).doFrame(frameTimeNanos); } else { ((Runnable)action).run(); } } }
doCallbacks()
主要执行了以下几步:
extractDueCallbacksLocked(now/TimeUtils.NANOS_PER_MS)
获取当前时间之前所有可执行的Callback,保存在单链表中。
关于CALLBACK_COMMIT
的处理,如果当前frame
渲染时间超出了两个Vsync
间隔,将当前提交时间修正为上一次VSync信号
发出时间。为了保证下一个frame的提交时间和当前frame的时间相差为1且不重复 。
CALLBACK_COMMIT
是为了解决属性动画
的问题引入的,有时候可能因遍历时间或绘制时间过长,导致动画启动时间过长,发生跳帧,在此处修正动画的第一帧时间 。
修正了动画启动时间,保证动画执行时间的正确性。
最后取出CallbackRecord
,执行run()
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 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 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 ; } 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); 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 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::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::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { sp<ISurfaceComposer> sf (ComposerService::getComposerService()) ; if (sf != nullptr ) { mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged); if (mEventConnection != nullptr ) { mDataChannel = std ::make_unique<gui::BitTube>(); 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 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)); 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 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 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 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 () { mEventThread->registerDisplayEventConnection(this ); }status_t EventThread::registerDisplayEventConnection (const sp<EventThreadConnection>& connection) { std ::lock_guard<std ::mutex> lock (mMutex) ; 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; }
EventThread
与EventThreadConnection
采用观察者模式
,当有显示事件发生时,EventThread
向EventThreadConnection
传递事件。
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
所获的文件句柄,一旦有数据到来,回调给this
即DisplayEventDispatcher
的handleEvent()
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 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 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 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 ; } if (!(events & Looper::EVENT_INPUT)) { ALOGW("Received spurious callback for unhandled poll event. " "events=0x%x" , events); return 1 ; } 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 ; }
回调到handleEvent()
在向下执行到dispatchVsync()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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绘制 。
其他
利用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) { ... Choreographer.getInstance().postFrameCallback(this ); } }
Choreographer.CALLBACK_INPUT
使用场景?
参考链接 View的工作原理
Choreographer原理
Android Code Search
Android-Choreographer
Android与SurfaceFlinger建立连接过程