点击阅读:Android 窗口显示系列文章
1. UI 绘制的调度入口
接上文,当窗口添加到 WMS 并完成尺寸计算后,requestLayout 触发 UI 绘制流程:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
// DecorView
mView = view;
mWindowAttributes.copyFrom(attrs);
// 核心流程3
requestLayout();
// 核心流程1
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
mTempControls, attachedFrame, compatScale);
// 核心流程2
mWindowLayout.computeFrames(mWindowAttributes, state,
displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */,
mTmpFrames);
setFrame(mTmpFrames.frame, true /* withinRelayout */);
}
}
}
虽然 requestLayout 在窗口添加前调用,但由于设置了同步屏障和 VSYNC 机制,实际 UI 绘制会在窗口添加完成后执行,确保绘制时窗口已就绪。看一下 requestLayout 方法:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {// 一个标志位,防止重复调用
checkThread();
mLayoutRequested = true;// 标志位
scheduleTraversals();
}
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
void scheduleTraversals() {
if (!mTraversalScheduled) {// 同样避免重复调用
mTraversalScheduled = true;
// 1. 设置同步屏障:阻塞同步消息,确保UI绘制优先
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 2. 通过Choreographer注册VSYNC回调
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
// 3. 通知渲染线程新帧即将开始
notifyRendererOfFramePending();
// 4. 请求Surface绘制锁
pokeDrawLockIfNeeded();
}
}
首先设置同步屏障,用于确保 UI 绘制消息(异步消息)能够优先于其他同步消息执行,从而保证绘制的及时性。
这里的关键在于 Choreographer.postCallback 方法,它将 mTraversalRunnable 与 VSYNC 信号绑定。当 VSYNC 信号到来时,系统会优先执行这个 Runnable。
2. Choreographer 对象的创建
mChoreographer 在 ViewRootImpl 构造函数中进行初始化:
mChoreographer = Choreographer.getInstance();
Choreographer 和 Looper 一样 是线程单例的:
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;
}
};
几个静态变量代表回调消息的类型,优先级由低至高,如下:
// 输入事件
public static final int CALLBACK_INPUT = 0;
// 动画
public static final int CALLBACK_ANIMATION = 1;
// 插入更新的动画
public static final int CALLBACK_INSETS_ANIMATION = 2;
// 绘制
public static final int CALLBACK_TRAVERSAL = 3;
// 提交
public static final int CALLBACK_COMMIT = 4;
3. VSYNC 回调注册
接着看一下 Choreographer 的 postCallback 方法:
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) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
// 当前时间
final long now = SystemClock.uptimeMillis();
// 加上延迟时间
final long dueTime = now + delayMillis;
// 将回调添加到对应类型的队列(CALLBACK_TRAVERSAL类型)
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);
}
}
}
最终调用到 postCallbackDelayedInternal 方法,传入的第一个参数为 Choreographer.CALLBACK_TRAVERSAL,回调消息类型为 UI 绘制。第二个参数为一个 Runnable 对象。第三个参数 token 为 null。
postCallbackDelayedInternal 中取对应类型的 CallbackQueue 添加任务,也就是在 UI 绘制的 CallbackQueue 中添加了一个任务。addCallbackLocked 方法就是把 dueTime、action、token 封装成 CallbackRecord 对象后存入 CallbackQueue 的下一个节点。
发送的消息没有延迟,直接调用了 scheduleFrameLocked 方法:
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {// 开启了 VSYNC
//当前执行的线程,是否是mLooper所在线程
if (isRunningOnLooperThreadLocked()) {
//申请 VSYNC 信号
scheduleVsyncLocked();
} else {
// 若不在,就用 mHandler 发送消息到原线程,最后还是调用 scheduleVsyncLocked 方法
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
// 如果未开启 VSYNC 则直接 doFrame 方法(4.1后默认开启)
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
若当前执行的线程,是否是 mLooper 所在线程,直接调用 scheduleVsyncLocked 方法申请 VSYNC 信号。若不在,就用 mHandler 发送消息到原线程,最后还是调用 scheduleVsyncLocked 方法:
private void scheduleVsyncLocked() {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
mDisplayEventReceiver.scheduleVsync();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
接着调用 DisplayEventReceiver 的 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 {
// 申请 VSYNC 中断信号,会回调 onVsync 方法
nativeScheduleVsync(mReceiverPtr);
}
}
在 DisplayEventReceiver 的构造方法会通过 JNI 创建一个 IDisplayEventConnection 的 VSYNC 的监听者:
// 注册VSYNC信号监听者
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this),
new WeakReference<VsyncEventData>(mVsyncEventData),
mMessageQueue,
vsyncSource, eventRegistration, layerHandle);
接着调用 native 方法 nativeScheduleVsync,并将 mReceiverPtr 作为参数传递。
这里我们只需要关注:申请完 VSYNC 信号后,VSYNC 信号的接收回调是 onVsync:
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
}
4. VSYNC 信号回调处理
看一下 FrameDisplayEventReceiver 中的实现:
private final class FrameDisplayEventReceiver extends android.view.DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
private final VsyncEventData mLastVsyncEventData = new VsyncEventData();
FrameDisplayEventReceiver(Looper looper, int vsyncSource, long layerHandle) {
super(looper, vsyncSource, /* eventRegistration */ 0, layerHandle);
}
@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.copyFrom(vsyncEventData);
// 将本身作为 runnable 传入 msg, 发消息后会走run,异步消息
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;
// onVsync 方法中只是使用 mHandler 发送消息到 MessageQueue 中,不一定是立刻执行,若 MessageQueue 中前面有较为耗时的操作,那么就要等完成,才会执行本次的 doFrame。
doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}
}
接着看下 doFrame 方法:
void doFrame(long frameTimeNanos, int frame,
DisplayEventReceiver.VsyncEventData vsyncEventData) {
final long startNanos;
final long frameIntervalNanos = vsyncEventData.frameInterval;
boolean resynced = false;
try {
FrameTimeline timeline = mFrameData.update(frameTimeNanos, vsyncEventData);
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(
Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + timeline.mVsyncId);
}
synchronized (mLock) {
if (!mFrameScheduled) {
traceMessage("Frame not scheduled");
return; // no work to do
}
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: "
+ ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
// 预期执行时间
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
// 超时时间是否超过一帧的时间(这是因为 MessageQueue 虽然添加了同步屏障,但是还是有正在执行的同步任务,导致 doFrame 延迟执行了)
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= frameIntervalNanos) {
// 计算掉帧数
frameTimeNanos = startNanos;
if (frameIntervalNanos == 0) {
// 掉帧超过30帧打印Log提示
Log.i(TAG, "Vsync data empty due to timeout");
} else {
long lastFrameOffset = jitterNanos % frameIntervalNanos;
frameTimeNanos = frameTimeNanos - lastFrameOffset;
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.");
}
}
timeline = mFrameData.update(
frameTimeNanos, mDisplayEventReceiver, jitterNanos);
resynced = true;
}
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);
// Frame标志位恢复
mFrameScheduled = false;
// 记录最后一帧时间
mLastFrameTimeNanos = frameTimeNanos;
mLastFrameIntervalNanos = frameIntervalNanos;
mLastVsyncEventData.copyFrom(vsyncEventData);
}
if (resynced && Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
String message = String.format("Choreographer#doFrame - resynced to %d in %.1fms",
timeline.mVsyncId, (timeline.mDeadlineNanos - startNanos) * 0.000001f);
Trace.traceBegin(Trace.TRACE_TAG_VIEW, message);
}
// 按类型顺序 执行任务
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS,
timeline.mExpectedPresentationTimeNanos);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos);
} finally {
AnimationUtils.unlockAnimationClock();
if (resynced) {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
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.");
}
}
接着看一下 doCallbacks 方法,
void doCallbacks(int callbackType, long frameIntervalNanos) {
CallbackRecord callbacks;
long frameTimeNanos = mFrameData.mFrameTimeNanos;
synchronized (mLock) {
final long now = System.nanoTime();
// 根据指定的类型 CallbackQueue 中查找到达执行时间的 CallbackRecord
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 (frameIntervalNanos > 0 && jitterNanos >= 2 * frameIntervalNanos) {
final long lastFrameOffset = jitterNanos % frameIntervalNanos
+ frameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
+ " ms which is more than twice the frame interval of "
+ (frameIntervalNanos * 0.000001f) + " ms! "
+ "Setting frame time to " + (lastFrameOffset * 0.000001f)
+ " ms in the past.");
mDebugPrintNextFrameTimeDelta = true;
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos);
}
}
}
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));
}
// 回调 CallbackRecord 的 run,其内部回调 Callback 的 run
c.run(mFrameData);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
//回收CallbackRecord
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
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;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
// 通过postFrameCallback 或 postFrameCallbackDelayed,会执行这里,postFrameCallback
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
//取出Runnable执行run()
((android.telecom.Logging.Runnable)action).run();
}
}
void run(FrameData frameData) {
frameData.setInCallback(true);
if (token == VSYNC_CALLBACK_TOKEN) {
((VsyncCallback) action).onVsync(frameData);
} else {
run(frameData.getFrameTimeNanos());
}
frameData.setInCallback(false);
}
}
最后会调用到 action 的 run 方法,即 TraversalRunnable 的 run 方法:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
在 doTraversal 中,移除了同步屏障,并且开始了 performTraversals 流程:
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
// 核心。主线程(main)的 Looper 回调到 TraversalRunnable 回调
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}