Android中的Choreographer工作原理解析
前言
Android應(yīng)用的UI
界面需要多個角色共同協(xié)作才能完成渲染上屏,最終呈現(xiàn)到屏幕上被用戶看到。其中包括App
進程的測量、布局和繪制,SurfaceFlinger
進程的渲染數(shù)據(jù)合成等。而App
進程何時開始測量、布局和繪制,SurfaceFlinger
進程何時開始數(shù)據(jù)的合成和上屏,決定了Android系統(tǒng)能否有條不紊地刷新屏幕內(nèi)容,給用戶提供流暢的使用體驗。
為了協(xié)調(diào)App
進程的視圖數(shù)據(jù)生產(chǎn)和SurfaceFlinger
進程的視圖數(shù)據(jù)消費處理,Android系統(tǒng)引入Choreographer
對App
進程的布局繪制工作和SurfaceFlinger
進程的數(shù)據(jù)合成工作進行調(diào)度,減少因為Android應(yīng)用繪制渲染和屏幕刷新之間不同步導(dǎo)致的屏幕撕裂(tearing
)問題。
本文從Choreographer
的創(chuàng)建流程和Choreographer
的VSYNC
請求、分發(fā)以及處理兩個方面來分析Choreographer
機制的工作原理。
說明:本文中的源碼對應(yīng)的Android版本是Android 13。
Choreographer的創(chuàng)建流程
先給出Choreographer
的創(chuàng)建時機:Android中啟動一個Activity
時,在SystemServer
進程在ActivityTaskSupervisor#realStartActivityLocked
方法中通過Binder
跨進程調(diào)用到App
進程,在App
進程調(diào)用了IApplicationThread#scheduleTransaction
,最終執(zhí)行完Activity#onResume
方法之后會調(diào)用ViewManager#addView
,最終創(chuàng)建了ViewRootImpl
實例,并在ViewRootImpl
的構(gòu)造函數(shù)中完成了Choreographer
實例創(chuàng)建,并作為ViewRootImpl
的成員變量持有。
SystemServer
進程收到App
進程啟動Activity
的Binder
請求后,在ActivityTaskSupervisor#realStartActivityLocked
方法中封裝LaunchActivityItem
和ResumeActivityItem
并通過ClientLifecycleManager#scheduleTransaction
調(diào)度執(zhí)行任務(wù),最終還是通過App
進程的IApplicationThread
(Binder
實例)跨進程調(diào)用到App
進程的ApplicationThread#scheduleTransaction
方法。
// com.android.server.wm.ActivityTaskSupervisor#realStartActivityLocked boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { // ... // Create activity launch transaction. final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token); // ... clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor, proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), results, newIntents, r.takeOptions(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken)); // Set desired final state. final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(isTransitionForward); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // Schedule transaction. mService.getLifecycleManager().scheduleTransaction(clientTransaction); // ... } // android.app.ClientTransactionHandler#scheduleTransaction void scheduleTransaction(ClientTransaction transaction) throws RemoteException { final IApplicationThread client = transaction.getClient(); transaction.schedule(); if (!(client instanceof Binder)) { // If client is not an instance of Binder - it's a remote call and at this point it is // safe to recycle the object. All objects used for local calls will be recycled after // the transaction is executed on client in ActivityThread. transaction.recycle(); } } // android.app.servertransaction.ClientTransaction#schedule /** * 當transaction初始化之后開始調(diào)度執(zhí)行,將會被發(fā)送給client端并按照以下順序進行處理: * 1. 調(diào)用preExecute(ClientTransactionHandler) * 2. 調(diào)度transaction對應(yīng)的消息 * 3. 調(diào)用TransactionExecutor#execute(ClientTransaction) */ public void schedule() throws RemoteException { mClient.scheduleTransaction(this); // mClient為App進程通過Binder通信傳遞的Binder句柄IApplicationThread。 }
此時調(diào)用鏈已經(jīng)傳遞到App進程,由ActivityThread
的ApplicationThread
類型的成員變量進行處理,而ApplicationThread#scheduleTransaction
方法直接調(diào)用了外部類ActivityThread
的scheduleTransaction
方法,相當于直接轉(zhuǎn)發(fā)給ActivityThread#scheduleTransaction
。而ActivityThread#scheduleTransaction
通過主線程的Handler
對象mH
向主線程的MessageQueue
中插入了一個EXECUTE_TRANSACTION
消息。此時,App
進程在主線程中處理EXECUTE_TRANSACTION
消息。
/** * 負責管理應(yīng)用進程中的主線程任務(wù),按照SystemServer進程請求的那樣對任務(wù)進行調(diào)度和執(zhí)行。 */ public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal { @UnsupportedAppUsage final ApplicationThread mAppThread = new ApplicationThread(); @UnsupportedAppUsage final Looper mLooper = Looper.myLooper(); @UnsupportedAppUsage final H mH = new H(); // An executor that performs multi-step transactions. private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this); // ... private class ApplicationThread extends IApplicationThread.Stub { // ... @Override public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { ActivityThread.this.scheduleTransaction(transaction); } // ... } // from the class ClientTransactionHandler that is the base class of ActivityThread /** Prepare and schedule transaction for execution. */ void scheduleTransaction(ClientTransaction transaction) { transaction.preExecute(this); sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); } private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { if (DEBUG_MESSAGES) { Slog.v(TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); } Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } // 主線程的Handler mH.sendMessage(msg); } class H extends Handler { public void handleMessage(Message msg) { // ... switch (msg.what) { // ... case EXECUTE_TRANSACTION: final ClientTransaction transaction = (ClientTransaction) msg.obj; mTransactionExecutor.execute(transaction); if (isSystem()) { // Client transactions inside system process are recycled on the client side // instead of ClientLifecycleManager to avoid being cleared before this // message is handled. transaction.recycle(); } // TODO(lifecycler): Recycle locally scheduled transactions. break; // ... } // ... } }
主線程調(diào)用TransactionExecutor#execute
方法處理消息,并在executeCallbacks
方法中執(zhí)行了ResumeActivityItem
/** * Class that manages transaction execution in the correct order. */ public class TransactionExecutor { // ... /** * Resolve transaction. * First all callbacks will be executed in the order they appear in the list. If a callback * requires a certain pre- or post-execution state, the client will be transitioned accordingly. * Then the client will cycle to the final lifecycle state if provided. Otherwise, it will * either remain in the initial state, or last state needed by a callback. */ public void execute(ClientTransaction transaction) { // ... // 實際執(zhí)行生命周期任務(wù)的地方 executeCallbacks(transaction); executeLifecycleState(transaction); mPendingActions.clear(); // ... } /** Cycle through all states requested by callbacks and execute them at proper times. */ @VisibleForTesting public void executeCallbacks(ClientTransaction transaction) { // 取出之前SystemServer進程放入的LaunchActivityItem和ResumeActivityItem final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); if (callbacks == null || callbacks.isEmpty()) { // No callbacks to execute, return early. return; } if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callbacks in transaction"); final IBinder token = transaction.getActivityToken(); ActivityClientRecord r = mTransactionHandler.getActivityClient(token); // In case when post-execution state of the last callback matches the final state requested // for the activity in this transaction, we won't do the last transition here and do it when // moving to final state instead (because it may contain additional parameters from server). final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest(); final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState() : UNDEFINED; // Index of the last callback that requests some post-execution state. final int lastCallbackRequestingState = lastCallbackRequestingState(transaction); final int size = callbacks.size(); for (int i = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item); final int postExecutionState = item.getPostExecutionState(); final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r, item.getPostExecutionState()); if (closestPreExecutionState != UNDEFINED) { cycleToPath(r, closestPreExecutionState, transaction); } // 執(zhí)行LaunchActivityItem和ResumeActivityItem的execute方法 item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); if (r == null) { // Launch activity request will create an activity record. r = mTransactionHandler.getActivityClient(token); } if (postExecutionState != UNDEFINED && r != null) { // Skip the very last transition and perform it by explicit state request instead. final boolean shouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction); } } } // ... }
最終調(diào)用到了ActivityThread#handleResumeActivity
方法,執(zhí)行了resume,并調(diào)用的addView將DecorView和WindowManagerImpl進行關(guān)聯(lián)。
/** * Request to move an activity to resumed state. * @hide */ public class ResumeActivityItem extends ActivityLifecycleItem { private static final String TAG = "ResumeActivityItem"; // ... @Override public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); // client是android.app.ActivityThread client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward, "RESUME_ACTIVITY"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } // ... } // android.app.ActivityThread#handleResumeActivity @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; // 執(zhí)行Activity的Resume方法 if (!performResumeActivity(r, finalStateRequest, reason)) { return; } // ... if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (r.mPreserveWindow) { a.mWindowAdded = true; r.mPreserveWindow = false; // Normally the ViewRoot sets up callbacks with the Activity // in addView->ViewRootImpl#setView. If we are instead reusing // the decor view we have to notify the view root that the // callbacks may have changed. ViewRootImpl impl = decor.getViewRootImpl(); if (impl != null) { impl.notifyChildRebuilt(); } } if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; // 將DecorView和WindowManagerImpl進行關(guān)聯(lián) 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; } // ... Looper.myQueue().addIdleHandler(new Idler()); }
在addView
方法中創(chuàng)建了ViewRootImpl
實例,并將ViewRootImpl
實例和DecorView
實例進行維護,最后調(diào)用setView
將DecorView
和ViewRootImpl
進行關(guān)聯(lián),后續(xù)由ViewRootImpl
作為橋梁來間接和DecorView
進行交互。
/** * Provides low-level communication with the system window manager for * operations that are not associated with any particular context. * * This class is only used internally to implement global functions where * the caller already knows the display and relevant compatibility information * for the operation. For most purposes, you should use {@link WindowManager} instead * since it is bound to a context. * * @see WindowManagerImpl * @hide */ public final class WindowManagerGlobal { @UnsupportedAppUsage private final ArrayList<View> mViews = new ArrayList<View>(); @UnsupportedAppUsage private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); @UnsupportedAppUsage private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId) { // ... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; ViewRootImpl root; View panelParentView = null; synchronized (mLock) { // ... IWindowSession windowlessSession = null; // ... // 創(chuàng)建ViewRootImpl實例 if (windowlessSession == null) { root = new ViewRootImpl(view.getContext(), display); } else { root = new ViewRootImpl(view.getContext(), display, windowlessSession); } view.setLayoutParams(wparams); // 維護DecorView、ViewRootImpl實例 mViews.add(view); mRoots.add(root); mParams.add(wparams); // do this last because it fires off messages to start doing things try { // 調(diào)用setView將DecorView和ViewRootImpl進行關(guān)聯(lián),后續(xù)由ViewRootImpl作為橋梁來間接和DecorView進行交互 root.setView(view, wparams, panelParentView, userId); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } } // ... }
最終,我們來到了ViewRootImpl
的構(gòu)造函數(shù),在ViewRootImpl
的構(gòu)造函數(shù)中創(chuàng)建了Choreographer
實例,并作為ViewRootImpl
的成員變量持有了,這樣ViewRootImpl
就作為橋梁在App
應(yīng)用層和Android系統(tǒng)之間進行雙向通信。接下來看下Choreographer
是如何請求VSYNC
信號以及如何分發(fā)VSYNC
信號,最終實現(xiàn)App
的UI
不斷刷新到屏幕上。
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl { private static final String TAG = "ViewRootImpl"; public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session, boolean useSfChoreographer) { // ... // 創(chuàng)建Choreographer實例 mChoreographer = useSfChoreographer ? Choreographer.getSfInstance() : Choreographer.getInstance(); // ... } // ... } /** * Coordinates the timing of animations, input and drawing. * <p> * The choreographer receives timing pulses (such as vertical synchronization) * from the display subsystem then schedules work to occur as part of rendering * the next display frame. * </p><p> * Applications typically interact with the choreographer indirectly using * higher level abstractions in the animation framework or the view hierarchy. * Here are some examples of things you can do using the higher-level APIs. * </p> * <ul> * <li>To post an animation to be processed on a regular time basis synchronized with * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li> * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display * frame, use {@link View#postOnAnimation}.</li> * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display * frame after a delay, use {@link View#postOnAnimationDelayed}.</li> * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the * next display frame, use {@link View#postInvalidateOnAnimation()} or * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li> * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in * sync with display frame rendering, do nothing. This already happens automatically. * {@link View#onDraw} will be called at the appropriate time.</li> * </ul> * <p> * However, there are a few cases where you might want to use the functions of the * choreographer directly in your application. Here are some examples. * </p> * <ul> * <li>If your application does its rendering in a different thread, possibly using GL, * or does not use the animation framework or view hierarchy at all * and you want to ensure that it is appropriately synchronized with the display, then use * {@link Choreographer#postFrameCallback}.</li> * <li>... and that's about it.</li> * </ul> * <p> * Each {@link Looper} thread has its own choreographer. Other threads can * post callbacks to run on the choreographer but they will run on the {@link Looper} * to which the choreographer belongs. * </p> */ public final class Choreographer { private static final String TAG = "Choreographer"; // Thread local storage for the choreographer. 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; } }; 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(); } // b/68769804: For low FPS experiments. setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1)); } /** * Gets the choreographer for the calling thread. Must be called from * a thread that already has a {@link android.os.Looper} associated with it. * * @return The choreographer for this thread. * @throws IllegalStateException if the thread does not have a looper. */ public static Choreographer getInstance() { return sThreadInstance.get(); } }
從上面的分析中,我們知道了Choreographer
的創(chuàng)建時機是在Activity#onResume
執(zhí)行之后,可見Android系統(tǒng)這么設(shè)計是出于Activity
是Android應(yīng)用中承載UI
的容器,只有容器創(chuàng)建之后,才需要創(chuàng)建Choreographer
來調(diào)度VSYNC
信號,最終開啟一幀幀的界面渲染和刷新。
那么會不會在每啟動一個Activity
之后都會創(chuàng)建一個Choreographer
實例呢?答案是不會的,因為從Choreographer
的構(gòu)造過程可以知道,Choreographer
的創(chuàng)建是通過ThreadLocal
實現(xiàn)的,所以Choreographer
是線程單例的,所以主線程只會創(chuàng)建一個Choreographer
實例。
那么是不是任何一個線程都可以創(chuàng)建Choreographer
實例呢?答案是只有創(chuàng)建了Looper
的線程才能創(chuàng)建Choreographer
實例,原因是Choreographer
會通過Looper
進行線程切換,至于為什么線程切換將會在下面進行分析回答。
VSYNC信號的調(diào)度分發(fā)流程
下面我們結(jié)合源碼分析下,Choreographer
是如何調(diào)度VSYNC
信號的,調(diào)度之后又是如何接收VSYNC
信號的,接收到VSYNC
信號之后又是怎么處理的。
首先,我們看下Choreographer
的構(gòu)造函數(shù)做了哪些事情來實現(xiàn)VSYNC
信號的調(diào)度分發(fā)。首先,基于主線程的Looper
創(chuàng)建了FrameHandler
用于線程切換,保證是在主線程請求調(diào)度VSYNC
信號以及在主線程處理接收到的VSYNC
信號。接著,創(chuàng)建了FrameDisplayEventReceiver
用于請求和接收VSYNC
信號。最后,創(chuàng)建了CallbackQueue
類型的數(shù)組,用于接收業(yè)務(wù)層投遞的各種類型的任務(wù)。
private Choreographer(Looper looper, int vsyncSource) { mLooper = looper; // 負責線程切換 mHandler = new FrameHandler(looper); // 負責請求和接收VSYNC信號 mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null; mLastFrameTimeNanos = Long.MIN_VALUE; mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); // 存儲業(yè)務(wù)提交的任務(wù),四種任務(wù)類型 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)); }
private final class CallbackQueue { private CallbackRecord mHead; // ... } // 鏈表結(jié)構(gòu) private static final class CallbackRecord { public CallbackRecord next; public long dueTime; /** Runnable or FrameCallback or VsyncCallback object. */ public Object action; /** Denotes the action type. */ public Object token; // ... }
下面結(jié)合源碼看下FrameDisplayEventReceiver
的創(chuàng)建過程,可以看到FrameDisplayEventReceiver
繼承自DisplayEventReceiver
,并在構(gòu)造函數(shù)中調(diào)用了DisplayEventReceiver
的構(gòu)造函數(shù)。因此,我們繼續(xù)跟下DisplayEventReceiver
的構(gòu)造函數(shù)。
private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { private boolean mHavePendingVsync; private long mTimestampNanos; private int mFrame; private VsyncEventData mLastVsyncEventData = new VsyncEventData(); // 直接調(diào)用DisplayEventReceiver的構(gòu)造函數(shù) public FrameDisplayEventReceiver(Looper looper, int vsyncSource) { super(looper, vsyncSource, 0); } @Override public void onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData) { try { long now = System.nanoTime(); if (timestampNanos > now) { 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; mLastVsyncEventData = vsyncEventData; // 發(fā)送異步消息到主線程 Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } // 在主線程執(zhí)行 @Override public void run() { mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame, mLastVsyncEventData); } }
DisplayEventReceiver
的構(gòu)造函數(shù)中將主線程的MessageQueue
取出,之后調(diào)用了nativeInit
方法并傳遞了主線程的MessageQueue
,并將自身作為參數(shù)也一起傳入nativeInit
方法。
/** * Provides a low-level mechanism for an application to receive display events * such as vertical sync. * * The display event receive is NOT thread safe. Moreover, its methods must only * be called on the Looper thread to which it is attached. * * @hide */ public abstract class DisplayEventReceiver { /** * Creates a display event receiver. * * @param looper The looper to use when invoking callbacks. * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values. * @param eventRegistration Which events to dispatch. Must be a bitfield consist of the * EVENT_REGISTRATION_*_FLAG values. */ public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) { if (looper == null) { throw new IllegalArgumentException("looper must not be null"); } mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue, vsyncSource, eventRegistration); } private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver, MessageQueue messageQueue, int vsyncSource, int eventRegistration); }
而nativeInit
是一個native方法,具體邏輯是通過C++實現(xiàn)的,代碼位于android_view_DisplayEventReceiver.cpp中。其中關(guān)鍵的部分是NativeDisplayEventReceiver
的創(chuàng)建以及調(diào)用initialize
方法進行初始化。
// frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak, jobject messageQueueObj, jint vsyncSource, jint eventRegistration, jlong layerHandle) { // 獲取native層的MessageQueue對象 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } // 創(chuàng)建native層的DisplayEventReceiver,即NativeDisplayEventReceiver sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue, vsyncSource, eventRegistration, layerHandle); // 調(diào)用initialize進行初始化 status_t status = receiver->initialize(); if (status) { String8 message; message.appendFormat("Failed to initialize display event receiver. status=%d", status); jniThrowRuntimeException(env, message.c_str()); return 0; } receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object return reinterpret_cast<jlong>(receiver.get()); } // 父類是DisplayEventDispatcher class NativeDisplayEventReceiver : public DisplayEventDispatcher { public: NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, jobject vsyncEventDataWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource, jint eventRegistration, jlong layerHandle); void dispose(); protected: virtual ~NativeDisplayEventReceiver(); private: jobject mReceiverWeakGlobal; jobject mVsyncEventDataWeakGlobal; sp<MessageQueue> mMessageQueue; void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, VsyncEventData vsyncEventData) override; void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; void dispatchHotplugConnectionError(nsecs_t timestamp, int errorCode) override; void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, nsecs_t renderPeriod) override; void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) override; void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {} void dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int connectedLevel, int maxLevel) override; }; NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, jobject vsyncEventDataWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource, jint eventRegistration, jlong layerHandle) // 父類構(gòu)造函數(shù) : DisplayEventDispatcher( messageQueue->getLooper(), static_cast<gui::ISurfaceComposer::VsyncSource>(vsyncSource), static_cast<gui::ISurfaceComposer::EventRegistration>(eventRegistration), layerHandle != 0 ? sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(layerHandle)) : nullptr ), // Java層的receiver mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), mVsyncEventDataWeakGlobal(env->NewGlobalRef(vsyncEventDataWeak)), mMessageQueue(messageQueue) { ALOGV("receiver %p ~ Initializing display event receiver.", this); }
首先看下NativeDisplayEventReceiver
對象的創(chuàng)建,NativeDisplayEventReceiver
的父類是DisplayEventDispatcher
。查看源碼可以判斷出DisplayEventDispatcher
是用于分發(fā)VSYNC
、Hotplug
等信號的,而DisplayEventDispatcher
內(nèi)部會創(chuàng)建DisplayEventReceiver
對象用于接收SurfaceFlinger
進程發(fā)送過來的信號。
// frameworks/native/libs/gui/DisplayEventDispatcher.cpp DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper, gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration, const sp<IBinder>& layerHandle) : mLooper(looper), mReceiver(vsyncSource, eventRegistration, layerHandle), // DisplayEventReceiver mWaitingForVsync(false), mLastVsyncCount(0), mLastScheduleVsyncTime(0) { ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this); } // frameworks/native/libs/gui/DisplayEventReceiver.cpp DisplayEventReceiver::DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration, const sp<IBinder>& layerHandle) { // 獲取SurfaceFlinger的代理對象 sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); if (sf != nullptr) { mEventConnection = nullptr; // 創(chuàng)建一個與SurfaceFlinger進程中的EventTread-app線程的vsyncSource信號連接 binder::Status status = sf->createDisplayEventConnection(vsyncSource, static_cast<gui::ISurfaceComposer::EventRegistration>(eventRegistration.get()), layerHandle, &mEventConnection); if (status.isOk() && mEventConnection != nullptr) { // 創(chuàng)建成功之后,構(gòu)造一個BitTube對象,并將上面創(chuàng)建好的連接的讀端描述拷貝過來,用于后續(xù)VSYNC信號的監(jiān)聽 mDataChannel = std::make_unique<gui::BitTube>(); // 拷貝SurfaceFlinger進程中創(chuàng)建的Scoket讀端描述符 status = mEventConnection->stealReceiveChannel(mDataChannel.get()); if (!status.isOk()) { ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str()); mInitError = std::make_optional<status_t>(status.transactionError()); mDataChannel.reset(); mEventConnection.clear(); } } else { ALOGE("DisplayEventConnection creation failed: status=%s", status.toString8().c_str()); } } } // frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp sp<EventThreadConnection> EventThread::createEventConnection(EventRegistrationFlags eventRegistration) const { auto connection = sp<EventThreadConnection>::make(const_cast<EventThread*>(this), IPCThreadState::self()->getCallingUid(), eventRegistration); if (FlagManager::getInstance().misc1()) { const int policy = SCHED_FIFO; connection->setMinSchedulerPolicy(policy, sched_get_priority_min(policy)); } return connection; } // 創(chuàng)建了BitTube,內(nèi)部創(chuàng)建了Socket EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, EventRegistrationFlags eventRegistration) : mOwnerUid(callingUid), mEventRegistration(eventRegistration), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
從源碼中可以看到,BitTube
是用于接收SurfaceFlinger
進程發(fā)送過來的信號的,從BitTube
的類文件可以看出,BitTube
內(nèi)部是通過Socket
來實現(xiàn)跨進程發(fā)送信號的。
// frameworks/native/libs/gui/BitTube.cpp static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024; BitTube::BitTube(size_t bufsize) { init(bufsize, bufsize); } void BitTube::init(size_t rcvbuf, size_t sndbuf) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) { size_t size = DEFAULT_SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); // since we don't use the "return channel", we keep it small... setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); fcntl(sockets[0], F_SETFL, O_NONBLOCK); fcntl(sockets[1], F_SETFL, O_NONBLOCK); mReceiveFd.reset(sockets[0]); mSendFd.reset(sockets[1]); } else { mReceiveFd.reset(); ALOGE("BitTube: pipe creation failed (%s)", strerror(errno)); } } base::unique_fd BitTube::moveReceiveFd() { return std::move(mReceiveFd); }
總結(jié)一下,Choreographer的創(chuàng)建流程:
VSYNC信號的請求
對于刷新率為60Hz的屏幕來說,一般是每16.67ms產(chǎn)生一個VSYNC
信號,但是每個App
進程不一定會每個VSYNC
信號都會接收,而是根據(jù)上層業(yè)務(wù)的實際需要進行VSYNC
信號的監(jiān)聽和接收。這樣設(shè)計的好處是可以按需觸發(fā)App
進程的渲染流程,降低不必要的渲染所帶來的功耗。
上層業(yè)務(wù)一般會通過validate
或者requestLayout
方法來發(fā)起一次繪制請求,最終這個繪制請求會被轉(zhuǎn)換成CallbackRecord
放入對應(yīng)類型的CallbackQueue
中。
public final class Choreographer { // ... private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { synchronized (mLock) { final long now = SystemClock.uptimeMillis(); // 計算任務(wù)執(zhí)行的具體時間戳 final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { // 如果不需要延遲執(zhí)行的話,則立即請求調(diào)度VSYNC信號 scheduleFrameLocked(now); } else { // 否則通過延遲消息來請求調(diào)度VSYNC信號 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); msg.arg1 = callbackType; msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, dueTime); } } } private void scheduleFrameLocked(long now) { if (!mFrameScheduled) { mFrameScheduled = true; if (USE_VSYNC) { // 檢查當前線程是否為主線程,如果是主線程,直接請求調(diào)度VSYNC信號,否則向主線程發(fā)送異步消息來請求調(diào)度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); } } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void scheduleVsyncLocked() { try { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked"); // 通過調(diào)用FrameDisplayEventReceiver的scheduleVsync方法請求VSYNC信號 mDisplayEventReceiver.scheduleVsync(); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } // ... }
最終調(diào)用了native
方法向SurfaceFlinger
進程進行通信,請求分發(fā)VSYNC
信號到App
進程。之前創(chuàng)建Choreographer
的過程中,創(chuàng)建了DisplayEventReceiver
并通過JNI
調(diào)用到了native層,在native層創(chuàng)建了NativeDisplayEventReceiver
對象之后,將其返回了Java層,并保存在了Java層的DisplayEventReceiver
對象中。Java層通過JNI
調(diào)用到native層并將之前創(chuàng)建的NativeDisplayEventReceiver
指針傳回了native層,這樣就可以在native層找到之前創(chuàng)建好的NativeDisplayEventReceiver
對象,并調(diào)用其scheduleVsync
方法,最終通過mEventConnection
完成跨進程請求,
// android.view.DisplayEventReceiver#scheduleVsync @UnsupportedAppUsage 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); } } // frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { sp<NativeDisplayEventReceiver> receiver = reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr); status_t status = receiver->scheduleVsync(); if (status) { String8 message; message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status); jniThrowRuntimeException(env, message.c_str()); } } // frameworks/native/libs/gui/DisplayEventDispatcher.cpp status_t DisplayEventDispatcher::scheduleVsync() { if (!mWaitingForVsync) { ALOGV("dispatcher %p ~ Scheduling vsync.", this); // Drain all pending events. nsecs_t vsyncTimestamp; PhysicalDisplayId vsyncDisplayId; uint32_t vsyncCount; VsyncEventData vsyncEventData; if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) { ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp))); } // 請求下一個VSYNC信號 status_t status = mReceiver.requestNextVsync(); if (status) { ALOGW("Failed to request next vsync, status=%d", status); return status; } mWaitingForVsync = true; mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC); } return OK; } // frameworks/native/libs/gui/DisplayEventReceiver.cpp status_t DisplayEventReceiver::requestNextVsync() { if (mEventConnection != nullptr) { mEventConnection->requestNextVsync(); return NO_ERROR; } return mInitError.has_value() ? mInitError.value() : NO_INIT; }
VSYNC信號的分發(fā)
當SurfaceFlinger
進程通過Socket
通知App
進程VSYNC
信號到達之后,App
進程的handleEvent
方法將會被調(diào)用,最終通過JNI
調(diào)用到Java層的FrameDisplayEventReceiver#dispatchVsync
方法。
// frameworks/native/libs/gui/DisplayEventDispatcher.cpp int DisplayEventDispatcher::handleEvent(int, int events, void*) { if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { return 0; // remove the callback } if (!(events & Looper::EVENT_INPUT)) { return 1; // keep the callback } // Drain all pending events, keep the last vsync. nsecs_t vsyncTimestamp; PhysicalDisplayId vsyncDisplayId; uint32_t vsyncCount; VsyncEventData vsyncEventData; if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) { mWaitingForVsync = false; mLastVsyncCount = vsyncCount; dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData); } if (mWaitingForVsync) { const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime; if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) { mWaitingForVsync = false; dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */, ++mLastVsyncCount, vsyncEventData /* empty data */); } } return 1; // keep the callback } // frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, VsyncEventData vsyncEventData) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); ScopedLocalRef<jobject> vsyncEventDataObj(env, GetReferent(env, mVsyncEventDataWeakGlobal)); if (receiverObj.get() && vsyncEventDataObj.get()) { env->SetIntField(vsyncEventDataObj.get(), gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex, syncEventData.preferredFrameTimelineIndex); env->SetIntField(vsyncEventDataObj.get(), gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelinesLength, vsyncEventData.frameTimelinesLength); env->SetLongField(vsyncEventDataObj.get(), gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval, vsyncEventData.frameInterval); ScopedLocalRef<jobjectArray> frameTimelinesObj(env, reinterpret_cast<jobjectArray>(env->GetObjectField(vsyncEventDataObj.get(), gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelines))); for (size_t i = 0; i < vsyncEventData.frameTimelinesLength; i++) { VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i]; ScopedLocalRef<jobject> frameTimelineObj(env, env->GetObjectArrayElement(frameTimelinesObj.get(), i)); env->SetLongField(frameTimelineObj.get(), gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId, frameTimeline.vsyncId); env->SetLongField(frameTimelineObj.get(), gDisplayEventReceiverClassInfo.frameTimelineClassInfo .expectedPresentationTime, frameTimeline.expectedPresentationTime); env->SetLongField(frameTimelineObj.get(), gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline, frameTimeline.deadlineTimestamp); } // 最終調(diào)用到了Java層的dispatchVsync env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId.value, count); ALOGV("receiver %p ~ Returned from vsync handler.", this); } mMessageQueue->raiseAndClearException(env, "dispatchVsync"); }
// android.view.DisplayEventReceiver // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData) { onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData); } // android.view.Choreographer.FrameDisplayEventReceiver @Override public void onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData) { try { long now = System.nanoTime(); if (timestampNanos > now) { 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; mLastVsyncEventData = vsyncEventData; Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); // 異步消息,利用之前插入的同步屏障來加速消息的處理 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } @Override public void run() { mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame, mLastVsyncEventData); }
最終調(diào)用到了Choreographer#doFrame
方法,到了這里就開始了新的一幀的處理,開始下一幀的數(shù)據(jù)準備工作。
VSYNC信號的處理
App
進程收到VSYNC
信號之后就會調(diào)用doFrame
方法開始新的一幀數(shù)據(jù)的準備工作,其中還會計算卡頓時間,即VSYNC
信號到達之后多久才被主線程處理,等待時間過長會導(dǎo)致無法在一幀時間內(nèi)完成數(shù)據(jù)準備的工作,最終導(dǎo)致用戶看到的視覺效果不夠流暢。
// android.view.Choreographer void doFrame(long frameTimeNanos, int frame, DisplayEventReceiver.VsyncEventData vsyncEventData) { final long startNanos; final long frameIntervalNanos = vsyncEventData.frameInterval; try { FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData); synchronized (mLock) { if (!mFrameScheduled) { traceMessage("Frame not scheduled"); return; // no work to do } long intendedFrameTimeNanos = frameTimeNanos; startNanos = System.nanoTime(); // frameTimeNanos是SurfaceFlinger傳遞給來的時間戳,可能會被校準為App進程接收到VSYNC信號的時間戳 // jitterNanos包含了Handler處理消息的耗時,即異步消息被處理之前,主線程還在處理其他消息所占用的時間,如果這個時間過長會導(dǎo)致卡頓 final long jitterNanos = startNanos - frameTimeNanos; if (jitterNanos >= frameIntervalNanos) { long lastFrameOffset = 0; if (frameIntervalNanos == 0) { Log.i(TAG, "Vsync data empty due to timeout"); } else { lastFrameOffset = jitterNanos % frameIntervalNanos; final long skippedFrames = jitterNanos / frameIntervalNanos; if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main " + "thread."); } if (DEBUG_JANK) { Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " + "which is more than the frame interval of " + (frameIntervalNanos * 0.000001f) + " ms! " + "Skipping " + skippedFrames + " frames and setting frame " + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); } } frameTimeNanos = startNanos - lastFrameOffset; frameData.updateFrameData(frameTimeNanos); } 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."); } traceMessage("Frame time goes backward"); scheduleVsyncLocked(); return; } if (mFPSDivisor > 1) { long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos; if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) { traceMessage("Frame skipped due to FPSDivisor"); scheduleVsyncLocked(); return; } } mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.preferredFrameTimeline().vsyncId, vsyncEventData.preferredFrameTimeline().deadline, startNanos, vsyncEventData.frameInterval); mFrameScheduled = false; mLastFrameTimeNanos = frameTimeNanos; mLastFrameIntervalNanos = frameIntervalNanos; mLastVsyncEventData = vsyncEventData; } // 開始執(zhí)行各種類型的Callback AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart(); doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos); mFrameInfo.markAnimationsStart(); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData, frameIntervalNanos); mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }
接著,就會將之前業(yè)務(wù)提交的各種類型的CallbackRecord
,主要分為:
- CALLBACK_INPUT:輸入類型,比如屏幕觸摸事件,最先執(zhí)行;
- CALLBACK_ANIMATION:動畫類型,比如屬性動畫;
- CALLBACK_INSETS_ANIMATION:背景更新動畫;
- CALLBACK_TRAVERSAL:布局繪制類型,View的測量、布局和繪制等;
- CALLBACK_COMMIT:提交繪制數(shù)據(jù);
按照順序執(zhí)行完所有的CallbackRecord
之后,App
進程的繪制任務(wù)就完成了,最終數(shù)據(jù)提交到GraphicBuffer
中,最終調(diào)度sf
類型的VSYNC
信號,最后由SurfaceFlinger
完成數(shù)據(jù)合成和送顯。
總結(jié)一下,VSYNC
信號的分發(fā)處理流程:
總結(jié)
整個Choreographer
工作機制作為App
進程和SurfaceFlinger
進程的協(xié)調(diào)機制,承接App
進程的業(yè)務(wù)刷新UI
的請求,統(tǒng)一調(diào)度VSYNC
信號,將UI
渲染任務(wù)同步到 VSYNC
信號的時間線上。同時作為中轉(zhuǎn)站來分發(fā)VSYNC
信號,并處理上層業(yè)務(wù)的刷新請求。按照 VSYNC
信號的周期有規(guī)律地準備每一幀數(shù)據(jù),并通過SurfaceFlinger
進程完成合成上屏。
到此這篇關(guān)于淺析Android中的Choreographer工作原理的文章就介紹到這了,更多相關(guān)Android Choreographer工作原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android BroadcastReceiver廣播機制概述
這篇文章主要為大家詳細介紹了Android BroadcastReceiver廣播機制,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-08-08Android多線程+單線程+斷點續(xù)傳+進度條顯示下載功能
這篇文章主要介紹了Android多線程+單線程+斷點續(xù)傳+進度條顯示下載功能,需要的朋友可以參考下2017-06-06Android 關(guān)于ExpandableListView去掉里頭分割線的方法
下面小編就為大家?guī)硪黄狝ndroid 關(guān)于ExpandableListView去掉里頭分割線的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12Android自定義View系列之Path繪制仿支付寶支付成功動畫
這篇文章主要為大家詳細介紹了Android自定義View系列之Path繪制仿支付寶支付成功動畫,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12Android用RecyclerView實現(xiàn)動態(tài)添加本地圖片
本篇文章主要介紹了Android用RecyclerView實現(xiàn)動態(tài)添加本地圖片,具有一定的參考價值,有興趣的可以了解一下2017-08-08