本文主要讲解WMS在管理窗口动画的启动和更新过程。 主要分4个部分:
1.接收VSync 信号:动画需要动态刷新需要用到VSync信号
2.VSync处理回调过程:当每一帧数据到来时,WMS如何接收到信号
3.窗口动画的启动:WMS启动窗口动画过程
4.窗口动画更新:动画启动后数据如何动态更新的
窗口视图最终变成图像绘制在屏幕上,窗口动画即是对动画视图的图像绘制的图层不停的做位置,大小,透明度等各种变换。这就需要一种定时机制驱动变换定时刷新屏幕。WMS使用VSync信号来驱动动画。 VSync 信号是一种用于控制屏幕刷新的信号。VSync 信号是 Vertical Sync(垂直同步)的缩写,它是一种硬件信号,用于控制显示器的刷新率。在 Android 中,VSync 信号由系统的 SurfaceFlinger 服务发送,它会定期发送 VSync 信号来控制屏幕的刷新。
Android WMS是如何接收VSync信号的?
一 接收VSync 信号
流程图
总结下来,接收Sync信号的主要过程就是获取与SurfaceFlinger服务中的EventThread对象进行通信的通道的Fd句柄,然后将Fd添加的Looper的监听中,当有VSync信号到来时就会回调Looper的callback。即可以在这个callback中处理相关的页面逻辑。 下面看看具体源码实现
- Choreographer类 Choreographer 会在每个 VSync 信号到来时调用应用程序注册的 FrameCallback 回调,并触发相应的绘制操作,以保证应用程序的绘制操作与 VSync 信号的同步。 它的实例化过程,如:在WindowAnimator构造函数中调用了Choreographer.getSfInstance()方法获取到了Choreographer实例对象。
WindowAnimator(final WindowManagerService service) {
mService = service;
mContext = service.mContext;
mPolicy = service.mPolicy;
mTransaction = service.mTransactionFactory.get();
service.mAnimationHandler.runWithScissors(
() -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
mAnimationFrameCallback = frameTimeNs -> {
synchronized (mService.mGlobalLock) {
mAnimationFrameCallbackScheduled = false;
final long vsyncId = mChoreographer.getVsyncId();
animate(frameTimeNs, vsyncId);
if (mNotifyWhenNoAnimation && !mLastRootAnimating) {
mService.mGlobalLock.notifyAll();
}
}
};
}
// Choreographer.getSfInstance()方法
/**
* @hide
*/
@UnsupportedAppUsage
public static Choreographer getSfInstance() {
return sSfThreadInstance.get();
}
// sSfThreadInstance变量
// Thread local storage for the SF choreographer.
private static final ThreadLocal<Choreographer> sSfThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
}
};
Choreographer.getSfInstance() 方法调用了sSfThreadInstance.get()方法。而sSfThreadInstance是ThreadLocal类的实例,它是一个线程局部变量,即在当前线程中只有一个Choreographer实例对象。在Choreographer 构造函数中传入了当前线程的looer。即当前线程的Looper和Choreographer绑定在了一起。 再看看 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));
}
首先创建FrameHandler,它继承至Handler,用于接收发来的message消息。再创建FrameDisplayEventReceiver继承自DisplayEventReceiver的类用于接收VSync信号,接着创建CallbackQueue对象数组。CallbackQueue用于添加删除动画回调等各种类型的callback,比如在调用Choreographer的postFrameCallback() 方法的时候传入的callback会被添加到对应的CallbackQueue对象中。下面主要来看看FrameDisplayEventReceiver类做了什么 FrameDisplayEventReceiver类继承自DisplayEventReceiver
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
private VsyncEventData mLastVsyncEventData = new VsyncEventData();
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, 0);
}
....
// 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);
}
DisplayEventReceiver构造方法中主要调用了本地方法nativeInit。
//本地方法nativeInit对应的native代码
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
jint vsyncSource, jint eventRegistration) {
//获取native层的消息队列
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//创建NativeDisplayEventReceiver对象
sp<NativeDisplayEventReceiver> receiver =
new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
eventRegistration);
//调用NativeDisplayEventReceiver对象的nitialize方法
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize display event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}
receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}
本地方法nativeInit主要是创建了NativeDisplayEventReceiver对象,并传入消息队列messageQueue。 NativeDisplayEventReceiver继承了DisplayEventDispatcher类,而DisplayEventDispatcher继承了LooperCallback类。
// NativeDisplayEventReceiver 构造方法
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
const sp<MessageQueue>& messageQueue,
jint vsyncSource, jint eventRegistration)
: DisplayEventDispatcher(messageQueue->getLooper(),
static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
static_cast<ISurfaceComposer::EventRegistration>(eventRegistration)),
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mMessageQueue(messageQueue) {
ALOGV("receiver %p ~ Initializing display event receiver.", this);
}
//DisplayEventDispatcher 构造方法
DisplayEventDispatcher::DisplayEventDispatcher(
const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration)
: mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
mLastVsyncCount(0), mLastScheduleVsyncTime(0) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
// DisplayEventDispatcher头文件定义的变量
...
private:
sp<Looper> mLooper;
DisplayEventReceiver mReceiver; // 定义类DisplayEventReceiver为的变量mReceiver
bool mWaitingForVsync;
uint32_t mLastVsyncCount;
nsecs_t mLastScheduleVsyncTime;
...
在DisplayEventDispatcher构造函数中可以看到这个语句:mReceiver(vsyncSource, eventRegistration)。mReceiver在头文件DisplayEventDispatcher.h 中定义类型为DisplayEventReceiver。这句话意思是创建一个DisplayEventReceiver类,传入vsyncSource, eventRegistration 2个参数,同时使用该类初始化mReceiver变量。即这条语句调用构造函数DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::EventRegistrationFlags eventRegistration),并将其赋值给mReceiver变量。 看看这个构造函数做了什么?
DisplayEventReceiver::DisplayEventReceiver(
ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr) {
// 调用SurfaceFlinger的createDisplayEventConnection函数
mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
if (mEventConnection != nullptr) {
//获得和SurfaceFlinger中的EventThread对象进行通信的通道。
mDataChannel = std::make_unique<gui::BitTube>();
const auto 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();
}
}
}
}
//DisplayEventReceiver.h头文件
...
private:
sp<IDisplayEventConnection> mEventConnection; // 定义mEventConnection
std::unique_ptr<gui::BitTube> mDataChannel; //定义mDataChannel变量
std::optional<status_t> mInitError;
...
在DisplayEventReceiver构造方法中做了件重要的事:调用SurfaceFlinger的createDisplayEventConnection函数获取类为IDisplayEventConnection的对象mEventConnection,再通过mEventConnection对象获取和SurfaceFlinger中的EventThread对象进行通信的通道,存储在变量mDataChannel中。 回到上面提到的android_view_DisplayEventReceiver类的nativeInit方法:
...
sp<NativeDisplayEventReceiver> receiver =
new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
eventRegistration);
status_t status = receiver->initialize();
...
创建NativeDisplayEventReceiver完成后赋值给receiver变量,然后调用receiver->initialize()
// receiver->initialize() 源代码
status_t DisplayEventDispatcher::initialize() {
status_t result = mReceiver.initCheck();
if (result) {
ALOGW("Failed to initialize display event receiver, status=%d", result);
return result;
}
if (mLooper != nullptr) {
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
if (rc < 0) {
return UNKNOWN_ERROR;
}
}
return OK;
}
// mReceiver.getFd() 方法代码
int DisplayEventReceiver::getFd() const {
if (mDataChannel == nullptr) return mInitError.has_value() ? mInitError.value() : NO_INIT;
return mDataChannel->getFd();
}
receiver->initialize()实际是调用了DisplayEventDispatcher类的initialize函数。 在initialize函数中mReceiver.getFd()方法中的mReceiver即是上面提到的DisplayEventReceiver类的实例,从mReceiver.getFd()函数代码可以看到,内部实际调用的是mDataChannel->getFd()方法,并返回其结果。也就是说实际返回的是与SurfaceFlinger中的EventThread对象进行通信的通道mDataChannel获取的Fd句柄。将这个Fd通过mlooper的addFd方法注册到looper中。当有VSync 信号时,Fd就会产生变化,looper就会被唤醒。 同时注意到mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL)该方法调用将第4个参数this传入到了addFd做为回调,上文提到DisplayEventDispatcher继承了LooperCallback类,所以可以传入addFd参数中作为回调。当looper被唤醒时,会回调注册的LooperCallback回调对象的handleEvent方法。这里实际调用的是子类DisplayEventDispatcher的handleEvent方法。 至此WMS就可以正确接收到VSync信号了。
总结方法调用流程
二 VSync处理回调过程
获取到VSync信号就有了定时刷新的能力,就可以动态改变窗口的样式。当VSync信号到来时,是如何回调callback的? 从上面的介绍可以看到当VSync信号到来时,会调用DisplayEventDispatcher的handleEvent方法
int DisplayEventDispatcher::handleEvent(int, int events, void*) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
"events=0x%x",
events);
return 0; // remove the callback
}
if (!(events & Looper::EVENT_INPUT)) {
ALOGW("Received spurious callback for unhandled poll event. "
"events=0x%x",
events);
return 1; // keep the callback
}
// Drain all pending events, keep the last vsync.
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
VsyncEventData vsyncEventData;
// processPendingEvents函数从通道中读取数据,如果读取到的数据是表示VSync信号的消息,则返回true
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
", displayId=%s, count=%d, vsyncId=%" PRId64,
this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
vsyncEventData.preferredVsyncId());
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) {
ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
mWaitingForVsync = false;
dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
++mLastVsyncCount, vsyncEventData /* empty data */);
}
}
return 1; // keep the callback
}
bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
PhysicalDisplayId* outDisplayId,
uint32_t* outCount,
VsyncEventData* outVsyncEventData) {
bool gotVsync = false;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
ssize_t n;
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
mFrameRateOverrides.reserve(n);
for (ssize_t i = 0; i < n; i++) {
const DisplayEventReceiver::Event& ev = buf[i];
switch (ev.header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: // 读取到VSync 信号返回true
// Later vsync events will just overwrite the info from earlier
// ones. That's fine, we only care about the most recent.
gotVsync = true;
*outTimestamp = ev.header.timestamp;
*outDisplayId = ev.header.displayId;
*outCount = ev.vsync.count;
*outVsyncEventData = ev.vsync.vsyncData;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
break;
case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
break;
case DisplayEventReceiver::DISPLAY_EVENT_NULL:
dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
break;
case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
mFrameRateOverrides.emplace_back(ev.frameRateOverride);
break;
case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
std::move(mFrameRateOverrides));
break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
break;
}
}
}
if (n < 0) {
ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n));
}
return gotVsync;
}
// DisplayEventDispatcher子类的dispatchVsync方法
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
uint32_t count, VsyncEventData vsyncEventData) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData);
// 调用java类DisplayEventReceiver的dispatchVsync 方法
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
timestamp, displayId.value, count, javaVsyncEventData);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}
在DisplayEventDispatcher::handleEvent 调用主要过程 :
- 先调用processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData) 方法,如果读取的VSync信号数据返回true。
- 如果processPendingEvents 返回true,接着调用dispatchVsync方法。dispatchVsync方法是在DisplayEventDispatcher的子类中实现。NativeDisplayEventReceiver继承了DisplayEventDispatcher类,所以dispatchVsync实际是在NativeDisplayEventReceiver 中实现
- NativeDisplayEventReceiver的dispatchVsync方法实际是调用了java类DisplayEventReceiver的dispatchVsync方法。
DisplayEventReceiver类的dispatchVsync方法
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData);
}
// onVsync 为空实现
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
}
// FrameDisplayEventReceiver 类的实现
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
private VsyncEventData mLastVsyncEventData = new VsyncEventData();
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, 0);
}
// TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
// the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
// for the internal display implicitly.
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"Choreographer#onVsync "
+ vsyncEventData.preferredFrameTimeline().vsyncId);
}
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
// the message queue. If there are no messages in the queue with timestamps
// earlier than the frame time, then the vsync event will be processed immediately.
// Otherwise, messages that predate the vsync event will be handled first.
long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
mLastVsyncEventData = vsyncEventData;
Message msg = Message.obtain(mHandler, this); // this 代表Runnable回调。
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);
}
}
在DisplayEventReceiver类的dispatchVsync方法中只调用了onVsync方法。但是DisplayEventReceiver的onVsync方法是空实现,具体实现过程是有子类实现,即FrameDisplayEventReceiver类实现的onVsync方法。在FrameDisplayEventReceiver.onVsync 方法中创建了Message,并将Message发送给当前线程的Looper的Handler。其中Message.obtain方法的回调传入this指针,即传入的是当前对象FrameDisplayEventReceiver,因为FrameDisplayEventReceiver继承了Runnable方法,所以可以将FrameDisplayEventReceiver对象传入Message.obtain方法。当handler处理消息时会回调Runnable的run方法,即FrameDisplayEventReceiver的run方法。 而在run方法中调用了doFrame方法。doFrame方法是Choreographer类的实现方法。因为FrameDisplayEventReceiver是Choreographer的内部类,所以它可以直接调用该方法。
// doFrame 中调用doCallbacks 处理各种类型的callback。
void doFrame(long frameTimeNanos, int frame,
DisplayEventReceiver.VsyncEventData vsyncEventData) {
...
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos);
mFrameInfo.markAnimationsStart();
//处理动画的callback,并传入对应的类型Choreographer.CALLBACK_ANIMATION
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);
...
}
// doCallbacks 方法
void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) {
CallbackRecord callbacks;
long frameTimeNanos = frameData.mFrameTimeNanos;
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
// in a following phase, such as an input event that causes an animation to start.
final long now = System.nanoTime();
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
...
}
...
//遍历获取的callback,并调用它的run方法。
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameData);
}
}
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) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
void run(FrameData frameData) {
if (token == VSYNC_CALLBACK_TOKEN) {
((VsyncCallback) action).onVsync(frameData);
} else {
run(frameData.getFrameTimeNanos());
}
}
}
...
doFrame中调用doCallbacks并传入对应的回调类型如Choreographer.CALLBACK_ANIMATION。doCallbacks方法通过该类型获取CallbackQueues数组对应的callback。然后遍历所有该类型的callback并调用它的run方法。这样当外部注册到CallbackQueues数组中的callback就得到了执行。在CallbackRecord类中可以看到,如果是FrameCallback,则执行的是其doFrame()方法. 下面看看WMS窗口动画的注册和执行过程。
三 窗口动画的启动
当窗口需要执行关闭和退出动画,或者当窗口需要执行布局动画时,WMS都会调用scheduleAnimationLocked()方法。
//WMS scheduleAnimationLocked() 方法
/** Note that Locked in this case is on mLayoutToAnim */
void scheduleAnimationLocked() {
mAnimator.scheduleAnimation();
}
// mAnimator 为WindowAnimator类的对象
// mAnimator = new WindowAnimator(this);
//WindowAnimator类的scheduleAnimation()方法
void scheduleAnimation() {
if (!mAnimationFrameCallbackScheduled) {
mAnimationFrameCallbackScheduled = true;
mChoreographer.postFrameCallback(mAnimationFrameCallback);
}
}
WMS scheduleAnimationLocked()的方法只调用了mAnimator.scheduleAnimation(),mAnimator在WMS构造方法中创建mAnimator = new WindowAnimator(this);所以实际调用的是WindowAnimator类的scheduleAnimation() 方法。 WindowAnimator类的scheduleAnimation()中,向Choreographer注册了callback,mAnimationFrameCallback。当VSync信号到来时,根据上讨论的调用流程,mAnimationFrameCallback的run方法将会被调用。 mAnimationFrameCallback变量是在WindowAnimator类的构造函数中被初始化。如下:
WindowAnimator(final WindowManagerService service) {
mService = service;
mContext = service.mContext;
mPolicy = service.mPolicy;
mTransaction = service.mTransactionFactory.get();
service.mAnimationHandler.runWithScissors(
() -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
mAnimationFrameCallback = frameTimeNs -> {
synchronized (mService.mGlobalLock) {
mAnimationFrameCallbackScheduled = false;
final long vsyncId = mChoreographer.getVsyncId();
animate(frameTimeNs, vsyncId);
if (mNotifyWhenNoAnimation && !mLastRootAnimating) {
mService.mGlobalLock.notifyAll();
}
}
};
}
// animate方法
private void animate(long frameTimeNs, long vsyncId) {
if (!mInitialized) {
return;
}
// Schedule next frame already such that back-pressure happens continuously.
scheduleAnimation();
final RootWindowContainer root = mService.mRoot;
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
mBulkUpdateParams = 0;
root.mOrientationChangeComplete = true;
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
}
ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate");
mService.openSurfaceTransaction();
try {
// Remove all deferred displays, tasks, and activities.
root.handleCompleteDeferredRemoval();
final AccessibilityController accessibilityController =
mService.mAccessibilityController;
final int numDisplays = mDisplayContentsAnimators.size();
// 获取所有DisplayContent
for (int i = 0; i < numDisplays; i++) {
final int displayId = mDisplayContentsAnimators.keyAt(i);
final DisplayContent dc = root.getDisplayContent(displayId);
// Update animations of all applications, including those associated with
// exiting/removed apps.
dc.updateWindowsForAnimator();
dc.prepareSurfaces();
}
for (int i = 0; i < numDisplays; i++) {
final int displayId = mDisplayContentsAnimators.keyAt(i);
final DisplayContent dc = root.getDisplayContent(displayId);
dc.checkAppWindowsReadyToShow();
if (accessibilityController.hasCallbacks()) {
accessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId,
mTransaction);
}
}
cancelAnimation();
if (mService.mWatermark != null) {
mService.mWatermark.drawIfNeeded();
}
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
}
...
}
// DisplayContent类的updateWindowsForAnimator方法
void updateWindowsForAnimator() {
forAllWindows(mUpdateWindowsForAnimator, true /* traverseTopToBottom */);
}
mAnimationFrameCallback 将mAnimationFrameCallbackScheduled 变量设置为false,表示调用WMS的scheduleAnimationLocked() 方法后,只有在执行一次VSync信号的回调后才能再次调用scheduleAnimationLocked()。 animate方法中,调用了scheduleAnimation(),再次注册mAnimationFrameCallback, 下一帧继续执行. DisplayContent类用于管理一个屏幕上的所有窗口和Surface。每个屏幕在WMS中都会有一个对应的DisplayContent对象。 animate方法中获取所有DisplayContent对象,并分别调用其updateWindowsForAnimator()和prepareSurfaces(); 其中updateWindowsForAnimator()方法调用了forAllWindows方法,forAllWindows会遍历所有的窗口并回调mUpdateWindowsForAnimator(类型为Consumer)
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
if (winAnimator.mDrawState == READY_TO_SHOW) {
if (activity == null || activity.canShowWindows()) {
// 变量 w 的类型为WindowState
// 调用WindowState类的performShowLocked()
if (w.performShowLocked()) {
pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
if (DEBUG_LAYOUT_REPEATS) {
mWmService.mWindowPlacerLocked.debugLayoutRepeats(
"updateWindowsAndWallpaperLocked 5", pendingLayoutChanges);
}
}
}
}
};
// WindowState 类
// This must be called while inside a transaction.
boolean performShowLocked() {
...
if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
return false;
}
logPerformShow("Showing ");
mWmService.enableScreenIfNeededLocked();
mWinAnimator.applyEnterAnimationLocked();
// Force the show in the next prepareSurfaceLocked() call.
mWinAnimator.mLastAlpha = -1;
ProtoLog.v(WM_DEBUG_ANIM, "performShowLocked: mDrawState=HAS_DRAWN in %s", this);
mWinAnimator.mDrawState = HAS_DRAWN;
mWmService.scheduleAnimationLocked();
....
return true;
}
//WindowStateAnimator类
void applyEnterAnimationLocked() {
// If we are the new part of a window replacement transition and we have requested
// not to animate, we instead want to make it seamless, so we don't want to apply
// an enter transition.
if (mWin.mSkipEnterAnimationForSeamlessReplacement) {
return;
}
final int transit;
if (mEnterAnimationPending) {
mEnterAnimationPending = false;
transit = WindowManagerPolicy.TRANSIT_ENTER;
} else {
transit = WindowManagerPolicy.TRANSIT_SHOW;
}
// We don't apply animation for application main window here since this window type
// should be controlled by ActivityRecord in general. Wallpaper is also excluded because
// WallpaperController should handle it.
if (mAttrType != TYPE_BASE_APPLICATION && !mIsWallpaper) {
applyAnimationLocked(transit, true);
}
if (mService.mAccessibilityController.hasCallbacks()) {
mService.mAccessibilityController.onWindowTransition(mWin, transit);
}
}
//
/**
* Choose the correct animation and set it to the passed WindowState.
* @param transit If AppTransition.TRANSIT_PREVIEW_DONE and the app window has been drawn
* then the animation will be app_starting_exit. Any other value loads the animation from
* the switch statement below.
* @param isEntrance The animation type the last time this was called. Used to keep from
* loading the same animation twice.
* @return true if an animation has been loaded.
*/
boolean applyAnimationLocked(int transit, boolean isEntrance) {
if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
return true;
}
if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
mWin.getDisplayContent().adjustForImeIfNeeded();
if (isEntrance) {
mWin.setDisplayLayoutNeeded();
mService.mWindowPlacerLocked.requestTraversal();
}
}
if (mWin.mControllableInsetProvider != null) {
// All our animations should be driven by the insets control target.
return false;
}
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
// is running.
if (mWin.mToken.okToAnimate()) {
int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);
int attr = -1;
Animation a = null;
if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {
if (anim != DisplayPolicy.ANIMATION_NONE) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#loadAnimation");
a = AnimationUtils.loadAnimation(mContext, anim);
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
} else {
switch (transit) {
case WindowManagerPolicy.TRANSIT_ENTER:
attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
break;
case WindowManagerPolicy.TRANSIT_EXIT:
attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
break;
case WindowManagerPolicy.TRANSIT_SHOW:
attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
break;
case WindowManagerPolicy.TRANSIT_HIDE:
attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
break;
}
if (attr >= 0) {
a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
mWin.mAttrs, attr, TRANSIT_OLD_NONE);
}
}
if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
ProtoLog.v(WM_DEBUG_ANIM, "applyAnimation: win=%s"
+ " anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
this, anim, attr, a, transit, mAttrType, isEntrance, Debug.getCallers(20));
}
if (a != null) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#startAnimation");
mWin.startAnimation(a);
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
mAnimationIsEntrance = isEntrance;
}
} else {
mWin.cancelAnimation();
}
return mWin.isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
}
在WindowState 类中performShowLocked方法中,调用了mWinAnimator.applyEnterAnimationLocked(),mWinAnimator的类型是WindowStateAnimator。 调用过程:w.performShowLocked() --> mWinAnimator.applyEnterAnimationLocked() --> mWinAnimator.applyAnimationLocked --> mWin.startAnimation(a) 在applyAnimationLocked方法中,根据属性加载动画,并调用mWin.startAnimation(a)启动动画。变量mWin的类型为WindowState
总结调用流程:
四 窗口动画更新
调用mWin.startAnimation 启动动画后,最终会调用到SurfaceAnimationRunner类的startAnimationLocked(RunningAnimation a)方法。在这个方法中通过mAnimatorFactory.makeAnimator()获取SfValueAnimator(父类是ValueAnimator)类的对象ainm。设置动画开始,接收,更新等监听。
// SurfaceAnimationRunner类
@GuardedBy("mLock")
private void startAnimationLocked(RunningAnimation a) {
final ValueAnimator anim = mAnimatorFactory.makeAnimator();
// Animation length is already expected to be scaled.
anim.overrideDurationScale(1.0f);
anim.setDuration(a.mAnimSpec.getDuration());
// 更新动画回调
anim.addUpdateListener(animation -> {
synchronized (mCancelLock) {
if (!a.mCancelled) {
final long duration = anim.getDuration();
long currentPlayTime = anim.getCurrentPlayTime();
if (currentPlayTime > duration) {
currentPlayTime = duration;
}
//应用Transaction
applyTransformation(a, mFrameTransaction, currentPlayTime);
}
}
// Transaction will be applied in the commit phase.
scheduleApplyTransaction();
});
//添加动画开始,结束监听
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
synchronized (mCancelLock) {
if (!a.mCancelled) {
// TODO: change this back to use show instead of alpha when b/138459974 is
// fixed.
mFrameTransaction.setAlpha(a.mLeash, 1);
}
}
}
@Override
public void onAnimationEnd(Animator animation) {
synchronized (mLock) {
mRunningAnimations.remove(a.mLeash);
synchronized (mCancelLock) {
if (!a.mCancelled) {
// Post on other thread that we can push final state without jank.
mAnimationThreadHandler.post(a.mFinishCallback);
}
}
}
}
});
a.mAnim = anim;
mRunningAnimations.put(a.mLeash, a);
//启动动画
anim.start();
if (a.mAnimSpec.canSkipFirstFrame()) {
// If we can skip the first frame, we start one frame later.
anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
}
// Immediately start the animation by manually applying an animation frame. Otherwise, the
// start time would only be set in the next frame, leading to a delay.
anim.doAnimationFrame(mChoreographer.getFrameTime());
}
anim.start()启动动画,实际调用的是ValueAnimator的start() 方法,start()方法又调用start(false)。 ValueAnimator类为执行动画提供了简单的时间引擎,计算动画的值并将其应用到目标对象上 在start(false) 方法中调用了addAnimationCallback用于添加下一帧的监听
//ValueAnimator类
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mReversing = playBackwards;
mSelfPulse = !mSuppressSelfPulseRequested;
// Special case: reversing from seek-to-0 should act as if not seeked at all.
if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
if (mRepeatCount == INFINITE) {
// Calculate the fraction of the current iteration.
float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
mSeekFraction = 1 - fraction;
} else {
mSeekFraction = 1 + mRepeatCount - mSeekFraction;
}
}
mStarted = true;
mPaused = false;
mRunning = false;
mAnimationEndRequested = false;
// Resets mLastFrameTime when start() is called, so that if the animation was running,
// calling start() would put the animation in the
// started-but-not-yet-reached-the-first-frame phase.
mLastFrameTime = -1;
mFirstFrameTime = -1;
mStartTime = -1;
//设置动画更新回调
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// If there's no start delay, init the animation and notify start listeners right away
// to be consistent with the previous behavior. Otherwise, postpone this until the first
// frame after the start delay.
startAnimation();
if (mSeekFraction == -1) {
// No seek, start at play time 0. Note that the reason we are not using fraction 0
// is because for animations with 0 duration, we want to be consistent with pre-N
// behavior: skip to the final value immediately.
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
//设置动画更新回调
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
// 由于ValueAnimator实现了AnimationHandler.AnimationFrameCallback接口,所以这里直接传this
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
// AnimationHandler
//注册VSync 信号监听
/**
* Register to get a callback on the next frame after the delay.
*/
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
//getProvider即是SfVsyncFrameCallbackProvider对象
getProvider().postFrameCallback(mFrameCallback);
}
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
// SfVsyncFrameCallbackProvider类
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
//AnimationHandler 类
//当下一帧到时,回调mFrameCallback
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
// 将注册的监听一一取出,
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
//AnimationHandler 类
// 取出添加的callback,并调用其doAnimationFrame方法
private void doAnimationFrame(long frameTime) {
long currentTime = SystemClock.uptimeMillis();
final int size = mAnimationCallbacks.size();
for (int i = 0; i < size; i++) {
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
if (isCallbackDue(callback, currentTime)) {
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
cleanUpList();
}
上面代码的调用过程:addAnimationCallback(0) --> getAnimationHandler().addAnimationFrameCallback(this, delay) --> getProvider().postFrameCallback(mFrameCallback) --> mChoreographer.postFrameCallback(callback); 最终是将mFrameCallback注册到Choreographer类中,并将ValueAnimator添加到mAnimationCallbacks列表中。 另外由于ValueAnimator实现了AnimationHandler.AnimationFrameCallback接口,所以当调用getAnimationHandler().addAnimationFrameCallback(this, delay)时,实际是将ValueAnimator类添加到mAnimationCallbacks列表中。 接收到下一帧VSync 信号后,mFrameCallback.doFrame被调用。在FrameCallback.doFrame中又调用了doAnimationFrame方法,这个方法将mAnimationCallbacks列表中的数据一一取出并调用其doAnimationFrame方法,即ValueAnimator类的doAnimationFrame方法。 在ValueAnimator类的doAnimationFrame方法中,计算动画数据,并回调之前在SurfaceAnimationRunner类startAnimationLocked方法里注册的mUpdateListeners动画更新监听。这时动画即根据ValueAnimator计算的值更新到页面上。
源码路径
Choreographer: frameworks/base/core/java/android/view/Choreographer.java
FrameDisplayEventReceiver:frameworks/base/core/java/android/view/Choreographer.java 内部类
DisplayEventReceiver(java):frameworks/base/core/java/android/view/DisplayEventReceiver.java
DisplayEventReceiver(C++): frameworks/native/libs/gui/DisplayEventReceiver.cpp
NativeDisplayEventReceiver:frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
DisplayEventDispatcher:frameworks/native/libs/gui/DisplayEventDispatcher.cpp frameworks/native/libs/gui/include/gui/DisplayEventReceiver.h
WindowState:frameworks/base/services/core/java/com/android/server/wm/WindowState.java
WindowStateAnimator:frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
DisplayContent:frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
WindowManagerService:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
SurfaceAnimationRunner: frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
SfVsyncFrameCallbackProvider:frameworks/base/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
AnimationHandler:frameworks/base/core/java/android/animation/AnimationHandler.java