Android显示系统
显示系统
CPU : 负责计算帧数据,把计算好的数据交给 GPU
GPU : 对图形数据进行渲染,渲染好后放到 buffer (图像缓冲区)中存起来
Display : 屏幕或者显示器,负责把 buffer 中的数据呈现到屏幕上
Choreographer
编舞者,用来控制当收到 VSync 信号后才开始绘制任务,保证绘制拥有完整的 16.6 ms.
入口: scheduleTraversals
在调用 startActivity 后, 经过 AMS 的一些处理, 后面又通过 Binder 调用目标进程的 ActivityThread.handleResumeActivity 方法,在这个方法里会回调目标 Activity 的 onResume 和 makeVisible 方法, 在 makeVisible 方法里完成 WindowManager.addView 的过程,这个过程调用了 ViewRootImpl.setView 方法, 内部又调用其 scheduleTraversals 方法,最后会走到 perfromTraversals 方法,接着就到了 measure, layout, draw 三大流程了。
// frameworks/base/core/java/android/view/ViewRootImpl.java
2351 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2352 void scheduleTraversals() {
2353 if (!mTraversalScheduled) {
// 保证同时间多次更改只会刷新一次
2354 mTraversalScheduled = true;
2355 // nubia modify for app launch traversals accelerate
2356 //mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
2357 if (!ActivityThread.ZTE_TRAVERSAL_ACCELERATE_ENABLED || !mHasStartTraversalsAccelerate) {
// 添加同步屏障,保证Vsync 到来立即执行绘制
2358 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
2359 } else {
2360 Log.d(mTag, "scheduleTraversals ,mHasStartTraversalsAccelerate: " + mHasStartTraversalsAccelerate);
2361 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrierAtFrontByZTE();
2362 }
2363 // nubia modify end
2364 //none-ui thread postSyncBarrie may case block,check it here
2365 if (mThread != Thread.currentThread()) {
2366 Slog.w(mTag, "postSyncBarrier() from None-UIThread!,vripl=" + this
2367 + ",barrier=" + mTraversalBarrier
2368 + ",t=" + mThread + ",curT=" + Thread.currentThread());
2369 }
2370 mChoreographer.postCallback(
2371 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
2372 notifyRendererOfFramePending();
2373 pokeDrawLockIfNeeded();
2374 }
2375 }
...
9059 final class TraversalRunnable implements Runnable {
9060 @Override
9061 public void run() {
9062 doTraversal();
9063 }
9064 }
9065 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
...
...
2400 void doTraversal() {
2401 if (mTraversalScheduled) {
2402 mTraversalScheduled = false;
2403 // nubia modify for app launch traversals accelerate
2404 //mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2405 if (ActivityThread.ZTE_TRAVERSAL_ACCELERATE_ENABLED) {
2406 if (!mHasStartTraversalsAccelerate) {
2407 if (mHandler.getLooper().getQueue().checkHasSyncBarrier(mTraversalBarrier)) {
// 移除同步屏障
2408 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2409 }
2410 }
2411 } else {
2412 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2413 }
2414 // nubia modify end
2415 if (mProfile) {
2416 Debug.startMethodTracing("ViewAncestor");
2417 }
2418 // 真正执行 View 的 measure , layout, draw 流程
2419 performTraversals();
2420
2421 if (mProfile) {
2422 Debug.stopMethodTracing();
2423 mProfile = false;
2424 }
2425 }
2426 }
首先使用 mTraversalScheduled 字段保证同时间多次更改只会刷新一次。
然后为当前线程的 MessageQueue 添加同步屏障,来屏蔽同步消息,保证 VSync 到来后立即执行绘制,而不是等前面的同步消息。
调用 mChoreographer.postCallback() 方法发送了一个会在下一帧执行的回调,即在下一个 VSync 到来时会执行 TraversalRunnable->doTrvaersal()->performTraversals()->绘制流程。
Choreographer 实例化
// frameworks/base/core/java/android/view/Choreographer.java
95 public final class Choreographer {
96 private static final String TAG = "Choreographer";
97
98 // Prints debug messages about jank which was detected (low volume).
99 private static final boolean DEBUG_JANK = false;
100 private static final boolean OPTS_INPUT = true;
101
102 // Prints debug messages about every frame and callback registered (high volume).
103 private static final boolean DEBUG_FRAMES = false;
104
105 // The default amount of time in ms between animation frames.
106 // When vsync is not enabled, we want to have some idea of how long we should
107 // wait before posting the next animation message. It is important that the
108 // default value be less than the true inter-frame delay on all devices to avoid
109 // situations where we might skip frames by waiting too long (we must compensate
110 // for jitter and hardware variations). Regardless of this value, the animation
111 // and display loop is ultimately rate-limited by how fast new graphics buffers can
112 // be dequeued.
113 private static final long DEFAULT_FRAME_DELAY = 10;
114 private static final int TOP_APP_ADJ = 0;
115 private static final int PERCEPTIBLE_APP_ADJ = 200;
116
117 // The number of milliseconds between animation frames.
118 private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
119
120 // Thread local storage for the choreographer.
121 private static final ThreadLocal<Choreographer> sThreadInstance =
122 new ThreadLocal<Choreographer>() {
123 @Override
124 protected Choreographer initialValue() {
125 Looper looper = Looper.myLooper();
126 if (looper == null) {
127 throw new IllegalStateException("The current thread must have a looper!");
128 }
129 Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
130 if (looper == Looper.getMainLooper()) {
131 mMainInstance = choreographer;
132 }
133 return choreographer;
134 }
135 };
136
137 private static volatile Choreographer mMainInstance;
138
139 // Thread local storage for the SF choreographer.
140 private static final ThreadLocal<Choreographer> sSfThreadInstance =
141 new ThreadLocal<Choreographer>() {
142 @Override
143 protected Choreographer initialValue() {
144 Looper looper = Looper.myLooper();
145 if (looper == null) {
146 throw new IllegalStateException("The current thread must have a looper!");
147 }
148 return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
149 }
150 };
...
300 private Choreographer(Looper looper, int vsyncSource) {
301 mLooper = looper;
// 使用当前线程 looper 创建 Handler
302 mHandler = new FrameHandler(looper);
303 mDisplayEventReceiver = USE_VSYNC
304 ? new FrameDisplayEventReceiver(looper, vsyncSource)
305 : null;
306 mLastFrameTimeNanos = Long.MIN_VALUE;
307 // 计算一帧的时间,即16ms
308 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
309 ScrollOptimizer.setFrameInterval(mFrameIntervalNanos);
310
311 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
312 for (int i = 0; i <= CALLBACK_LAST; i++) {
313 mCallbackQueues[i] = new CallbackQueue();
314 }
315 // b/68769804: For low FPS experiments.
316 setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
317 }
Choreographer 中共有四种 callbackType:
//
/**
243 * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
244 * @hide
245 */
246 private static final String[] CALLBACK_TRACE_TITLES = {
247 "input", "animation", "insets_animation", "traversal", "commit"
248 };
249
250 /**
251 * Callback type: Input callback. Runs first.
252 * @hide
253 */
// 输入事件
254 public static final int CALLBACK_INPUT = 0;
255
256 /**
257 * Callback type: Animation callback. Runs before {@link #CALLBACK_INSETS_ANIMATION}.
258 * @hide
259 */
260 @TestApi // 动画
261 public static final int CALLBACK_ANIMATION = 1;
262
263 /**
264 * Callback type: Animation callback to handle inset updates. This is separate from
265 * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
266 * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} for multiple
267 * ongoing animations but then update the whole view system with a single callback to
268 * {@link View#dispatchWindowInsetsAnimationProgress} that contains all the combined updated
269 * insets.
270 * <p>
271 * Both input and animation may change insets, so we need to run this after these callbacks, but
272 * before traversals.
273 * <p>
274 * Runs before traversals.
275 * @hide
276 */
// 窗口刷新, 执行 measure / layout / draw 操作
277 public static final int CALLBACK_INSETS_ANIMATION = 2;
278
279 /**
280 * Callback type: Traversal callback. Handles layout and draw. Runs
281 * after all other asynchronous messages have been handled.
282 * @hide
283 */
284 public static final int CALLBACK_TRAVERSAL = 3;
285
286 /**
287 * Callback type: Commit callback. Handles post-draw operations for the frame.
288 * Runs after traversal completes. The {@link #getFrameTime() frame time} reported
289 * during this callback may be updated to reflect delays that occurred while
290 * traversals were in progress in case heavy layout operations caused some frames
291 * to be skipped. The frame time reported during this callback provides a better
292 * estimate of the start time of the frame in which animations (and other updates
293 * to the view hierarchy state) actually took effect.
294 * @hide
295 */
296 public static final int CALLBACK_COMMIT = 4;
297
298 private static final int CALLBACK_LAST = CALLBACK_COMMIT;
299
这四种类型的任务存入对应类型的 CallbackQueue 中, 每当收到 VSYNC 信号时,Choreographer 将按顺序处理这些类型的任务。
// FrameHandler ,它用来处理异步消息
1113 private final class FrameHandler extends Handler {
1114 public FrameHandler(Looper looper) {
1115 super(looper);
1116 }
1117
1118 @Override
1119 public void handleMessage(Message msg) {
1120 switch (msg.what) {
1121 case MSG_DO_FRAME:
1122 doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
1123 break;
1124 case MSG_DO_SCHEDULE_VSYNC:
1125 doScheduleVsync();
1126 break;
1127 case MSG_DO_SCHEDULE_CALLBACK:
1128 doScheduleCallback(msg.arg1);
1129 break;
1130 case MSG_DO_CHECK_BACKGROUND:
1131 doCheckBackgroundDrawing();
1132 break;
1133 }
1134 }
1135 }
1136
Vsync 信号注册
DisplayEventReceiver
mDisplayEventReceiver 是 FrameDisplayEventReceiver 类型的实例。
在 Choreographer 构造方法中实例化,其父类为 DisplayEventReceiver。
//frameworks/base/core/java/android/view/DisplayEventReceiver.java
82 private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
83 MessageQueue messageQueue, int vsyncSource, int eventRegistration);
...
106 public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
107 if (looper == null) {
108 throw new IllegalArgumentException("looper must not be null");
109 }
110
111 mMessageQueue = looper.getQueue();
// 注册 VSYNC 信号监听者
112 mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
113 vsyncSource, eventRegistration);
114 }
nativeInit
nativeInit 是一个 native 方法,其实现在 android_view_DisplayEventReceiver.cpp 中
// frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
178 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
179 jint vsyncSource, jint eventRegistration) {
180 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
181 if (messageQueue == NULL) {
182 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
183 return 0;
184 }
185
186 sp<NativeDisplayEventReceiver> receiver =
187 new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
188 eventRegistration);
189 status_t status = receiver->initialize();
190 if (status) {
191 String8 message;
192 message.appendFormat("Failed to initialize display event receiver. status=%d", status);
193 jniThrowRuntimeException(env, message.string());
194 return 0;
195 }
196
197 receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
198 return reinterpret_cast<jlong>(receiver.get());
199 }
NativeDisplayEventReceiver 继承于 DisplayEventDispatcher
// frameworks/native/libs/gui/DisplayEventReceiver.cpp
35 DisplayEventReceiver::DisplayEventReceiver(
36 ISurfaceComposer::VsyncSource vsyncSource,
37 ISurfaceComposer::EventRegistrationFlags eventRegistration) {
38 sp<ISurfaceComposer> sf(ComposerService::getComposerService());
39 if (sf != nullptr) {
40 mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
41 if (mEventConnection != nullptr) {
42 mDataChannel = std::make_unique<gui::BitTube>();
43 mEventConnection->stealReceiveChannel(mDataChannel.get());
44 }
45 }
46 }
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
return mSFEventThread->createEventConnection();
} else {
// vsyncSource 是 APP
return mEventThread->createEventConnection();
}
}
EventThread.createEventConnection 创建了一个对 Vsync 信号感兴趣的连接。
// frameworks/native/libs/gui/DisplayEventDispatcher.cpp
43 status_t DisplayEventDispatcher::initialize() {
44 status_t result = mReceiver.initCheck();
45 if (result) {
46 ALOGW("Failed to initialize display event receiver, status=%d", result);
47 return result;
48 }
49
50 if (mLooper != nullptr) {
// 用来监听 mReceiver 所获取的文件句柄,当有存在对 Vsync 信号感兴趣的连接且接收到了 Vsync 信号时
// 会发送数据到 mReceiver,然后回调 DisplayEventDispatcher 中的 handleEvent
51 int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
52 if (rc < 0) {
53 return UNKNOWN_ERROR;
54 }
55 }
56
57 return OK;
58 }
59
97 int DisplayEventDispatcher::getFd() const {
98 return mReceiver.getFd();
99 }
// frameworks/native/libs/gui/DisplayEventReceiver.cpp
57 int DisplayEventReceiver::getFd() const {
58 if (mDataChannel == nullptr)
59 return NO_INIT;
60
61 return mDataChannel->getFd();
62 }
mReceiver 是 DisplayEventReceiver 类型实例,位于 frameworks/native/libs/gui/DisplayEventReceiver.cpp
Looper.addFd
BitTube
是 Android 提供的一种进程通讯方式,它通过socketpair 来实现全双工的通讯。
在 BitTube 对象中有两个文件描述符: mReceivedFd 和 mSendFd, 以及 read 和 write 分别用来进行读写操作。
获取两个文件描述符的函数:
int BitTube::getFd() const {
return mReceivedFd;
}
int BitTube::getSendFd() const {
return mSendFd;
}
跨进程
上面 Choreographer 中的 mEventConnection 是 IDisplayEventConnection 类型,是一个 native 层的 Binder 代理对象,用来跟 SurfaceFlinger 跨进程通信,可以看到它通过 stealReceiveChannel 方法把 APP 进程端创建的 BitTube 指针传给了 SF 进程。
然后在 APP 进程又通过 Looper->addFd(mReceiver.getFd(), ...) 方法监听 mReceiveFd 描述符的数据,当 Vsync 信号到来后,SF 对 BitTube 做 send 操作,则 Looper 监听到对应 mReceiveFd 中的数据变化,于是触发 DisplayEventDispatcher.handleEvent 方法,该方法中会调用 mReceiver(DisplayEventReceiver).getEvents 方法,这个方法会调用 BitTube.recvObjects 拿到 SF 进程传来的数据(由于 Looper 触发了监听,此时 recvObjects 肯定能拿到数据,而不会阻塞),即表示 Vsync 信号来了。
请求 Vsync 信号
Choreographer.postCallback
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null):
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
public void postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException("action must not be null");
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
// 对应类型的CallbackQueue添加Callback
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);
// handleMessage会调用doScheduleCallback(msg.arg1)方法
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
void doScheduleCallback(int callbackType) {
synchronized (mLock) {
if (!mFrameScheduled) {
final long now = SystemClock.uptimeMillis();
if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now);
}
}
}
}
可以看到延迟与否都会调用 scheduleFrameLocked 方法。
Choreographer.scheduleFrameLocked
// frameworks/base/core/java/android/view/Choreographer.java
private void scheduleFrameLocked(long now) {
710 if (!mFrameScheduled) {
711 mFrameScheduled = true;
712 if (OPTS_INPUT) {
713 if (!mIsVsyncScheduled) {
714 long curr = System.nanoTime();
715 boolean skipFlag = curr - mLastTouchOptTimeNanos < mFrameIntervalNanos;
716 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "scheduleFrameLocked-mMotionEventType:"
717 + mMotionEventType + " mTouchMoveNum:"+ mTouchMoveNum
718 + " mConsumedDown:" + mConsumedDown
719 + " mConsumedMove:" + mConsumedMove
720 + " mIsDoFrameProcessing:" + mIsDoFrameProcessing
721 + " skip:" + skipFlag
722 + " diff:" + (curr - mLastTouchOptTimeNanos));
723 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
724 synchronized(this) {
725 switch(mMotionEventType) {
726 case MOTION_EVENT_ACTION_DOWN:
727 mConsumedMove = false;
728 if (!mConsumedDown && !skipFlag && !mIsDoFrameProcessing) {
729 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
730 msg.setAsynchronous(true);
731 mHandler.sendMessageAtFrontOfQueue(msg);
732 mLastTouchOptTimeNanos = System.nanoTime();
733 mConsumedDown = true;
734 return;
735 }
736 break;
737 case MOTION_EVENT_ACTION_MOVE:
738 mConsumedDown = false;
739 //if ((mTouchMoveNum == 1) && !mConsumedMove && !skipFlag) {
740 if (!mConsumedMove && !skipFlag && !mIsDoFrameProcessing) {
741 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
742 msg.setAsynchronous(true);
743 mHandler.sendMessageAtFrontOfQueue(msg);
744 mLastTouchOptTimeNanos = System.nanoTime();
745 mConsumedMove = true;
746 return;
747 }
748 break;
749 case MOTION_EVENT_ACTION_UP:
750 case MOTION_EVENT_ACTION_CANCEL:
751 mConsumedMove = false;
752 mConsumedDown = false;
753 break;
754 default:
755 break;
756 }
757 }
758 }
759 }
760 if (ZFrameMetricsListener.ZTE_FEATURE_ZFRAMEMETRICS && ZFrameMetricsListener.getInstance() != null) {
761 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "scheduleFrameLocked reportDrawEvent");
762 ZFrameMetricsListener.getInstance().reportDrawEvent();
763 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
764 }
765 if (ScrollOptimizer.shouldUseVsync(USE_VSYNC)) {
766 if (DEBUG_FRAMES) {
767 Log.d(TAG, "Scheduling next frame on vsync.");
768 }
769
770 // If running on the Looper thread, then schedule the vsync immediately,
771 // otherwise post a message to schedule the vsync from the UI thread
772 // as soon as possible.
773 if (!mVisible && !mBackgroundDrawing)
774 mBackgroundFrameCount++;
775
776 if (!mBackgroundDrawing) {
777 if (isRunningOnLooperThreadLocked()) {
778 scheduleVsyncLocked();
779 } else {
780 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
781 msg.setAsynchronous(true);
782 mHandler.sendMessageAtFrontOfQueue(msg);
783 }
784 } else {
785 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
786 msg.setAsynchronous(true);
787 mHandler.sendMessageDelayed(msg, 100);
788 }
789 } else {
790 sFrameDelay = ScrollOptimizer.getFrameDelay(sFrameDelay,
791 mLastFrameTimeNanos);
792 final long nextFrameTime = Math.max(
793 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
794 if (DEBUG_FRAMES) {
795 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
796 }
797 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
798 msg.setAsynchronous(true);
799 mHandler.sendMessageAtTime(msg, nextFrameTime);
800 }
801 }
802 }
803
...
1015 void doScheduleVsync() {
1016 synchronized (mLock) {
1017 if (mFrameScheduled) {
1018 scheduleVsyncLocked();
1019 }
1020 }
1021 }
...
1047 private void scheduleVsyncLocked() {
1048 try {
1049 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
1050 mDisplayEventReceiver.scheduleVsync();
1051 mIsVsyncScheduled = true;
1052 } finally {
1053 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1054 }
1055 }
1056
DisplayEventReceiver.scheduleVsync
public void scheduleVsync() {
if (mReceiverPtr == 0) {
// ...
} 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();
// ...
}
// frameworks/base/libs/androidfw/DisplayEventDispatcher.cpp
status_t DisplayEventDispatcher::scheduleVsync() {
if (!mWaitingForVsync) {
// Drain all pending events.
nsecs_t vsyncTimestamp;
int32_t vsyncDisplayId;
uint32_t vsyncCount;
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
}
status_t status = mReceiver.requestNextVsync();
mWaitingForVsync = true;
}
return OK;
}
// frameworks/native/libs/gui/DisplayEventReceiver.cpp
status_t DisplayEventReceiver::requestNextVsync() {
if (mEventConnection != NULL) {
// 请求接收下一次Vsync信号的回调
// 可以唤醒 EventThread 线程,等到 Vsync 信号到来后回调给 APP
mEventConnection->requestNextVsync();
return NO_ERROR;
}
return NO_INIT;
}
Vsync 回调流程
DisplayEventDispatcher::handleEvent
//frameworks/native/libs/gui/DisplayEventDispatcher.cpp
101 int DisplayEventDispatcher::handleEvent(int, int events, void*) {
102 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
103 ALOGE("Display event receiver pipe was closed or an error occurred. "
104 "events=0x%x",
105 events);
106 return 0; // remove the callback
107 }
108
109 if (!(events & Looper::EVENT_INPUT)) {
110 ALOGW("Received spurious callback for unhandled poll event. "
111 "events=0x%x",
112 events);
113 return 1; // keep the callback
114 }
115
116 // Drain all pending events, keep the last vsync.
117 nsecs_t vsyncTimestamp;
118 PhysicalDisplayId vsyncDisplayId;
119 uint32_t vsyncCount;
120 VsyncEventData vsyncEventData;
// 清除所有的 pending 事件,只保留最后一次 vsync
121 if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
122 ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
123 ", displayId=%s, count=%d, vsyncId=%" PRId64,
124 this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
125 vsyncEventData.id);
126 mWaitingForVsync = false;
127 dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
128 }
129
130 return 1; // keep the callback
131 }
132
// frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
101 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
102 uint32_t count, VsyncEventData vsyncEventData) {
103 JNIEnv* env = AndroidRuntime::getJNIEnv();
104
105 ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
106 if (receiverObj.get()) {
107 ALOGV("receiver %p ~ Invoking vsync handler.", this);
108 env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
109 timestamp, displayId.value, count, vsyncEventData.id,
110 vsyncEventData.deadlineTimestamp, vsyncEventData.frameInterval);
111 ALOGV("receiver %p ~ Returned from vsync handler.", this);
112 }
113
114 mMessageQueue->raiseAndClearException(env, "dispatchVsync");
115 }
116
...
233 int register_android_view_DisplayEventReceiver(JNIEnv* env) {
234 int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
235 NELEM(gMethods));
236
237 jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
238 gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
239
240 gDisplayEventReceiverClassInfo.dispatchVsync =
241 GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync",
242 "(JJIJJJ)V");
243 gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
244 gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
245 gDisplayEventReceiverClassInfo.dispatchModeChanged =
246 GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
247 "(JJI)V");
248 gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
249 GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
250 "dispatchFrameRateOverrides",
251 "(JJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V");
252
253 jclass frameRateOverrideClazz =
254 FindClassOrDie(env, "android/view/DisplayEventReceiver$FrameRateOverride");
255 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz =
256 MakeGlobalRefOrDie(env, frameRateOverrideClazz);
257 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init =
258 GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
259 "<init>", "(IF)V");
260
261 return res;
262 }
由上可知,回调到 Java 层android/view/DisplayEventReceiver 的 dispatchVsync 方法:
256 // Called from native code.
257 @SuppressWarnings("unused")
258 private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
259 long frameTimelineVsyncId, long frameDeadline, long frameInterval) {
260 onVsync(timestampNanos, physicalDisplayId, frame,
261 new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval));
262 }
263
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
1138 implements Runnable {
1139 private boolean mHavePendingVsync;
1140 private long mTimestampNanos;
1141 private int mFrame;
1142 private VsyncEventData mLastVsyncEventData = new VsyncEventData();
1143
1144 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
1145 super(looper, vsyncSource, 0);
1146 }
1147
1148 // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
1149 // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
1150 // for the internal display implicitly.
1151 @Override
1152 public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
1153 VsyncEventData vsyncEventData) {
1154 try {
1155 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1156 Trace.traceBegin(Trace.TRACE_TAG_VIEW,
1157 "Choreographer#onVsync " + vsyncEventData.id);
1158 }
1159 // Post the vsync event to the Handler.
1160 // The idea is to prevent incoming vsync events from completely starving
1161 // the message queue. If there are no messages in the queue with timestamps
1162 // earlier than the frame time, then the vsync event will be processed immediately.
1163 // Otherwise, messages that predate the vsync event will be handled first.
1164 long now = System.nanoTime();
1165 if (timestampNanos > now) {
1166 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
1167 + " ms in the future! Check that graphics HAL is generating vsync "
1168 + "timestamps using the correct timebase.");
1169 timestampNanos = now;
1170 }
1171
1172 if (mHavePendingVsync) {
1173 Log.w(TAG, "Already have a pending vsync event. There should only be "
1174 + "one at a time.");
1175 } else {
1176 mHavePendingVsync = true;
1177 }
1178
1179 mTimestampNanos = timestampNanos;
1180 mFrame = frame;
1181 mLastVsyncEventData = vsyncEventData;
1182 ScrollOptimizer.setVsyncTime(mTimestampNanos);
// 会调用 run 方法
1183 Message msg = Message.obtain(mHandler, this);
1184 msg.setAsynchronous(true);
1185 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
1186 } finally {
1187 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1188 }
1189 }
1190
1191 @Override
1192 public void run() {
1193 mHavePendingVsync = false;
1194 doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
1195 }
1196 }
1197
Choreographer.doFrame
Choreographer.doFrame
void doFrame(long frameTimeNanos, int frame,
839 DisplayEventReceiver.VsyncEventData vsyncEventData) {
840 final long startNanos;
841 final long frameIntervalNanos = vsyncEventData.frameInterval;
842 try {
843 mIsDoFrameProcessing = true;
844 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
845 Trace.traceBegin(Trace.TRACE_TAG_VIEW,
846 "Choreographer#doFrame " + vsyncEventData.id);
847 }
848 synchronized (mLock) {
849 mIsVsyncScheduled = false;
850 if (!mFrameScheduled) {
851 traceMessage("Frame not scheduled");
852 return; // no work to do
853 }
854
855 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
856 mDebugPrintNextFrameTimeDelta = false;
857 Log.d(TAG, "Frame time delta: "
858 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
859 }
860 // 计划执行时间
861 long intendedFrameTimeNanos = frameTimeNanos;
862 startNanos = System.nanoTime();
863 final long jitterNanos = startNanos - frameTimeNanos;
864 if (jitterNanos >= frameIntervalNanos) {
// 是否超过一帧的时间,因为虽然添加了同步屏障,但是还是有正在执行的同步任务,导致doFrame 延迟执行了
// 计算掉帧数
865 final long skippedFrames = jitterNanos / frameIntervalNanos;
866 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
// 默认掉帧超过30帧打印日志
867 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
868 + "The application may be doing too much work on its main thread.");
869 try {
870 if (getSceneDecisionManager() != null) {
871 getSceneDecisionManager().monitorFrameSkipped(skippedFrames, Process.myPid());
872 }
873 } catch (Exception e) {
874 // do nothing
875 }
876 }
877 final long lastFrameOffset = jitterNanos % frameIntervalNanos;
878 if (DEBUG_JANK) {
879 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
880 + "which is more than the frame interval of "
881 + (frameIntervalNanos * 0.000001f) + " ms! "
882 + "Skipping " + skippedFrames + " frames and setting frame "
883 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
884 }
885 frameTimeNanos = startNanos - lastFrameOffset;
886 }
887
888 if (frameTimeNanos < mLastFrameTimeNanos) {
889 if (DEBUG_JANK) {
890 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
891 + "previously skipped frame. Waiting for next vsync.");
892 }
893 traceMessage("Frame time goes backward");
894 scheduleVsyncLocked();
895 return;
896 }
897
898 if (mFPSDivisor > 1) {
899 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
900 if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
901 traceMessage("Frame skipped due to FPSDivisor");
902 scheduleVsyncLocked();
903 return;
904 }
905 }
906
907 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
908 vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
909 mFrameScheduled = false;
910 mLastFrameTimeNanos = frameTimeNanos;
911 if (false && ZFrameMetricsListener.ZTE_FEATURE_ZFRAMEMETRICS
912 && ZFrameMetricsListener.getInstance() != null) {
913 if (frameIntervalNanos > 0 && frameIntervalNanos != mLastFrameIntervalNanos) {
914 ZFrameMetricsListener.getInstance().reportFrameRateChange((long) (frameIntervalNanos * 0.000001f));
915 }
916 }
917 mLastFrameIntervalNanos = frameIntervalNanos;
918 mLastVsyncEventData = vsyncEventData;
919 }
920
921 ScrollOptimizer.setUITaskStatus(true);
922 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
923
924 mFrameInfo.markInputHandlingStart();
925 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
926
927 mFrameInfo.markAnimationsStart();
928 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
929 doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos,
930 frameIntervalNanos);
931
932 mFrameInfo.markPerformTraversalsStart();
933 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
934
935 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
936 ScrollOptimizer.setUITaskStatus(false);
937 } finally {
938 AnimationUtils.unlockAnimationClock();
939 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
940 }
941
942 if (DEBUG_FRAMES) {
943 final long endNanos = System.nanoTime();
944 Log.d(TAG, "Frame " + frame + ": Finished, took "
945 + (endNanos - startNanos) * 0.000001f + " ms, latency "
946 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
947 }
948 mIsDoFrameProcessing = false;
949 }
Choreographer.doCallbacks
Choreographer.doCallbacks
void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) {
952 CallbackRecord callbacks;
953 synchronized (mLock) {
954 // We use "now" to determine when callbacks become due because it's possible
955 // for earlier processing phases in a frame to post callbacks that should run
956 // in a following phase, such as an input event that causes an animation to start.
957 final long now = System.nanoTime();
// 根据指定的类型callbackQueue 中查找到达执行时间的 CallbackRecord
958 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
959 now / TimeUtils.NANOS_PER_MS);
960 if (callbacks == null) {
961 return;
962 }
963 mCallbacksRunning = true;
964
965 // Update the frame time if necessary when committing the frame.
966 // We only update the frame time if we are more than 2 frames late reaching
967 // the commit phase. This ensures that the frame time which is observed by the
968 // callbacks will always increase from one frame to the next and never repeat.
969 // We never want the next frame's starting frame time to end up being less than
970 // or equal to the previous frame's commit frame time. Keep in mind that the
971 // next frame has most likely already been scheduled by now so we play it
972 // safe by ensuring the commit time is always at least one frame behind.
973 if (callbackType == Choreographer.CALLBACK_COMMIT) {
974 final long jitterNanos = now - frameTimeNanos;
975 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
976 if (jitterNanos >= 2 * frameIntervalNanos) {
// 当commit类型回调执行的时间点超过2帧,则更新mLastFrameTimeNanos
977 final long lastFrameOffset = jitterNanos % frameIntervalNanos
978 + frameIntervalNanos;
979 if (DEBUG_JANK) {
980 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
981 + " ms which is more than twice the frame interval of "
982 + (frameIntervalNanos * 0.000001f) + " ms! "
983 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
984 + " ms in the past.");
985 mDebugPrintNextFrameTimeDelta = true;
986 }
987 frameTimeNanos = now - lastFrameOffset;
988 mLastFrameTimeNanos = frameTimeNanos;
989 }
990 }
991 }
992 try {
// 迭代执行队列所有任务
993 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
994 for (CallbackRecord c = callbacks; c != null; c = c.next) {
995 if (DEBUG_FRAMES) {
996 Log.d(TAG, "RunCallback: type=" + callbackType
997 + ", action=" + c.action + ", token=" + c.token
998 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
999 }
1000 c.run(frameTimeNanos);
1001 }
1002 } finally {
1003 synchronized (mLock) {
1004 mCallbacksRunning = false;
1005 do {
1006 final CallbackRecord next = callbacks.next;
1007 recycleCallbackLocked(callbacks);
1008 callbacks = next;
1009 } while (callbacks != null);
1010 }
1011 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1012 }
1013 }
598 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
599 if (callback == null) {
600 throw new IllegalArgumentException("callback must not be null");
601 }
602
// 也是调用 postCallbackDelayedInteral 方法
// callbackTyoe 是 CALLBACK_ANIMATION 类型
// token 是 FRAME_CALLBACK_TOKEN, action 是 FrameCallback
603 postCallbackDelayedInternal(CALLBACK_ANIMATION,
604 callback, FRAME_CALLBACK_TOKEN, delayMillis);
605 }
...
1198 private static final class CallbackRecord {
1199 public CallbackRecord next;
1200 public long dueTime;
1201 public Object action; // Runnable or FrameCallback
1202 public Object token;
1203
1204 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1205 public void run(long frameTimeNanos) {
1206 if (token == FRAME_CALLBACK_TOKEN) {
1207 ((FrameCallback)action).doFrame(frameTimeNanos);
1208 } else {
1209 ((Runnable)action).run();
1210 }
1211 }
1212 }
1213
总结
- Choreographer:使 CPU/GPU 的绘制在 VSYNC 到来时开始。 Choreographer 初始化时会创建一个表示对 Vsync 信号感兴趣的连接,当有绘制请求时通过 postCallback 方法请求下一次 Vsync 信号,当信号到来后才开始执行绘制任务。
- 只有当 App 注册监听下一 Vsync 信号后才能接收到 Vsync 到来的回调。如果界面一直保持不变,那么 App 不会去接收每隔 16.6 ms一次的 Vsync 事件,但底层依旧会以这个频率来切换每一帧的画面(也是通过监听 Vsync 信号实现)。即当界面不变时屏幕也会固定每 16.6 ms 刷新,但 CPU/GPU 不会走绘制流程。
- 当 View 请求刷新你时,这个任务并不会马上开始,而是需要等到下一个 Vsync 信号到来时才开始。 measure/layout/draw 流程运行完后,界面也不会立刻刷新,而会等到下一个 Vsync 信号到来时才进行缓存交换和显示。
- 造成丢帧主要有两个原因:一是遍历绘制 View 树以及计算屏幕数据超过了16.6ms;二是主线程一直在处理其他耗时消息,导致绘制任务迟迟不能开始(同步屏障不能完全解决这个问题)。
- 可通过Choreographer.getInstance().postFrameCallback()来监听帧率情况。
Choreographer 工作流程