SurfaceFlinger VSync信号(5)

SurfaceFlinger VSync信号

简介

Vsync是垂直同步信号,这个是用于约束渲染速度的信号,主要是为了防止出现“撕裂”的情况,所谓“撕裂”,就是画面分离的,一个图像被分成两个图像。
出现这个问题的原因是渲染和显示的速度不同导致的。举个例子。显示器刷新率是60HZ,而GPU渲染速度一秒钟更新90次,这样相当于显示器显示一帧的时间gpu可以渲染1.5屏图片,那么就会出现屏幕显示的时候,显示出第一帧的1/2图像和第二帧的1/2的图像,这样如果两帧图像内容有变化,就会出现撕裂。
而Vsync就是为了解决这个问题,比如一般android的Vsync信号是60HZ或者120HZ,gpu如果想要渲染,就必须等到一次vsync信号,只要gpu渲染和显示屏处理速度都大于等于vsync帧率,就可以避免撕裂且不会卡顿。

而Android的显示流程中,一般会用到两次VSync信号。app会向SurfaceFlinger请求VSync信号来渲染内容,SurfaceFlinger也会用VSync信号来合成内容。由于合成依赖于渲染,所以合成的内容是上一帧VSync信号渲染的内容。
Android的VSync信号是由SurfaceFlinger用软件模拟的,但是会根据hwc硬件的VSync定期更新修正。

我们会分别介绍app请求VSync信号,SurfaceFlinger侧初始化Schduler以及产生VSync信号。

app请求VSync信号

当View需要重新绘制时,都会调用invalidate(),会递归调用ViewParent的invalidate(),最终会调用到ViewRootImpl的invalidate()来请求下一个VSync,我们就从这里开始看。
在这里插入图片描述

1.1 ViewRootImpl.invalidate

void invalidate() {
    mDirty.set(0, 0, mWidth, mHeight);
    if (!mWillDrawSoon) {
        // 详见1.2
        scheduleTraversals();
    }
}

1.2 ViewRootImpl.scheduleTraversals
调用Choreographer.postCallback请求下一个VSync

void scheduleTraversals() {
    // 防止重复请求
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        // 配置异步消息,VSync消息优先处理
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // 通过Choreographer请求下一个VSync,详见1.3
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

1.3 Choreographer.postCallback
postCallback->postCallbackDelayed->postCallbackDelayedInternal
前两个方法只是传入默认参数和参数非法校验,我们直接看postCallbackDelayedInternal

主要就是调用scheduleFrameLocked,但是在这之前我们还记录来一个type为CALLBACK_TRAVERSAL的CallbackQueue,里面的action是mTraversalRunnable,这个是后面VSync回来后回调的方法。

private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {

    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        // 入参delayMillis是0,立刻执行
        final long dueTime = now + delayMillis;
        // 记录action,后续回调会使用,这里的type是Choreographer.CALLBACK_TRAVERSAL
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

        if (dueTime <= now) {
            // 走的这里,详见1.4
            scheduleFrameLocked(now);
        } else {
            // 如果有延时,post一个消息,最终还是调用scheduleFrameLocked
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

1.4 scheduleFrameLocked
主要工作是调用scheduleVsyncLocked

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        // 默认都是走这里,使用VSync信号
        if (USE_VSYNC) {
            // 如果当前是主线程,直接调用scheduleVsyncLocked,详见1.5
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked();
            } else {
                // 这里post消息,其实还是调用了scheduleVsyncLocked
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            // 。。。
        }
    }
}

1.5 scheduleVsyncLocked
调用了FrameDisplayEventReceiver的scheduleVsync
FrameDisplayEventReceiver继承DisplayEventReceiver,实际调用的DisplayEventReceiver的scheduleVsync

private void scheduleVsyncLocked() {
    try {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
        // 详见1.6
        mDisplayEventReceiver.scheduleVsync();
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

1.6 DisplayEventReceiver.scheduleVsync
jni调用nativeScheduleVsync

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 {
        //详见1.7
        nativeScheduleVsync(mReceiverPtr);
    }
}

1.7 nativeScheduleVsync
调用了NativeDisplayEventReceiver::scheduleVsync
NativeDisplayEventReceiver继承DisplayEventDispatcher,实际调用DisplayEventDispatcher::scheduleVsync

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    // 详见1.8
    status_t status = receiver->scheduleVsync();
    //。。。如果返回值不为0,抛出java异常
}

1.8 DisplayEventDispatcher::scheduleVsync
处理之前的事件,然后调用DisplayEventReceiver::requestNextVsync请求下一个VSync信号。

status_t DisplayEventDispatcher::scheduleVsync() {
    // 防止重复同时请求
    if (!mWaitingForVsync) {
        ALOGV("dispatcher %p ~ Scheduling vsync.", this);

        // Drain all pending events.
        nsecs_t vsyncTimestamp;
        PhysicalDisplayId vsyncDisplayId;
        uint32_t vsyncCount;
        VsyncEventData vsyncEventData;
        // 处理pending事件
        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
                ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
        }
        // 请求下一个VSync信号,详见1.9
        status_t status = mReceiver.requestNextVsync();
        if (status) {
            ALOGW("Failed to request next vsync, status=%d", status);
            return status;
        }

        mWaitingForVsync = true;
        mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
    }
    return OK;
}

1.9 DisplayEventReceiver::requestNextVsync()
这里mEventConnection是一个EventThreadConnection,是binder对象,requestNextVsync会调用到SurfaceFlinger侧。我们到这先看看EventThreadConnection是怎么创建的。

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != nullptr) {
        // 这里是个Binder,调用到SurfaceFlinger侧。详见2.1
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return mInitError.has_value() ? mInitError.value() : NO_INIT;
}

1.9.1 nativeInit
前面Choreographer里面持有一个java层DisplayEventReceiver,DislayEventReceiver构造会调用nativeInit,我们就从这里开始介绍。
构造了一个NativeDisplayEventReceiver,而NativeDisplayEventReceiver继承DisplayEventDispatcher

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak,
                        jobject messageQueueObj, jint vsyncSource, jint eventRegistration,
                        jlong layerHandle) {
    //。。。
    // 构造了一个NativeDisplayEventReceiver,详见1.9.2
    sp<NativeDisplayEventReceiver> receiver =
            new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue,
                                        vsyncSource, eventRegistration, layerHandle);
    status_t status = receiver->initialize();
    //。。。
    return reinterpret_cast<jlong>(receiver.get());
}

1.9.2 DisplayEventDispatcher构造
主要是构造了一个DisplayEventReceiver

DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
                                            gui::ISurfaceComposer::VsyncSource vsyncSource,
                                            EventRegistrationFlags eventRegistration,
                                            const sp<IBinder>& layerHandle)
    : mLooper(looper),
    // 构造了一个DisplayEventReceiver,详见1.9.3
        mReceiver(vsyncSource, eventRegistration, layerHandle),
        mWaitingForVsync(false),
        mLastVsyncCount(0),
        mLastScheduleVsyncTime(0) {
    ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}

1.9.3 DisplayEventReceiver构造
我们关注的mEventConnection就在这里初始化,就是通过SurfaceFlinger的binder接口createDisplayEventConnection拿到一个binder对象,除了返回binder对象,还返回了BitTube一侧的读写fd,后续端侧就可以通过这个BitTube和SurfaceFlinger通信,处理VSync相关的通知。
BitTube是对socketpair的封装,这里只要知道他可以用来跨进程通讯即可(会有两个fd,一个用来读一个用来写)。stealReceiveChannel方法将两个fd取出保存在mDataChannel中。

这里再提一下DisplayEventDispatcher::initialize方法,会把这里BitTube的fd添加到looper里。了解过Android的Looper机制就会直到,后续fd上如果有数据可读,就会自动回调LooperCallback的handleEvent。DisplayEventDispatcher继承了LooperCallback,这里传去的callback就是DisplayEventDispatcher,所以后续会回调DisplayEventDispatcher::handleEvent.

DisplayEventReceiver::DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource,
                                        EventRegistrationFlags eventRegistration,
                                        const sp<IBinder>& layerHandle) {
    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
    if (sf != nullptr) {
        mEventConnection = nullptr;
        // 详见1.9.4
        binder::Status status =
                sf->createDisplayEventConnection(vsyncSource,
                                                static_cast<
                                                        gui::ISurfaceComposer::EventRegistration>(
                                                        eventRegistration.get()),
                                                layerHandle, &mEventConnection);
        if (status.isOk() && mEventConnection != nullptr) {
            mDataChannel = std::make_unique<gui::BitTube>();
            将SurfaceFlinger返回的BitTube fd保存在mDataChannel中
            status = mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
        // 。。。
    }
}


status_t DisplayEventDispatcher::initialize() {
    // 。。。

    if (mLooper != nullptr) {
        // 添加上面BitTube的fd到Looper中,后续fd有信息就回调
        int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
        if (rc < 0) {
            return UNKNOWN_ERROR;
        }
    }

    return OK;
}

1.9.4 SurfaceFlinger::createDisplayEventConnection
调用了Scheduler的createDisplayEventConnection,Scheduler是SurfaceFlinger处理VSync信号的一重要的类,负责了VSync信号的产生,矫正等等。

sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
        gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration,
        const sp<IBinder>& layerHandle) {
    const auto& handle =
            vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger
            ? mSfConnectionHandle
            : mAppConnectionHandle;
    // createDisplayEventConnection调用了createConnectionInternal
    // 我们直接看createConnectionInternal,详见1.9.5
    return mScheduler->createDisplayEventConnection(handle, eventRegistration, layerHandle);
}  

1.9.5 Scheduler::createConnectionInternal
SurfaceFlinger有两个EventThread,分辨用来处理app-VSync和app-sf-VSync。(sf的VSync和app的Vsync不是同一个,有时候app也会需要使用sf的VSync,就是请求app-sf-VSync)
调用EventThread::createEventConnection来构造EventThreadConnection

sp<EventThreadConnection> Scheduler::createConnectionInternal(
        EventThread* eventThread, EventRegistrationFlags eventRegistration,
        const sp<IBinder>& layerHandle) {
    int32_t layerId = static_cast<int32_t>(LayerHandle::getLayerId(layerHandle));
    // createEventConnection就是直接构造EventThreadConnection
    // 我们直接看EventThreadConnection构造函数,详见1.9.6
    auto connection = eventThread->createEventConnection([&] { resync(); }, eventRegistration);
    mLayerHistory.attachChoreographer(layerId, connection);
    return connection;
}

1.9.6 EventThreadConnection构造
这里mChannel是BitTube,构造了一个BitTube用来后续的跨进程通信,同步VSync的消息。

EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid,
                                            ResyncCallback resyncCallback,
                                            EventRegistrationFlags eventRegistration)
    // 这里的resyncCallback是上面传入的Scheduler::resync,后续请求VSync就是调用这个。
    : resyncCallback(std::move(resyncCallback)),
        mOwnerUid(callingUid),
        mEventRegistration(eventRegistration),
        mEventThread(eventThread),
        mChannel(gui::BitTube::DefaultSize) {}

SurfaceFlinger处理app的VSync请求

2.1 EventThreadConnection::requestNextVsync
我们接着1.9,通过EventThreadConnection的binder调用requestNextVsync到SurfaceFlinger侧。

binder::Status EventThreadConnection::requestNextVsync() {
    ATRACE_CALL();
    // 调用EventThread::requestNextVsync,详见2.2
    mEventThread->requestNextVsync(sp<EventThreadConnection>::fromExisting(this));
    return binder::Status::ok();
}

2.2 EventThread::requestNextVsync
调用EventThreadConnection的resyncCallback,由1.9.6可知就是调用了Scheduler::resync
mCondition.notify_all唤醒EventThread去调度VSync信号。

void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
    // 由1.9.6可知这里的resyncCallback就是Scheduler::resync
    if (connection->resyncCallback) {
        // 调用Scheduler::resync,和模拟VSync信号矫正相关,如果想了解可以看5.1节
        connection->resyncCallback();
    }

    if (connection->vsyncRequest == VSyncRequest::None) {
        // 修改vsyncRequest的值,表示这个连接是需要响应下一次VSync的
        connection->vsyncRequest = VSyncRequest::Single;
        // 唤醒EventThread线程,详见2.3
        mCondition.notify_all();
    } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {
        connection->vsyncRequest = VSyncRequest::Single;
    }
}

2.3 EventThread::threadMain
EventThread就是在threadMain循环处理VSync相关的事件,每次处理完事件后会mCondition.wait(lock),等待新的事件来临唤醒线程。
这里的真实的执行顺序一般是这样:
调用来mVsyncRegistration.schedule来请求下一个VSync,然后就在mCondition等着,等下一个VSync计时器时间触发,就会往mPendingEvents放一个VSync事件并且唤醒线程,线程进入下一次循环,开始筛选Consumer(调用过requestNextVsync的都是需要回调的Consumer,Consumer就是EventThreadConnection),然后把事件分发给需要回调的Consumer。
接下去我们来详细看下这个流程。

void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    DisplayEventConsumers consumers;
    // 循环处理VSync相关的事件
    while (mState != State::Quit) {
        std::optional<DisplayEventReceiver::Event> event;

        // 从队列中获取下一个事件
        if (!mPendingEvents.empty()) {
            event = mPendingEvents.front();
            mPendingEvents.pop_front();
            // 如果是屏幕热插拔时间,重置mVSyncState,这个和软件模拟VSync逻辑有关
            // 由于软件模拟VSync信号也是通过硬件VSync样本来预测的,如果屏幕发生热插拔,模拟数据自然需要重置
            if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
                if (event->hotplug.connected && !mVSyncState) {
                    mVSyncState.emplace(event->header.displayId);
                } else if (!event->hotplug.connected && mVSyncState &&
                        mVSyncState->displayId == event->header.displayId) {
                    mVSyncState.reset();
                }
            }
        }

        bool vsyncRequested = false;

        // 我们之前说过,client会调用surfaceFlinger的binder接口构造DisplayEventConnections
        // 这里也通过DisplayEventConnections来鉴别哪些client需要响应下一次VSync
        auto it = mDisplayEventConnections.begin();
        while (it != mDisplayEventConnections.end()) {
            if (const auto connection = it->promote()) {
                // 判断这个连接是否需要相应下一次VSync
                // 判断的核心逻辑就是根据vsyncRequest,2.2节我们看到requestNextVsync是会修改vsyncRequest的,就可以根据这个值判断是否需要响应下一个VSync
                if (event && shouldConsumeEvent(*event, connection)) {
                    consumers.push_back(connection);
                }

                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;

                ++it;
            } else {
                it = mDisplayEventConnections.erase(it);
            }
        }

        if (!consumers.empty()) {
            // 给所有需要响应VSync的Connection分发事件。详见2.4
            dispatchEvent(*event, consumers);
            consumers.clear();
        }

        if (mVSyncState && vsyncRequested) {
            mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
        } else {
            ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
            mState = State::Idle;
        }

        if (mState == State::VSync) {
            // 主要就是通过这里来触发下一次VSync信号的。
            // mVsyncRegistration.schedule会设置一个alarm,在下一个vsync的时候alarm会唤醒往mPendingEvents里面添加事件。详见2.3.1
            const auto scheduleResult =
                    mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
                                                .readyDuration = mReadyDuration.count(),
                                                .earliestVsync = mLastVsyncCallbackTime.ns()});
            LOG_ALWAYS_FATAL_IF(!scheduleResult, "Error scheduling callback");
        } else {
            mVsyncRegistration.cancel();
        }

        if (!mPendingEvents.empty()) {
            continue;
        }

        // 等待在mCondition上,前面就是通过mCondition.notifyAll来唤醒的。
        if (mState == State::Idle) {
            mCondition.wait(lock);
        } else {
            // 。。。
        }
    }

    mVsyncRegistration.cancel();
}

2.3.1 VSyncCallbackRegistration.schedule
在继续分析VSync分发之前,我们先来看看VSyncCallbackRegistration.schedule,这里是请求VSync信号的关键。
实际上调用了mDispatch->schedule,这个mDispatch是从VsyncSchedule::createDispatch方法构造的,是一个VSyncDispatchTimerQueue对象,所以这里就是调用来VSyncDispatchTimerQueue::schedule

ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
    if (!mToken) {
        return std::nullopt;
    }
    // 调用了mDispatch::schedule,这里的mDispatch是在EventThread构造函数构造VSyncCallbackRegistration时候传入的
    // 最终可以看到mDispatch是一个VSyncDispatchTimerQueue,我们接下去看VSyncDispatchTimerQueue::schedule,详见2.3.2
    return mDispatch->schedule(*mToken, scheduleTiming);
}


EventThread::EventThread(const char* name, std::shared_ptr<scheduler::VsyncSchedule> vsyncSchedule,
                        android::frametimeline::TokenManager* tokenManager,
                        ThrottleVsyncCallback throttleVsyncCallback,
                        GetVsyncPeriodFunction getVsyncPeriodFunction,
                        std::chrono::nanoseconds workDuration,
                        std::chrono::nanoseconds readyDuration)
    : mThreadName(name),
        mVsyncTracer(base::StringPrintf("VSYNC-%s", name), 0),
        mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
        mReadyDuration(readyDuration),
        mVsyncSchedule(std::move(vsyncSchedule)),
        // 可以看到mDispatch是从vsyncSchedule->getDispatch方法获取的
        // VsyncSchedule是软件VSync模拟的核心类,dispatch是通过VsyncSchedule::createDispatch方法构造的
        // 是一个VSyncDispatchTimerQueue对象,这里就不跟了,我们直接看VSyncDispatchTimerQueue::schedule,详见2.3.2
        mVsyncRegistration(mVsyncSchedule->getDispatch(), createDispatchCallback(), name),
        mTokenManager(tokenManager),
        mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
        mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)) {
    // 。。。
}

2.3.2 VSyncDispatchTimerQueue::schedule
加了锁后直接调用了scheduleLocked

ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
                                                ScheduleTiming scheduleTiming) {
    std::lock_guard lock(mMutex);
    // 调用scheduleLocked,详见2.3.3
    return scheduleLocked(token, scheduleTiming);
}

2.3.3 VSyncDispatchTimerQueue::scheduleLocked
这里的逻辑有一些难懂,首先我们要先搞清楚这里的mCallbacks为什么有多个,他们是和什么对应的。实际上是和EventThread相对应的,前面我们提过SurfaceFlinger会构造两个EventThread,一个是app的VSync节奏,一个是SurfaceFlinger的VSync节奏。
但是两个EventThread的VsyncSchedule实际用的是一个,他是和屏幕相关的,因为我们知道VSync信号其实是屏幕发出来的,即使是软件模拟的VSync信号也是参照屏幕的硬件VSync来模拟,所以这里VSyncDispatchTimerQueue和EventThread是一对多(一对二)的关系。
mIntendedWakeupTime记录的是当前alarm配置的时间,有三种可能,一个配置的是kInvalidTime(是int64最大值),另一个是app EventThread请求的下一次VSync时间,还一个是SurfaceFlinger请求的下一次VSync时间。
那么当now > mIntendedWakeupTime是什么情况呢,不会是kInvalidTime,因为他是最大值,每个alarm被触发回调后要不就会把mIntendedWakeupTime更新成下一次请求的VSync(如果有人请求的话),要不就是更新成kInvalidTime。所以now > mIntendedWakeupTime应该是由于时间误差mIntendedWakeupTime记录的这个时间的alarm还没有执行的情况。这种情况我们不需要重置alram,只需要通过addPendingWorkloadUpdate记录请求的下一次VSync时间。这次alarm触发后会根据addPendingWorkloadUpdate记录的时间来配置下一次alarm。

看完这个逻辑基本上也就能理解VSyncDispatchTimerQueue这里的思路了,剩下的逻辑看起来就简单多了。

ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
                                                    ScheduleTiming scheduleTiming) {
    // 如果没有mCallbacks,直接返回。
    auto it = mCallbacks.find(token);
    if (it == mCallbacks.end()) {
        return {};
    }
    auto& callback = it->second;
    auto const now = mTimeKeeper->now();

    // mIntendedWakeupTime记录的是当前定时器设定的时间
    // 如果有Callback,并且now > mIntendedWakeupTime,说明定时器很快就会触发
    auto const rearmImminent = now > mIntendedWakeupTime;
    if (CC_UNLIKELY(rearmImminent)) {
        // 这种情况就不重置计时器来,等待之前的计时器触发后再重置。
        callback->addPendingWorkloadUpdate(scheduleTiming);
        return getExpectedCallbackTime(*mTracker, now, scheduleTiming);
    }
    // 计算是否需要更新,这里callback是VSyncDispatchTimerQueueEntry的实例,详见2.3.3.1
    const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
    if (!result.has_value()) {
        return {};
    }
    // 如果计算出来的唤醒时间在mIntendedWakeupTime(本来计时器设定的)之前,那就要重新设计计时器
    // wakeupTime()返回的是mArmedInfo里面的nextWakeupTime,在上面VSyncDispatchTimerQueueEntry::schedule计算出来的
    if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
        // 重置计时器,详见2.3.4
        rearmTimerSkippingUpdateFor(now, it);
    }

    return result;
}

2.3.3.1 VSyncDispatchTimerQueueEntry::schedule
计算下一个VSync时间以及VSync唤醒时间。
timing.workDuration和timing.readyDuration是VSync的相位,我们现在已经知道有app的VSync和sf的VSync,其实这两种VSync都是基于hwc硬件VSync的基础上,加上一定相位差,然后软件模拟出来的。
这里tracker实际是一个VSyncPredictor对象,nextAnticipatedVSyncTimeFrom会根据传入参数来找到一个最接近传入参数时间的VSync点。关于VSyncPredictor逻辑我们后面再介绍。
adjustVsyncIfNeeded方法会判断新算出来的VSync时间是不是已经是触发过或者离上一个VSync时间太接近了,如果是就再他的基础上加一个VSync周期时间(60HZ就是16ms左右)
最后把算好的VSync时间和需要唤醒的时间放到mArmedInfo里。

ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
                                                    VSyncTracker& tracker, nsecs_t now) {
    // 这里的tracker实际是一个VSyncPredictor,nextAnticipatedVSyncTimeFrom会根据入参找到附近的Vsync时间点
    // VSyncPredictor内部的逻辑我们在后面将软件模拟VSync的原理时再来介绍,现在就当做黑盒即可。
    auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
            std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
    auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;

    bool const wouldSkipAVsyncTarget =
            mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
    bool const wouldSkipAWakeup =
            mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
    if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
        return getExpectedCallbackTime(nextVsyncTime, timing);
    }
    // adjustVsyncIfNeeded调整时间的逻辑:如果拿到的nextVsyncTime离上一次太近或者是已经执行过的时间,就加一个VSync周期
    nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
    nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;

    auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
    mScheduleTiming = timing;
    // 存储算好的VSync时间到mArmedInfo
    mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
    return getExpectedCallbackTime(nextVsyncTime, timing);
}

2.3.4 VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor
重置定时器,wakeupTime是schedule计算出来的时间,PendingWorkloadUpdate是之前存储的唤醒时间,如果都没有则说明这个callback当前没有人请求VSync,否则就会调用update重新计算这个callback对应的下次VSync唤醒时间,但是入参callback因为我们刚刚计算过,所以不需要要调用update重新计算。
轮询callback找到一个最早的时间来做为定时器需要设置的时间,然后调用setTimer重置定时器。

void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
        nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
    std::optional<nsecs_t> min;
    std::optional<nsecs_t> targetVsync;
    std::optional<std::string_view> nextWakeupName;
    // 遍历所有callback,
    for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
        auto& callback = it->second;
        // wakeupTime是schedule计算出来的时间,PendingWorkloadUpdate是之前存储的唤醒时间
        if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
            continue;
        }
        // 如果不是入参的callback,重新计算该callback的VSync(入参的callback才刚刚计算过,不需要重新计算)
        if (it != skipUpdateIt) {
            callback->update(*mTracker, now);
        }
        // 找到一个最早的时间
        auto const wakeupTime = *callback->wakeupTime();
        if (!min || *min > wakeupTime) {
            nextWakeupName = callback->name();
            min = wakeupTime;
            targetVsync = callback->targetVsync();
        }
    }
    // 如果最早的时间比之前设定的mIntendedWakeupTime早,就重新配置计时器。
    if (min && min < mIntendedWakeupTime) {
        if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
            ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
                            "us; VSYNC in ", ns2us(*targetVsync - now), "us");
            ATRACE_NAME(trace.c_str());
        }
        // 重新配置计数器,详见2.3.5
        setTimer(*min, now);
    } else {
        ATRACE_NAME("cancel timer");
        cancelTimer();
    }
}

2.3.5 VSyncDispatchTimerQueue::setTimer
TimeKeeper的本质就是对linux系统调用timerfd_settime进行封装,实现一个定时器的功能。这里就是根据之前计算的VSync时间设置一个定时器,定时器到了就回调timerCallback方法。

void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
    mIntendedWakeupTime = targetTime;
    // 这里TimeKeeper实际是调用linux的系统调用timerfd_settime来配置计时器,我们就不细看了。
    // 等VSync时间到了,回调VSyncDispatchTimerQueue::timerCallback,详见2.3.6
    mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
                        mIntendedWakeupTime);
    mLastTimerSchedule = mTimeKeeper->now();
}

2.3.6 VSyncDispatchTimerQueue::timerCallback
这个方法主要的逻辑就是根据callback.wakeupTime来判断这个callback是否需要立刻回调。如果需要就封装到一个Invocation,再push到一个队列里,轮询回调。同时由于当前计时器已经触发,需要重新调用rearmTimerSkippingUpdateFor来确认是否需要配置下一个计时器。

void VSyncDispatchTimerQueue::timerCallback() {
    struct Invocation {
        std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
        nsecs_t vsyncTimestamp;
        nsecs_t wakeupTimestamp;
        nsecs_t deadlineTimestamp;
    };
    std::vector<Invocation> invocations;
    {
        std::lock_guard lock(mMutex);
        auto const now = mTimeKeeper->now();
        mLastTimerCallback = now;
        for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
            auto& callback = it->second;
            // 如果需要回调的wakeupTime一定不为空。
            auto const wakeupTime = callback->wakeupTime();
            if (!wakeupTime) {
                continue;
            }

            auto const readyTime = callback->readyTime();

            auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
            // 根据wakeupTime判断这个callback是否需要回调,如果需要则封装到Invocation
            if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
                callback->executing();
                invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
                                                    *wakeupTime, *readyTime});
            }
        }

        mIntendedWakeupTime = kInvalidTime;
        // 重置计时器,实际调用还是rearmTimerSkippingUpdateFor,详见之前2.3.4
        rearmTimer(mTimeKeeper->now());
    }

    // 之前判断过需要当前触发的callback都封装存储到invocations,现在开始回调。
    for (auto const& invocation : invocations) {
        详见2.3.7
        invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
                                    invocation.deadlineTimestamp);
    }
}

2.3.7 VSyncDispatchTimerQueueEntry::callback
这个mCallback是VSyncDispatchTimerQueueEntry构造时传入的。
这里的构造链路:
EventThread::onNewVsyncSchedule里构造VSyncCallbackRegistration
-》VSyncCallbackRegistration构造时构造了VSyncDispatchTimerQueueEntry
-》VSyncDispatchTimerQueueEntry构造传入了mCallback
由此我们也可以看出来,VSyncDispatchTimerQueue里面的callback其实是和EventThread一一关联的。

void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
                                            nsecs_t deadlineTimestamp) {
    {
        std::lock_guard<std::mutex> lk(mRunningMutex);
        mRunning = true;
    }
    // 这个mCallback是VSyncDispatchTimerQueueEntry构造时传入的。
    // 这里的构造链路是EventThread::onNewVsyncSchedule里构造VSyncCallbackRegistration
    // VSyncCallbackRegistration构造时构造了VSyncDispatchTimerQueueEntry
    // VSyncDispatchTimerQueueEntry构造传入了mCallback
    mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);

    std::lock_guard<std::mutex> lk(mRunningMutex);
    mRunning = false;
    mCv.notify_all();
}


scheduler::VSyncCallbackRegistration EventThread::onNewVsyncScheduleInternal(
    std::shared_ptr<scheduler::VsyncSchedule> schedule) {
// 。。。
auto oldRegistration =
        std::exchange(mVsyncRegistration,
                      scheduler::VSyncCallbackRegistration(mVsyncSchedule->getDispatch(),
                      // mCallback就是createDispatchCallback,详见2.3.8
                                                           createDispatchCallback(),
                                                           mThreadName));
// 。。。
return oldRegistration;

}

2.3.8 EventThread::createDispatchCallback()
mCallback其实就是回调EventThread::onVsync

scheduler::VSyncDispatch::Callback EventThread::createDispatchCallback() {
    return [this](nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
        // 所以2.3.7 的mCallback就是回调EventThread::onVsync,详见2.3.9
        onVsync(vsyncTime, wakeupTime, readyTime);
    };
}

2.3.9 EventThread::onVsync
构造一个VSync的Event,放在mPendingEvents队列里,然后唤醒2.3 EventThread::threadMain来处理这个事件,到此我们就介绍完了一个VSync信号是怎么产生的。接下去我们看下分发回应用的逻辑。

void EventThread::onVsync(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
    std::lock_guard<std::mutex> lock(mMutex);
    mLastVsyncCallbackTime = TimePoint::fromNs(vsyncTime);

    LOG_FATAL_IF(!mVSyncState);
    mVsyncTracer = (mVsyncTracer + 1) % 2;
    // 构造了一个VSync事件,放在mPendingEvents
    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, wakeupTime, ++mVSyncState->count,
                                    vsyncTime, readyTime));
    // 唤醒2.3 EventThread::threadMain来处理这个事件。
    mCondition.notify_all();
}

2.4 EventThread::dispatchEvent
我们接着2.3 threadMain里面调用dispatchEvent来分发VSync事件的逻辑继续看。
由2.3我们可以知道这里consumers都是调用过requestNextVSync的EventThreadConnection。

void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                const DisplayEventConsumers& consumers) {
    for (const auto& consumer : consumers) {
        DisplayEventReceiver::Event copy = event;
        // 。。。
        // 调用postEvent分发事件,详见2.5
        switch (consumer->postEvent(copy)) {
            // 。。。
        }
    }
}

2.5 EventThreadConnection::postEvent
通过BitTube通道发送事件

status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
    // 。。。
    // 通过BitTube通道发送事件。
    auto size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
    return toStatus(size);
}

2.6 DisplayEventDispatcher::handleEvent
之前在1.9.3有提到过,我们把Bitube的fd通过mLooper->addFd加到looper里,这样当fd消息就会回调DisplayEventDispatcher::handleEvent

processPendingEvents里面会调用mReceiver.getEvents来获取2.5节通过BitTube传过来的字节流,并且构建一个Events.
然后调用dispatchVsync来分发VSync事件。

int DisplayEventDispatcher::handleEvent(int, int events, void*) {

    // 。。。
    nsecs_t vsyncTimestamp;
    PhysicalDisplayId vsyncDisplayId;
    uint32_t vsyncCount;
    VsyncEventData vsyncEventData;
    // 调用mReceiver.getEvents,将BitTube的字节流封装成Event
    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
        // 。。。
        mWaitingForVsync = false;
        mLastVsyncCount = vsyncCount;
        // 分发事件,详见2.7
        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
    }

    // 等待超时则直接分发一个空的Event VSync
    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
}

2.7 NativeDisplayEventReceiver::dispatchVsync
这里DisplayEventDispatcher实际是NativeDisplayEventReceiver,前面初始化的时候介绍过,所以这里实际调用来NativeDisplayEventReceiver::dispatchVsync
这里是jni回调回java层,调用DisplayEventReceiver的dispatchVsync

void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
uint32_t count, VsyncEventData vsyncEventData) {
// 。。。
if (receiverObj.get() && vsyncEventDataObj.get()) {
// 。。。
// jni反向调用java层,调用DisplayEventReceiver的dispatchVsync,详见2.8
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
timestamp, displayId.value, count);
ALOGV(“receiver %p ~ Returned from vsync handler.”, this);
}

mMessageQueue->raiseAndClearException(env, "dispatchVsync");

}

2.8 DisplayEventReceiver.dispatchVsync
调用了onVsync,前面介绍过,这里的DisplayEventReceiver实际是FrameDisplayEventReceiver,所以回调的是Chreographer的内部类FrameDisplayEventReceiver的onVsync

private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
    onVsync(timestampNanos, physicalDisplayId, frame, mVsyncEventData);
}

2.9 FrameDisplayEventReceiver.onVsync
发送了一个MSG_DO_FRAME消息,这里没有配置message.what,但是MSG_DO_FRAME的实际值就是0,所以没有配置消息类型默认就是MSG_DO_FRAME。mHandler是FrameHandler的实例。

public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
            VsyncEventData vsyncEventData) {
    try {
        // 。。。
        mTimestampNanos = timestampNanos;
        mFrame = frame;
        mLastVsyncEventData.copyFrom(vsyncEventData);
        Message msg = Message.obtain(mHandler, this);
        msg.setAsynchronous(true);
        // 发送了一个MSG_DO_FRAME消息,FrameHandler处理,详见2.10
        mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

2.10 FrameHandler.handleMessage
调用了doFrame

public void handleMessage(Message msg) {
    switch (msg.what) {
        case MSG_DO_FRAME:
            //详见2.11
            doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
            break;
        // 。。。
    }
}

2.11 Choreographer.doFrame
这里doCallbacks中type为CALLBACK_TRAVERSAL的回调是mTraversalRunnable,链路太长来可能忘记来,我们回头看看1.3节,这个callback是在1.3节配置的。
mTraversalRunnable在ViewRootImpl里,里面会执行ViewRootImpl.doTraversal,后面就不展开将来,和本章内容关系不大,做过应用开发的可能知道doTraversal会执行View的测量,布局,绘制等,这样应用侧的请求Vsync信号的流程的我们就讲解完了,接下去看一下SurfaceFlinger侧。

void doFrame(long frameTimeNanos, int frame,
        DisplayEventReceiver.VsyncEventData vsyncEventData) {
    final long startNanos;
    final long frameIntervalNanos = vsyncEventData.frameInterval;
    boolean resynced = false;
    try {

        // 。。。处理VsyncEventData里面的数据,封装到FrameInfo
        mFrameInfo.markInputHandlingStart();
        doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);

        mFrameInfo.markAnimationsStart();
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);
        doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);

        mFrameInfo.markPerformTraversalsStart();
        // 主要是这里的回调,大家回头看看1.3节,之前配置的CALLBACK_TRAVERSAL类型的callback
        // 这里的callback是mTraversalRunnable
        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);
    }
    // 。。。
}

SurfaceFlinger请求VSync

我们之前在介绍BlastBufferQueue那个章节的时候提到过,无论是内容变化还是窗口属性变化,都会通过Transaction.apply来同步给SurfaceFlinger,而SurfaceFlinger在处理变化后都会调用SurfaceFlinger::setTransactionFlags,记录需要重新做合成,这时候就会去请求VSync信号,我们就从这里开始看。
这个流程总体比较简单,相对复杂的部分和上面app的请求VSync是一样的。
在这里插入图片描述

3.1 SurfaceFlinger::setTransactionFlags
调用scheduleCommit来请求下一个VSync,这个VSync是SurfaceFlinger用来合成图层的。

void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
                                        const sp<IBinder>& applyToken, FrameHint frameHint) {
    mScheduler->modulateVsync({}, &VsyncModulator::setTransactionSchedule, schedule, applyToken);
    uint32_t transactionFlags = mTransactionFlags.fetch_or(mask);
    ATRACE_INT("mTransactionFlags", transactionFlags);

    if (const bool scheduled = transactionFlags & mask; !scheduled) {
        // 调用scheduleCommit来请求下一个VSync,详见3.2
        scheduleCommit(frameHint);
    } else if (frameHint == FrameHint::kActive) {
        mScheduler->resetIdleTimer();
    }
}

3.2 SurfaceFlinger::scheduleCommit
调用Scheduler::scheduleFrame,我们之前说过VSync的调用都是由Schduler来处理的,这里也是调用Srchduler的方法

void SurfaceFlinger::scheduleCommit(FrameHint hint) {
    if (hint == FrameHint::kActive) {
        mScheduler->resetIdleTimer();
    }
    mPowerAdvisor->notifyDisplayUpdateImminentAndCpuReset();
    // 调用Scheduler::scheduleFrame,详见3.3
    mScheduler->scheduleFrame();
}

3.3 MessageQueue::scheduleFrame
Scheduler继承自MessageQueue,所以这里实际执行的是MessageQueue::scheduleFrame
mVsync.registration->schedule是不是看着很眼熟,2.3.1已经讲过这个逻辑了,最终他会回调VSyncCallbackRegistration内部的mCallback,我们往下来看看这里的mCallback是哪里传入的

void MessageQueue::scheduleFrame() {
    ATRACE_CALL();

    std::lock_guard lock(mVsync.mutex);
    // 前面已经介绍过了,这里的逻辑和app请求是一样的。
    mVsync.scheduledFrameTime =
            mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
                                        .readyDuration = 0,
                                        .earliestVsync = mVsync.lastCallbackTime.ns()});
}

3.4 MessageQueue::onNewVsyncScheduleLocked
这里的链路实际是在Scheduler初始化时,调用initVsync->onNewVsyncSchedule->onNewVsyncScheduleLocked,但是我们不关注这些,直接来看传入mCallback的地方MessageQueue::onNewVsyncScheduleLocked。
可以看到最终回调方法是MessageQueue::vsyncCallback

std::unique_ptr<scheduler::VSyncCallbackRegistration> MessageQueue::onNewVsyncScheduleLocked(
        std::shared_ptr<scheduler::VSyncDispatch> dispatch) {
    const bool reschedule = mVsync.registration &&
            mVsync.registration->cancel() == scheduler::CancelResult::Cancelled;
    auto oldRegistration = std::move(mVsync.registration);
    mVsync.registration = std::make_unique<
            scheduler::VSyncCallbackRegistration>(std::move(dispatch),
                                                // MessageQueue::vsyncCallback是传入的回调,详见3.5
                                                std::bind(&MessageQueue::vsyncCallback, this,
                                                            std::placeholders::_1,
                                                            std::placeholders::_2,
                                                            std::placeholders::_3),
                                                "sf");
    if (reschedule) {
        mVsync.scheduledFrameTime =
                mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
                                            .readyDuration = 0,
                                            .earliestVsync = mVsync.lastCallbackTime.ns()});
    }
    return oldRegistration;
}

3.5 MessageQueue::vsyncCallback
封装来一下VSync的参数,调用了Handler::dispatchFrame

void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
    ATRACE_CALL();
    // Trace VSYNC-sf
    mVsync.value = (mVsync.value + 1) % 2;

    const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime);
    {
        std::lock_guard lock(mVsync.mutex);
        mVsync.lastCallbackTime = expectedVsyncTime;
        mVsync.scheduledFrameTime.reset();
    }

    const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
            {targetWakeupTime, readyTime, vsyncTime})};
    // 详见3.6
    mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
}  

3.6 MessageQueue::Handler::dispatchFrame
post了一个消息,我们来看handleMessage处理消息的地方。

void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) {
    if (!mFramePending.exchange(true)) {
        mVsyncId = vsyncId;
        mExpectedVsyncTime = expectedVsyncTime;
        // 往looper里发送来一个消息,在handleMessage处理,详见3.7
        mQueue.mLooper->sendMessage(sp<MessageHandler>::fromExisting(this), Message());
    }
}

3.7 MessageQueue::Handler::handleMessage
调用MessageQueue::onFrameSignal,这里的MessageQueue是Scheduler实例,所以调用的是Scheduler::onFrameSignal

void MessageQueue::Handler::handleMessage(const Message&) {
    mFramePending.store(false);
    // 详见3.8
    mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime);
}

3.8 Scheduler::onFrameSignal
到这里SurfaceFlinger就收到了VSync,并且开始处理了,SurfaceFlinger收到VSync信号主要做的处理就是合成surface。

void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
                          TimePoint expectedVsyncTime) {
    const TimePoint frameTime = SchedulerClock::now();
    // 做合成的一些预处理,判断flag决策是否需要合成
    if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) {
        return;
    }
    // 触发合成。
    compositor.composite(frameTime, vsyncId);
    compositor.sample();
}

软件模拟VSync信号的计算以及矫正

我们在2.3.3.1节提到过,使用的VSync是软件模拟,通过VSyncPredictor::nextAnticipatedVSyncTimeFrom来预测的,实际上软件VSync的模拟也是离不开硬件VSync的样本。接下来我们来介绍一下软件VSync模拟以及矫正的逻辑。
大家可能会有点疑惑,觉得软件模拟VSync不是很简单吗,怎么会有这么复杂的逻辑,直接搞一个计时器,60HZ就弄一个16.666~ms的计时器不就行了。其实这样是不准确的,首先定时器的接口提供的能力本身就不一定准确,加上我们需要收到定时器后再去配置下一个定时器,代码执行也需要一些时间,所以就会造成不小的误差。
而这里模拟的思路就是我们根据HWC硬件提供的VSync样本来计算软件需要的间隔时间,也就是说,可能60HZ的时候,我们算出来定时器是15ms一次(只是打个比方)。

我们先从VSyncPredictor::nextAnticipatedVSyncTimeFrom入手来分析。
4.1 VSyncPredictor::nextAnticipatedVSyncTimeFrom
我们之前提过这个方法的作用,传入的参数是一个时间点,返回最靠近这个时间点的VSync信号的时间戳。

nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const {
    std::lock_guard lock(mMutex);

    // 根据现在的模型获取下一个VSync,详见4.2
    mLastVsyncSequence = getVsyncSequenceLocked(timePoint);

    const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int {
        if (!mRenderRate) return 0;

        const auto divisor =
                RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod),
                                                        *mRenderRate);
        if (divisor <= 1) return 0;

        const int mod = mLastVsyncSequence->seq % divisor;
        if (mod == 0) return 0;

        return divisor - mod;
    }();
    // 正常直接返回算好的VSync,否则是当屏幕的刷新率比渲染率快很多时候的处理。
    if (renderRatePhase == 0) {
        return mLastVsyncSequence->vsyncTime;
    }

    auto const [slope, intercept] = getVSyncPredictionModelLocked();
    const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase;
    return nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2);
}

4.2 VSyncPredictor::getVsyncSequenceLocked
通过nextAnticipatedVSyncTimeFromLocked获取下一个VSync时间,并且根据返回的VSync时间算VSync的序列号。

auto VSyncPredictor::getVsyncSequenceLocked(nsecs_t timestamp) const -> VsyncSequence {
    // 通过nextAnticipatedVSyncTimeFromLocked获取下一个VSync时间,详见4.3
    const auto vsync = nextAnticipatedVSyncTimeFromLocked(timestamp);
    if (!mLastVsyncSequence) return {vsync, 0};
    // VsyncSequence是VSync的序列号,表示他是第几个VSync,这里的计算很简单就不说了。
    const auto [slope, _] = getVSyncPredictionModelLocked();
    const auto [lastVsyncTime, lastVsyncSequence] = *mLastVsyncSequence;
    const auto vsyncSequence = lastVsyncSequence +
            static_cast<int64_t>(std::round((vsync - lastVsyncTime) / static_cast<float>(slope)));
    return {vsync, vsyncSequence};
}

4.3 VSyncPredictor::nextAnticipatedVSyncTimeFromLocked
这里分两种模式:
1.样本集为空的情况,这种情况就是根据第一个点加上n个VSync周期(大于timePonit的最小值)作为下一个VSync.
2.第二种情况是有足够的硬件VSync样本,那么会通过硬件VSync样本来计算一个模型,其实就是一条直线:y = slope * x + intercept。然后计算这个直线上,timePonit作为y,获得x,然后取大于x的最小整数,带入直线再算出y,作为下一个VSync信号的时间戳,说的有一些绕口,但是实际很简单,就是初中的数学知识。

接下去我们要看看是怎么计算出这个模型[slope, intercept]的,详见4.4 VSyncPredictor::addVsyncTimestamp

nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const {
    // 获取一个Model,这个model其实就是两个数值,slope斜率和intercept偏移。
    // 有这两个值就可以确定一条直线,而这个直线就是VSync预测函数。
    // 这两个值是通过硬件VSync样本点来计算出来的
    auto const [slope, intercept] = getVSyncPredictionModelLocked();
    // mTimestamps是样本集,一般是硬件VSync时间点
    // 如果现在样本是空的,那么就没法确定model这条直线,这个时候直接来算下一个VSync时间
    if (mTimestamps.empty()) {
        // mKnownTimestamp记录第一个样本点,如果有一个样本点,就一这个样本点来计算
        // 如果一个样本点都没有,就把入参当做第一个样本点时间
        auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint;
        // mIdealPeriod是刷新周期,比如当前刷新率如果是60HZ就是16.6ms
        // 计算得到的numPeriodsOut就是timePoint后面一个VSync距离第一个样本点的周期数
        auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1;
        // 直接以第一个样本时间+(上面计算出来的下一个VSync距离第一个样本周期数*单个周期的时间)来计算下一个VSync
        return knownTimestamp + numPeriodsOut * mIdealPeriod;
    }
    // 获取样本点里最早的
    auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end());

    // 这里就是通过简单的数据计算,基于前面斜率,intercept偏移确定的直线来确定下一个VSync时间点
    // 这里我举个具体的数字例子更容易讲清楚,假如我们的模型斜率是16,偏移是1。
    // 那么就是y = 16x + 1,第一个VSync时间就是1,第二个就是17,假如timePoint传入的是10,那么计算出来的下一个VSync就是17。
    auto const zeroPoint = oldest + intercept;
    auto const ordinalRequest = (timePoint - zeroPoint + slope) / slope;
    auto const prediction = (ordinalRequest * slope) + intercept + oldest;
    // 。。。日志打印

    return prediction;
}  

4.4 VSyncPredictor::addVsyncTimestamp
这个方法的入口是我们在后面会讲,如果感兴趣可以看5.1节。 核心逻辑就是app请求VSync时候,如果发现上一次硬件校准时间超过750ms了,就会触发硬件校准,到HWC去注册硬件VSync。

这里计算直线模型的算法是一元线性回归,我们就不详细看代码了,google给出计算公式的注释。

bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) {
    std::lock_guard lock(mMutex);

    if (!validate(timestamp)) {
        // 如果是无效的timestamp(和之前样本模型误差很大),就清空样本集
        if (mTimestamps.size() < kMinimumSamplesForPrediction) {
            mTimestamps.push_back(timestamp);
            clearTimestamps();
        } else if (!mTimestamps.empty()) {
            mKnownTimestamp =
                    std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end()));
        } else {
            mKnownTimestamp = timestamp;
        }
        return false;
    }
    // 添加样本集
    if (mTimestamps.size() != kHistorySize) {
        mTimestamps.push_back(timestamp);
        mLastTimestampIndex = next(mLastTimestampIndex);
    } else {
        mLastTimestampIndex = next(mLastTimestampIndex);
        mTimestamps[mLastTimestampIndex] = timestamp;
    }

    traceInt64If("VSP-ts", timestamp);

    const size_t numSamples = mTimestamps.size();
    // 如果样本集数量不够,就不计算模型参数
    if (numSamples < kMinimumSamplesForPrediction) {
        mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
        return true;
    }

    // This is a 'simple linear regression' calculation of Y over X, with Y being the
    // vsync timestamps, and X being the ordinal of vsync count.
    // The calculated slope is the vsync period.
    // Formula for reference:
    // Sigma_i: means sum over all timestamps.
    // mean(variable): statistical mean of variable.
    // X: snapped ordinal of the timestamp
    // Y: vsync timestamp
    //
    //         Sigma_i( (X_i - mean(X)) * (Y_i - mean(Y) )
    // slope = -------------------------------------------
    //         Sigma_i ( X_i - mean(X) ) ^ 2
    //
    // intercept = mean(Y) - slope * mean(X)
    //

    // 。。。计算模型
    // 这里就不看计算逻辑了,google给了我们注释,上面的公式就是计算模型的算法
    // 有数学基础的话就能看出来这个是一个一元线性回归,思路就是找出一条线,尽量和我们的样本点拟合。
    // slope是斜率,intercept是偏移。
    return true;
}  

其他(硬件VSync的触发流程/矫正的触发点)

硬件VSync的流程因为涉及HWC,很多细节不同平台也会不一样,而且总体也不复杂,我们不会介绍的那么详细,主要带了解一下大体的流程和思路。
回看一下2.2节,我们之前在app请求VSync信号的流程中提到来中间会调用Schduler::resync这个方法,这个就是校准用的,我们就从这里开始看
在这里插入图片描述
5.1 Scheduler::resync
判断距离上次校准时间是否超过750ms,如果超过就调用resyncAllToHardwareVsync再次进行校准。

void Scheduler::resync() {
    static constexpr nsecs_t kIgnoreDelay = ms2ns(750);

    const nsecs_t now = systemTime();
    const nsecs_t last = mLastResyncTime.exchange(now);
    // 只有上次校准间隔750ms以上才会再次校准
    if (now - last > kIgnoreDelay) {
        // 详见5.2
        resyncAllToHardwareVsync(false /* allowToEnable */);
    }
}  

5.2 resyncAllToHardwareVsync

void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
    ATRACE_CALL();
    std::scoped_lock lock(mDisplayLock);
    ftl::FakeGuard guard(kMainThreadContext);
    // 遍历mDisplays,调用resyncToHardwareVsyncLocked
    // 因为这里校准的依据是硬件VSync信号,不同屏幕可能是不同的硬件环境,详见5.3
    for (const auto& [id, _] : mDisplays) {
        resyncToHardwareVsyncLocked(id, allowToEnable);
    }
}

5.3 Scheduler::resyncToHardwareVsyncLocked
这里hw VSync有三种状态:

  • Enabled 当前hwVSyncz正在工作
  • Disabled 当前没有打开hwVSync(目前不在校准,可以通过enableHardwareVsync来enable)
  • Disallowed 不允许使用hwVSync,因为屏幕是灭屏状态

调用isHardwareVsyncAllowed判断状态是否处在Disallowed,只要不是Disallowed状态就继续校准流程。
startPeriodTransition传入的参数mSchedulerCallback是Scheduler构造时传入的,后面hw VSync回来之后会调用,后面再看。

void Scheduler::resyncToHardwareVsyncLocked(PhysicalDisplayId id, bool allowToEnable,
                                            std::optional<Fps> refreshRate) {
    const auto displayOpt = mDisplays.get(id);
    if (!displayOpt) {
        ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
        return;
    }
    const Display& display = *displayOpt;
    // 判断硬件VSync状态,只要不是Disallowed就返回ture(如果参数是ture,会把状态从Disallowed改成Disabled)
    if (display.schedulePtr->isHardwareVsyncAllowed(allowToEnable)) {
        if (!refreshRate) {
            refreshRate = display.selectorPtr->getActiveMode().modePtr->getFps();
        }
        if (refreshRate->isValid()) {
            // 这里的mSchedulerCallback是构建Scheduler时传入的,实际是SurfaceFlinger对象, 后面hwVSync信号回来会回调
            // schdulerPtr是VsyncSchedule,详见5.4
            display.schedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate->getPeriod(),
                                                    false /* force */);
        }
    }
}

5.4 VsyncSchedule::startPeriodTransition
startPeriodTransition主要是根据周期是否变化以及入参force来修改mMoreSamplesNeeded变量,同时会判断是否需要清空mUnfiredFences列表,这里列表里面存的是一些Fence,这里是另一个校准入口,我们只顺带提一下,在每次postComposition提交layer合成后,会去hwc拿一个Fence,然后通过这个Fence的时间来验证我们的软件模拟VSync模型是否准确,如果不准确也会触发校准逻辑。这里感兴趣的话自己去看一下,我们就不介绍了。
这个方法核心是调用enableHardwareVsyncLocked来使能hwVsync

void VsyncSchedule::startPeriodTransition(ISchedulerCallback& callback, Period period, bool force) {
    std::lock_guard<std::mutex> lock(mHwVsyncLock);
    // 主要是根据周期是否变化以及入参force来修改mMoreSamplesNeeded变量
    mController->startPeriodTransition(period.ns(), force);
    // 使能hw VSync,详见 5.5
    enableHardwareVsyncLocked(callback);
}

5.5 syncSchedule::enableHardwareVsyncLocked
主要就是调用了SurfaceFlinger::setVsyncEnabled使能VSync

void VsyncSchedule::enableHardwareVsyncLocked(ISchedulerCallback& callback) {
    if (mHwVsyncState == HwVsyncState::Disabled) {
        // 本来如果是Disabled,说明我们刚开始校准模型,把之前的模型reset掉。
        getTracker().resetModel();
        // 前面说过这个callback实际是SurfaceFlinger,这里就是调用SurfaceFlinger::setVsyncEnabled,详见5.6
        callback.setVsyncEnabled(mId, true);
        mHwVsyncState = HwVsyncState::Enabled;
    }
}

5.6 SurfaceFlinger::setVsyncEnabled
主要是调用了setHWCVsyncEnabled使能VSync

void SurfaceFlinger::setVsyncEnabled(PhysicalDisplayId id, bool enabled) {
    static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
        // 。。。

        if (const auto display = getDisplayDeviceLocked(id); display && display->isPoweredOn()) {
            // 详见5.7
            setHWCVsyncEnabled(id, enabled);
        }
    }));
}

5.7 SurfaceFlinger::setHWCVsyncEnabled
这里的getHwComposer返回的值是在SurfaceFlinger::init初始化的,其实是一个aidl的client端,SurfaceFlinger借助这个Cilent和HWC进行通信。
setVsyncEnabled是binder调用,调用到来HWC侧。

void setHWCVsyncEnabled(PhysicalDisplayId id, bool enabled) {
    hal::Vsync halState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;
    // 我们先来看看getHwComposer()是什么,详见5.7.1
    // setVsyncEnabled见5.8
    getHwComposer().setVsyncEnabled(id, halState);
}

5.7.1 SurfaceFlinger::init()

void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
    // 。。。
    // 这里只列了相关代码,上面getHwComposer()的结果就是这里构造的
    // 详见5.7.2
    mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));
    // 这里还注册来HWC的回调,后面HWC想要通知SurfaceFlinger就是通过这个Callback.
    // 这个Callback传的this,就是SurfaceFlinger
    mCompositionEngine->getHwComposer().setCallback(*this);
    // 。。。
}

5.7.2 DefaultFactory::createHWComposer
调用了Hwc2::Composer::create构造Composer

std::unique_ptr<HWComposer> DefaultFactory::createHWComposer(const std::string& serviceName) {
    return std::make_unique<android::impl::HWComposer>(serviceName);
}

HWComposer::HWComposer(const std::string& composerServiceName)
    // 详见5.7.3
  : HWComposer(Hwc2::Composer::create(composerServiceName)) {}

5.7.3 Composer::create
旧版本的Android用的hidl和底层hal通信(HWC),但是新版本的Android也换成aidl了。这里通过serviceName去ServiceManager里面拿到hwc binder的handle,后续就可以跟hwc进行binder通信了。

std::unique_ptr<Composer> Composer::create(const std::string& serviceName) {
    if (AidlComposer::isDeclared(serviceName)) {
        return std::make_unique<AidlComposer>(serviceName);
    }

    return std::make_unique<HidlComposer>(serviceName);
}

5.8 AidlComposer::setVsyncEnabled
我们接着5.7来看setVsyncEnabled
这里相关的aidl定义在/hardware/interfaces/graphics/composer/aidl/android/hardware/graphics/composer3路径下
真正的实现在/hardware/google/graphics/commom/hwc3下。
因为这里的操作和硬件关联较大,所以最终实现不同平台差异较大,我们就只简单看一下谷歌aosp的流程。

Error AidlComposer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
    const bool enableVsync = enabled == IComposerClient::Vsync::ENABLE;
    // binder调用,详见5.9
    const auto status =
            mAidlComposerClient->setVsyncEnabled(translate<int64_t>(display), enableVsync);
    // 。。。
    return Error::NONE;
}

5.9 ComposerClient::setVsyncEnabled
调用mHal的setVsyncEnabled,这里mHal是IComposerHal接口,也是个binder,在aosp中他的实现类是HalImpl

ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t display, bool enabled) {
    DEBUG_DISPLAY_FUNC(display);
    // 这里的mHal是IComposerHal,详见5.10
    auto err = mHal->setVsyncEnabled(display, enabled);
    return TO_BINDER_STATUS(err);
}

5.10 HalImpl::setVsyncEnabled
这里我们已经在Composer services里面了,而不是在SurfaceFlinger进程里。

int32_t HalImpl::setVsyncEnabled(int64_t display, bool enabled) {
    ExynosDisplay* halDisplay;
    RET_IF_ERR(getHalDisplay(display, halDisplay));

    hwc2_vsync_t hwcEnable;
    a2h::translate(enabled, hwcEnable);
    // halDisplay有很几种类型,但是最终都是继承自是ExynosDisplay实例,详见5.11
    return halDisplay->setVsyncEnabled(hwcEnable);
}

5.11 ExynosDisplay::setVsyncEnabled
mDisplayInterface是ExynosDisplayInterface或者继承他的某个子类,我们这里以ExynosDisplayDrmInterface为例进行介绍。
从这个名字可以看出他和drm有关系,新版本的Android现在的UI驱动架构都是基于linux的drm架构来实现的。目前我们不会对drm做过多介绍(本人水平有限),如果后面有时间

int32_t ExynosDisplay::setVsyncEnabled(
        int32_t /*hwc2_vsync_t*/ enabled) {
    Mutex::Autolock lock(mDisplayMutex);
    return setVsyncEnabledInternal(enabled);
}

int32_t ExynosDisplay::setVsyncEnabledInternal(
    int32_t enabled) {

    // 。。。
    // 核心流程在这里,mDisplayInterface的是ExynosDisplayInterface或者继承他的某个子类
    // 我们这里以ExynosDisplayDrmInterface为例进行介绍
    if (mDisplayInterface->setVsyncEnabled(val) < 0) {
        HWC_LOGE(this, "vsync ioctl failed errno : %d", errno);
        return HWC2_ERROR_BAD_DISPLAY;
    }

    mVsyncState = (hwc2_vsync_t)enabled;

    return HWC2_ERROR_NONE;
}

5.12 ExynosDisplayDrmInterface::setVsyncEnabled

int32_t ExynosDisplayDrmInterface::setVsyncEnabled(uint32_t enabled)
{
    if (enabled == HWC2_VSYNC_ENABLE) {
        // 使能VSyncWorker,详见5.13
        mDrmVSyncWorker.VSyncControl(true);
    } else {
        if (mVsyncCallback.getDesiredVsyncPeriod() == 0)
            mDrmVSyncWorker.VSyncControl(false);
    }
    // 回调通知VSync使能状态变化,这里我们不关心
    mVsyncCallback.enableVSync(HWC2_VSYNC_ENABLE == enabled);
    // 。。。
    return NO_ERROR;
}

5.13 VSyncWorker::VSyncControl
设置enable位,然后唤醒在cond_等待的线程,每个VSyncWork都会启一个线程然后循环执行VSyncWorker::Routine方法,然后如果之前enable是false,就会在cond_上等待唤醒。

void VSyncWorker::VSyncControl(bool enabled) {
    Lock();
    // 配置变量enabled
    enabled_ = enabled;
    last_timestamp_ = -1;
    Unlock();
    // 唤醒等待在cond_上的线程。
    // 这里VSyncWorker其实是一个线程循环执行Routine方法,这个线程会在cond_上挂起
    // 接下来我们来分析一下Routine这个方法,详见5.14
    Signal();
}

void Signal() {
    cond_.notify_all();
}

5.14 VSyncWorker::Routine
这个方法看着有点长,其实逻辑很简单,未使能的情况会在WaitForSignalOrExitLocked上等待,然后一直等到上面使能VSync的时候Signal之后唤醒。然后后面会通过drm的接口,等待硬件VSync信号。
硬件VSync信号来之后就调用callback_回调。

void VSyncWorker::Routine() {
int ret = 0;

Lock();
if (!enabled_) {
    // 如果是unabled状态,会在这里等待,实际是等待在cond_上,我们上面看到使能VSync就会唤醒这里。
    ret = WaitForSignalOrExitLocked();
    if (ret == -EINTR) {
    Unlock();
    return;
    }
}

// 。。。

if (pipe != nullptr) {
    uint32_t high_crtc = (pipe->crtc->Get()->GetIndexInResArray()
                        << DRM_VBLANK_HIGH_CRTC_SHIFT);

    vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
                                            (high_crtc &
                                            DRM_VBLANK_HIGH_CRTC_MASK));
    vblank.request.sequence = 1;
    // 这个方法就是等待DRM的VSync时间
    // 关于DRM我们就不深入了
    ret = drmWaitVBlank(pipe->device->GetFd(), &vblank);
    if (ret == -EINTR)
    return;
}

if (ret) {
    ret = SyntheticWaitVBlank(&timestamp);
    if (ret)
    return;
} else {
    timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
                (int64_t)vblank.reply.tval_usec * 1000;
}

if (!enabled_)
    return;

if (callback_) {
    // 回调callback_,这里的callback_是VsyncCallback,在我们这个流程里实际是ExynosDisplayDrmInterface,详见5.15
    callback_(timestamp);
}

last_timestamp_ = timestamp;
}

5.15 ExynosDisplayDrmInterface::Callback

void ExynosDisplayDrmInterface::Callback(
int display, int64_t timestamp)
{
// 。。。
// 我们只看我们关注的部分
exynosDevice->onVsync(mExynosDisplay->mDisplayId, timestamp);
}

5.16 ExynosDevice::onVsync
这里的mCallbackInfos里面是SurfaceFlinger通过binder注册的callback,所以这里会回调回SurfaceFlinger

void ExynosDevice::onVsync(uint32_t displayId, int64_t timestamp) {
    Mutex::Autolock lock(mDeviceCallbackMutex);

    if (!isCallbackRegisteredLocked(HWC2_CALLBACK_VSYNC)) return;

    hwc2_callback_data_t callbackData = mCallbackInfos[HWC2_CALLBACK_VSYNC].callbackData;
    // 这里的callback实际是5.7.1 在SurfaceFlinger通过binder注册的
    // 最终会回调回SurfaceFlinger,SurfaceFlinger的回调详见5.17
    HWC2_PFN_VSYNC callbackFunc =
            reinterpret_cast<HWC2_PFN_VSYNC>(mCallbackInfos[HWC2_CALLBACK_VSYNC].funcPointer);
    callbackFunc(callbackData, displayId, timestamp);
}

5.17 SurfaceFlinger::onComposerHalVsync
前面说过,注册的Callback就是SurfaceFlinger自身,硬件VSync会回调到这里,这里会调用mScheduler->addResyncSample去将硬件VSync样本加入模型。

void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
                                        std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
    ATRACE_NAME(vsyncPeriod
                        ? ftl::Concat(__func__, ' ', hwcDisplayId, ' ', *vsyncPeriod, "ns").c_str()
                        : ftl::Concat(__func__, ' ', hwcDisplayId).c_str());

    Mutex::Autolock lock(mStateLock);
    if (const auto displayIdOpt = getHwComposer().onVsync(hwcDisplayId, timestamp)) {
        // 这里会将硬件样本加入到模型中
        if (mScheduler->addResyncSample(*displayIdOpt, timestamp, vsyncPeriod)) {
            // period flushed
            mScheduler->modulateVsync(displayIdOpt, &VsyncModulator::onRefreshRateChangeCompleted);
        }
    }
}

5.18 VsyncSchedule::addResyncSample
Scheduler->addResyncSample会调用到VsyncSchedule::addResyncSample
这里会将硬件样本点加入模型,如果样本点足够,就会通知HWC禁用硬件VSync,否则就会重新走一轮请求硬件VSync的流程。
mController->addHwVsyncTimestamp逻辑比较简单,有了前面的基础想必大家猜都可以猜到里面做了什么,感兴趣的话就自己去看一下源码吧,这里就不介绍了。

bool VsyncSchedule::addResyncSample(ISchedulerCallback& callback, TimePoint timestamp,
                                    ftl::Optional<Period> hwcVsyncPeriod) {
    bool needsHwVsync = false;
    bool periodFlushed = false;
    {
        std::lock_guard<std::mutex> lock(mHwVsyncLock);
        // 会将硬件VSync样本添加到模型中,然后会根据当前样本个数是否足够返回是否需要更多样本。
        if (mHwVsyncState == HwVsyncState::Enabled) {
            needsHwVsync = mController->addHwVsyncTimestamp(timestamp.ns(),
                                                            hwcVsyncPeriod.transform(&Period::ns),
                                                            &periodFlushed);
        }
    }
    // 如果还需要,调用enableHardwareVsync请求下一个硬件VSync,5.5节介绍过了这个方法,相当于再重新走请求硬件VSync流程。
    if (needsHwVsync) {
        enableHardwareVsync(callback);
    } else {
        disableHardwareVsync(callback, false /* disallow */);
    }
    return periodFlushed;
}

总结

我们这节详细的讲述来三件事:

  1. app请求VSync信号并且获得回调的流程
  2. SurfaceFlinger获取VSync信号,并且获得回调的流程
  3. 软件模拟的VSync是怎么校准的,如果请求硬件VSync并且得到回调。

相信看完这篇文章大家对VSync有了比较深刻的了解,后面我们就要开始介绍SurfaceFlinger合成相关的逻辑了。

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值