Android WMS 窗口动画管理

795 阅读15分钟

本文主要讲解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 信号

流程图

Clipboard_2023-04-16-17-32-40.png

总结下来,接收Sync信号的主要过程就是获取与SurfaceFlinger服务中的EventThread对象进行通信的通道的Fd句柄,然后将Fd添加的Looper的监听中,当有VSync信号到来时就会回调Looper的callback。即可以在这个callback中处理相关的页面逻辑。 下面看看具体源码实现

  1. 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信号了。

总结方法调用流程

Clipboard_2023-04-19-21-19-48.png

二 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 调用主要过程 :

  1. 先调用processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData) 方法,如果读取的VSync信号数据返回true。
  2. 如果processPendingEvents 返回true,接着调用dispatchVsync方法。dispatchVsync方法是在DisplayEventDispatcher的子类中实现。NativeDisplayEventReceiver继承了DisplayEventDispatcher类,所以dispatchVsync实际是在NativeDisplayEventReceiver 中实现
  3. 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

总结调用流程:

Clipboard_2023-05-03-16-06-17.png

四 窗口动画更新

调用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