理解VSync-5-应用申请与接收VSync(中)

279 阅读16分钟

1. 前言

忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。

                        -- 服装学院的IT男

本篇为 VSync 系列的第五篇,上一篇已经对EventThread::threadMain有了个大概的印象,本篇来看看应用请求VSync后是如何接收到VSync的流程。

本系列为之前学习 SurfaceFlinger 整理的一些笔记,现在分享出来,希望能帮助到有需要的同学。 代码基于 Android 13 ,虽然最新源码源码中部分逻辑已经了,但总体思路还是没有变的,不影响对 VSync 整体逻辑的理解。

VSync 系列目录:

理解VSync-1-软件VSync及节拍器

理解VSync-2-app,appsf sf注册回调

理解VSync 3-应用添加链接

理解VSync-4-应用申请与接收VSync(上)

理解VSync-5-应用申请与接收VSync(中)

理解VSync-6-应用申请与接收VSync(下)

正文

应用请求VSYNC-app都会执行到EventThread::requestNextVsync方法,现在是应用首次请求所以现在的请求类型肯定是VSyncRequest::None

# EventThread.cpp

    void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
        ......
        // 1. 现在是VSyncRequest::None
        if (connection->vsyncRequest == VSyncRequest::None) {
            // 2. 设置为 Single
            connection->vsyncRequest = VSyncRequest::Single;
            // 3. 并唤醒等待的线程
            mCondition.notify_all();
        } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {
            connection->vsyncRequest = VSyncRequest::Single;
        }
    }

此时,EventThread 中的等待线程被唤醒,EventThread::threadMain 开始执行。

1. 第一次执行 EventThread::threadMain

# EventThread.cpp

    void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
        // 定义一个要消费 Vsync 事件的集合
        DisplayEventConsumers consumers;

        // 只要状态不是退出,则一直循环执行(没任务的时候内部会等待)
        while (mState != State::Quit) {
            std::optional<DisplayEventReceiver::Event> event;
            
            // mPendingEvents 为空不执行
            if (!mPendingEvents.empty()) {
                ......
            }
            // 是否有应用请求了 vsync
            bool vsyncRequested = false;

            // 遍历mDisplayEventConnections的各个链接
            // Find connections that should consume this event.
            auto it = mDisplayEventConnections.begin();
            while (it != mDisplayEventConnections.end()) {
                if (const auto connection = it->promote()) {
                    // 只要应用链接的集合里有一个应用申请了, syncRequested 就为true
                    // * 1. 所以当前请求类型已经是 Single 了,所以 vsyncRequested被设置为true
                    vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
                    // 当前没有event,下面不执行
                    if (event && shouldConsumeEvent(*event, connection)) {
                        // 消耗则添加到 consumers 集合
                        consumers.push_back(connection); 
                    }

                    ++it;
                } else {
                    it = mDisplayEventConnections.erase(it);
                }
            }
            // 现在 consumers 还是空
            if (!consumers.empty()) {
                ......
            }

            {
                // 定义当前线程的下一个状态
                State nextState;
                // mVSyncState 不为null,vsyncRequested 现在是true
                if (mVSyncState && vsyncRequested) {
                    // * 2. 有应用申请的话则 nextState = State::VSync
                    nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
                } else {
                    ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
                    nextState = State::Idle;
                }
                
                // 第一次执行的时候,mState = Idle ,nextState = VSync 所以不相等
                if (mState != nextState) {
                    if (mState == State::VSync) {
                        mVSyncSource->setVSyncEnabled(false);
                    } else if (nextState == State::VSync) {
                        // * 3. 当前条件走这,打开 Vsync-app
                        mVSyncSource->setVSyncEnabled(true);
                    }
                    // 状态同步,设置为State::VSync
                    mState = nextState;
                }
                // 目前没有event
                if (event) {
                    continue;
                }

                if (mState == State::Idle) {
                    mCondition.wait(lock);
                } else {
                    // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
                    // display is off, keep feeding clients at 60 Hz.
                    // 根据当前状态设置超时时间:若为合成VSYNC状态则设置较短超时(16毫秒),其他情况设置为1000毫秒

                    // * 4. 当前逻辑在这.开始超时等待
                    const std::chrono::nanoseconds timeout =
                            mState == State::SyntheticVSync ? 16ms : 1000ms;
                    if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                        ......// 超时处理,暂时忽略
                        
                    }
                    ......// 超时处理,暂时忽略
                }
            }
        }
    }

对于这次执行的逻辑代码里有一些针对性的注释,然后关键点有4个,再解释一下:

    1. EventThread::requestNextVsync 中,已将对应连接的 vsyncRequest 设置为 VSyncRequest::Single,因此 vsyncRequested 为 true,表示有应用请求了 VSync。
    1. 由于 vsyncRequested 为 true,nextState 被设置为 State::VSync
    1. 这里是关键,由于 mStatenextState不相等,并且 nextState = State::VSync ,这个时候表示当前线程本来是闲置状态,则VSYNC-app也处于关闭状态,现在有应用请求了VSYNC-app所以要开启VSYNC-app的发送。 曾将VsyncDispatch比作VSync的信号泵,它本处于关闭状态,现在需要他工作了,所以需要“插电,打开开关”
    1. 由于第 3 步的执行,现在需要进入超时等待,正常情况不会触发后续的超时处理,因为在下一个VSYNC-app来临的时候就会被再次唤醒

上述 4 点是首次执行的关键,第 3 步尤为重要,是后续VSync请求处理的逻辑基础,否则难以理解第 4 步的超时等待机制。

接下来,深入分析 DispSyncSource::setVSyncEnabled 的具体实现。

2. DispSyncSource::setVSyncEnabled 启动/关闭 VSYNC-app

软件VSync 是按需的所以也有不需要的时候,DispSyncSource::setVSyncEnabled就是控制VSYNC-app是启动还是关闭的方法。

# DispSyncSource.cpp

    void DispSyncSource::setVSyncEnabled(bool enable) {
        std::lock_guard lock(mVsyncMutex);
        if (enable) {
            // 启动流转
            mCallbackRepeater->start(mWorkDuration, mReadyDuration);
        } else {
            mCallbackRepeater->stop();
        }
        mEnabled = enable;
    }

DispSyncSource持有一个CallbackRepeater对象有startstop2个控制VSYNC-app是否轮转的方法,同时还有一个CallbackRepeater::callback用于接收VSYNC-app计时结束回调的方法。

2.1 VSYNC-app 开始轮转

    void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
        std::lock_guard lock(mMutex);
        // 表示处于工作状态
        mStarted = true;
        // 2个时间的赋值
        mWorkDuration = workDuration;
        mReadyDuration = readyDuration;
        // 开始定时任务
        auto const scheduleResult =
                mRegistration.schedule({.workDuration = mWorkDuration.count(),
                                        .readyDuration = mReadyDuration.count(),
                                        .earliestVsync = mLastCallTime.count()});
        LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback");
    }

mStarted 这个变量代表当前 VSYNC-app 的申请产生是否处于工作状态。

这里调用了VSyncCallbackRegistration::schedule方法,参数是根据几个时间构造了1个ScheduleTiming对象。这些时间将参与计算下一次定时多久, 也就是计算出下一个VSYNC-app是什么时候。

# VSyncDispatchTimerQueue.cpp

    ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
        if (!mValidToken) {
            return std::nullopt;
        }
        // mToken 代表是 app appsf sf 的哪一个
        return mDispatch.get().schedule(mToken, scheduleTiming);
    }

    ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
                                                 ScheduleTiming scheduleTiming) {
    ScheduleResult result;
    {
        std::lock_guard lock(mMutex);
        // 根据token确认是谁请求的 3个: app appsf sf 
        auto it = mCallbacks.find(token);
        if (it == mCallbacks.end()) {
            return result;
        }
        // 拿到对应的 VSyncDispatchTimerQueueEntry
        auto& callback = it->second;
        // 获取当前时间
        auto const now = mTimeKeeper->now();
        ......
        // 执行3个参数的 schedule 方法
        // 重点* 1. 计算出下一个 wakeupTime  
        result = callback->schedule(scheduleTiming, mTracker, now);
        if (!result.has_value()) {
            return result;
        }
        // 重点* 2. 如果符合条件,就开始触发定时
        if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
            rearmTimerSkippingUpdateFor(now, it);
        }
    }

    return result;
}
    1. 这里一共执行了 3 个schedule方法需要注意区分,重点1出,这里现在以黑盒形式了解。ScheduleTiming这个类下面是3个关键时间, VSyncDispatchTimerQueueEntry::schedule方法就是根据这3个时间,计算出下一次软件层的VSYNC-app是什么时候,这个时间就保存在VSyncDispatchTimerQueueEntrymArmedInfo中。
    1. 在重点2处,因为重点 1 的执行,mArmedInfo下已保存了下次唤醒时间,callback->wakeupTime()其实就是从mArmedInfo下获取时间的。

VSyncDispatchTimerQueueEntry::wakeupTime方法 。

# VSyncDispatchTimerQueue.cpp

std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
    if (!mArmedInfo) {
        return {};
    }
    // 返回下次唤醒时间
    return {mArmedInfo->mActualWakeupTime};
}

然后拿mActualWakeupTimemIntendedWakeupTime比较。这个mIntendedWakeupTime表示定下次被唤醒的时间,这里可能会有个困扰:wakeupTime 是唤醒时间,mIntendedWakeupTime又是唤醒时间,这是啥意思。

2.2 wakeupTime 和 mIntendedWakeupTime

  • mIntendedWakeupTime 是 VSyncDispatchTimerQueue 下的成员变量,节拍器是靠定时器完成SW-VSYNC的产生的,所以这个mIntendedWakeupTime代表是下一次计时器结束的时间。mIntendedWakeupTime的赋值是在启动定时器的时候,当定时到了之后又会被赋值为无穷大。

  • wakeupTime(mArmedInfo->mActualWakeupTime)这个是属于VSyncDispatchTimerQueueEntry下的变量。代表的是这个 VSyncDispatchTimerQueueEntry 下次唤醒的时间,根据目前的信息,一共是有3个 :app appsf sf 。

目前是以一个应用请求VSYNC-app的场景分析的,那假设appsfsf都没有申请,那mIntendedWakeupTime就等于wakeupTime。但是正常手机上,app``sf 都是在请求SW-VSYNC,那这个时候 mIntendedWakeupTime到底是等于哪个VSyncDispatchTimerQueueEntry的 wakeupTime就要看是谁设置的定时任务了。

谁先设置了定时任务就会把谁的wakeupTime设置给mIntendedWakeupTime。后申请SW-VSYNCVSyncDispatchTimerQueueEntry会因为定时器已经触发了,而不会再触发定时任务了,也就不会把wakeupTime设置给mIntendedWakeupTime了,这个时候的mIntendedWakeupTime就是上一个申请SW-VSYNCVSyncDispatchTimerQueueEntrywakeupTime

正常来说应用先绘制才会有SurfaceFlinger合成的需求,所以app是先与sf申请的,所以当sf请求VSYNC-sf的时候想触发定时任务,这个时候会发生定时任务已经执行了(app触发的)。

要区分wakeupTimemIntendedWakeupTime的区别要从各自所属的对象,以及赋值的时间。

3. 定时 rearmTimerSkippingUpdateFor

继续回到主流程,第一次执行mIntendedWakeupTime还没被赋值,所以是无穷大,所以wakeupTime < mIntendedWakeupTime满足条件执行rearmTimerSkippingUpdateFor方法来触发定时。

# VSyncDispatchTimerQueue.cpp

    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;
        // 遍历 3个 app appsf sf 要不要定时
        for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
            // 拿到对应的 entry
            auto& callback = it->second;
            
            // 如果有 wakeupTime 才会继续,否则当前的这个回调就不管了
            if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
                continue;
            }

            if (it != skipUpdateIt) {
                callback->update(mTracker, now);
            }
            // 拿到对应的 wakeupTime 时间
            auto const wakeupTime = *callback->wakeupTime();
            // 取3个里最小的 wakeupTime 赋值给 min
            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());
            }
            // * 设置定时任务
            setTimer(*min, now);
        } else {
            ATRACE_NAME("cancel timer");
            // 取消定时
            cancelTimer();
        }
    }

min && min < mIntendedWakeupTime满足才会走setTimer开始设置定时任务,第一次执行且只有app请求的话,这个min就是2.1计算出的下一次VSYNC-app的时间,mIntendedWakeupTime是无穷大,所以满足条件走setTimer

# VSyncDispatchTimerQueue.cpp

void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
    // 设置时间,赋值后就不是无穷大了
    mIntendedWakeupTime = targetTime;
    // 触发定时任务
    // 时间到了就执行 VSyncDispatchTimerQueue::timerCallback
    mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
                         mIntendedWakeupTime);
    mLastTimerSchedule = mTimeKeeper->now();
}

这个方法就是软件层 VSync 产生的关键了:

    1. mIntendedWakeupTime 在这里被赋值,值就是下一次定时时间,是app appsf sf 中最近一次的 WakeupTime
    1. 开启定时任务,定时的时间为 mIntendedWakeupTime ,所以说 mIntendedWakeupTime 就是下一次的定时结束时间
    1. 定时接触后触发 VSyncDispatchTimerQueue::timerCallback ,由这个回调开始触发 SW-VSYNC 的产生

这部分的逻辑如下:(cancelTimer部分暂时可以不看)

rearmTimerSkippingUpdateFor逻辑图.png

4. 定时结束回调处理 VSyncDispatchTimerQueue::timerCallback

定时时间到后,会执行VSyncDispatchTimerQueue::timerCallback

# VSyncDispatchTimerQueue.cpp

// 定时到了,回调执行当前 (定时到了走会走到这,但是内部会区分 app appsf sf,有各自的处理)
void VSyncDispatchTimerQueue::timerCallback() {
    ATRACE_CALL();
    // 定义结构体
    struct Invocation {
        std::shared_ptr<VSyncDispatchTimerQueueEntry> callback; // 注意这个变量(app appsf sf对应的回调Entry)
        nsecs_t vsyncTimestamp;
        nsecs_t wakeupTimestamp;
        nsecs_t deadlineTimestamp;
    };
    // 处理 SW-VSYNC 的Entry集合
    std::vector<Invocation> invocations;
    ......
    {
        std::lock_guard lock(mMutex);
        auto const now = mTimeKeeper->now();
        mLastTimerCallback = now;
        // 遍历 callback (app appsf sf)
        for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
            // 拿到Entry
            auto& callback = it->second;
            // 拿到其wakeupTime
            auto const wakeupTime = callback->wakeupTime();
            // 1. 没有对应的定时时间,说明不关心 VSync ,则不需要处理
            if (!wakeupTime) {
                continue;
            }

            auto const readyTime = callback->readyTime();
            // 这个值肯定大于 0 
            auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
            // wakeupTime = mIntendedWakeupTime    所以后面加了一点时间,就符合if
            // 这里我认为是因为代码执行需要时间,所以需要加上一个容错值
            if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
                // 2. 执行 里面会调用 mArmedInfo.reset 也就是设置为 null
                callback->executing();
                // 3. 把要执行回调的放到 invocations 下
                invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
                                                    *wakeupTime, *readyTime});
            }
            ......
        }
        // 4. 设置为无穷大
        mIntendedWakeupTime = kInvalidTime;
        // 5. 再启动定时,但是因为 executing 的时候会把 mArmedInfo 时间被置空,所以会 continue
        rearmTimer(mTimeKeeper->now());
        .....
    }

    for (auto const& invocation : invocations) {
        // 6. 执行回调 (VSyncDispatchTimerQueueEntry::callback)
        invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
                                      invocation.deadlineTimestamp);
        ......
    }
}
    1. 对应的 VSyncDispatchTimerQueueEntry 如果没有申请 VSync 则 wakeupTime 为 null 也就不需要执行后续逻辑
    1. 这次定时到了,VSyncDispatchTimerQueueEntry 对应的定时结构体 mArmedInfo 相关的时间就无效了,所以将其重置(为null)
    1. 构建出一个 Invocation 对象放到集合 invocations 中,VSyncDispatchTimerQueueEntry 现在被叫做 callback 也保存在这个结构体中
    1. mIntendedWakeupTime 被设置成无穷大,因为这次定时结束了,mIntendedWakeupTime 这个时候也没有了意义,所以被设置为无穷大
    1. 再次启动定时,如果说 app sf 都请求了 SW-VSYNC ,但是各自的 wakeupTime 不一样,那这个时候只有满足条件的才能执行 2,3 两步,然后产生对应的 VSync,而不满足条件的则说明当前定时结束的视觉不是他的 SW-VSYNC 时间,所以需要继续定时。
    1. 这里就是把触发这个 wakeupTime 是当前时间的回调了。以当前分析的场景来说,就是应用的第一次 VSYNC-app 要产生了。

定时结束逻辑.png

4.1 第一次 VSYNC-app 产生

VSyncDispatchTimerQueueEntry 定义在 VSyncDispatchTimerQueue.cpp 下

# VSyncDispatchTimerQueue.cpp

    void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
                                                nsecs_t deadlineTimestamp) {
        {
            std::lock_guard<std::mutex> lk(mRunningMutex);
            mRunning = true;
        }
        // 实际上调的是 mCallback ,构建时赋值
        mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);

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

这块回调的执行,在理解VSync-2-app,appsf sf注册回调已经介绍过了:

app回调执行逻辑.png

4.1.1 继续申请 VSYNC-app

根据之前的分析,回调会执行到CallbackRepeater::callback中,这个方法很重要,处理继续回调VSYNC-app外,还会触发下一次VSYNC-app的申请。

# DispSyncSource.cpp 

class CallbackRepeater {
    ......
private:
    void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
        ......
        // 重点* 1. 间接执行 DispSyncSource::onVsyncCallback
        mCallback(vsyncTime, wakeupTime, readyTime);

        {
            std::lock_guard lock(mMutex);
            // 如果处于关闭状态则返回
            if (!mStarted) {
                ATRACE_NAME("callback return not  mRegistration.schedule");
                return;
            }
            // 重点* 2. 请求 VSync
            auto const scheduleResult =
                    mRegistration.schedule({.workDuration = mWorkDuration.count(),
                                            .readyDuration = mReadyDuration.count(),
                                            .earliestVsync = vsyncTime});
        }
    }
}

执行 CallbackRepeater::callback 的时候会做2件事:

    1. 执行 mCallback 然后会触发 DispSyncSource::onVsyncCallback 的执行
    1. 如果 DispSyncSource 还处于打开状态的话,则触发申请下一次的 VSync 的申请

mStarted现在是true,所以还会继续申请VSync

4.1.2 产生 VSYNC-app

然后一路回调,会调用到DispSyncSource::onVsyncCallback方法。

# DispSyncSource.cpp

void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
                                     nsecs_t readyTime) {

    VSyncSource::Callback* callback;
    {
        std::lock_guard lock(mCallbackMutex);
        callback = mCallback;
    }
    
    // Vsync-app  trace的控制
    if (mTraceVsync) {
        mValue = (mValue + 1) % 2;
    }

    if (callback != nullptr) {
        // 传递到EventThread
        callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
    }
}

根据之前的分析,执行的就是EventThread::onVSyncEvent

# EventThread.cpp
void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {
    std::lock_guard<std::mutex> lock(mMutex);

    LOG_FATAL_IF(!mVSyncState);
    // 1. 构建一个event添加到mPendingEvents
    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
                                       vsyncData.expectedPresentationTime,
                                       vsyncData.deadlineTimestamp));
    // 2. 环境线程
    mCondition.notify_all();
}

这里就往mPendingEvents里添加了一个Event,然后又唤醒了线程。

之前分析到 EventThread::threadMain 方法最后是发现进入了超时等待,也就是“第4步”,现在就和它对应上来了。

5. 第二次执行 EventThread::threadMain

线程又被唤醒了,所以又要看EventThread::threadMain方法了。

# EventThread.cpp

    void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
        // 定义一个要消费 Vsync 事件的集合
        DisplayEventConsumers consumers;

        // 只要状态不是退出,则一直循环执行(没任务的时候内部会等待)
        while (mState != State::Quit) {
            std::optional<DisplayEventReceiver::Event> event;
            
            // Determine next event to dispatch.
           
            // 现在里面有值了
            if (!mPendingEvents.empty()) {
                // 取第一个值给event
                event = mPendingEvents.front();
                // 移除
                mPendingEvents.pop_front();
                // 这部分可忽略,正常情况不影响主流程
                switch (event->header.type) {
                    ......
                }
            }
            // 是否有应用请求了 vsync
            bool vsyncRequested = false;

            // 2. 开始遍历mDisplayEventConnections的各个链接
            // Find connections that should consume this event.
            auto it = mDisplayEventConnections.begin();
            while (it != mDisplayEventConnections.end()) {
                if (const auto connection = it->promote()) {
                    // 只要应用链接的集合里有一个应用申请了, syncRequested 就为true
                    vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
                    // 是否要消耗event (见2.6.1 )
                    if (event && shouldConsumeEvent(*event, connection)) {
                        // 添加到 consumers 集合
                        consumers.push_back(connection); 
                    }

                    ++it;
                } else {
                    it = mDisplayEventConnections.erase(it);
                }
            }
            
            if (!consumers.empty()) {
                // 3. 派发到应用端(见2.6.2)
                dispatchEvent(*event, consumers);
                // 置空
                consumers.clear();
            }

            {
                // 4. 状态处理
                // 定义当前线程的下一个状态
                State nextState;
                if (mVSyncState && vsyncRequested) {
                    // 还是设置为 nextState = State::VSync
                    nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
                } else {
                    ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
                    nextState = State::Idle;
                }
    
                // mState 本来就是State::VSync,所以不执行内部逻辑
                if (mState != nextState) {
                    ......
                }
    
                if (event) {
                    // 有事件则重头开始执行
                    continue;
                }
                // 这次在上面 continue 了,就不会走进后面的等待逻辑了。
                // Wait for event or client registration/request.
                if (mState == State::Idle) {
                    // 当状态为Idle时,无期限等待
                    mCondition.wait(lock);
                } else {
                    // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
                    // display is off, keep feeding clients at 60 Hz.
                    // 根据当前状态设置超时时间:若为合成VSYNC状态则设置较短超时(16毫秒),其他情况设置为1000毫秒
                    const std::chrono::nanoseconds timeout =
                            mState == State::SyntheticVSync ? 16ms : 1000ms;
                    if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                        ......// 超时处理,暂时忽略
                        
                    }
                    ......// 超时处理,暂时忽略
                }
            }
        }
    }

这一次执行的逻辑和前一次就有很大的区别了。

5.1 EventThread::shouldConsumeEvent

# EventThread.cpp

bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
                                     const sp<EventThreadConnection>& connection) const {
    
    ......
    switch (event.header.type) {
        ......

        case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
            switch (connection->vsyncRequest) {
                case VSyncRequest::None:
                    return false;
                case VSyncRequest::SingleSuppressCallback:
                    // SingleSuppressCallback --> None
                    connection->vsyncRequest = VSyncRequest::None;
                    return false;
                case VSyncRequest::Single: {
                    if (throttleVsync()) {
                        return false;
                    }
                    // Single -- > SingleSuppressCallback
                    connection->vsyncRequest = VSyncRequest::SingleSuppressCallback;
                    return true;
                }
                case VSyncRequest::Periodic:
                    if (throttleVsync()) {
                        return false;
                    }
                    return true;
                default:
                    // We don't throttle vsync if the app set a vsync request rate
                    // since there is no easy way to do that and this is a very
                    // rare case
                    return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
            }

        ......
        default:
            return false;
    }
}

就是对应用链接的 vsyncRequest 做判断,代码看着多但是逻辑很简单

shouldConsumeEvent处理转存失败,建议直接上传图片文件

如果应用请求了VSYNC-app那就会返回true,同时设置一下connection->vsyncRequest请求状态的值

5.2 派发 VSync 到应用端

# EventThread.cpp

void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                const DisplayEventConsumers& consumers) {
    // 遍历消费集合(哪些应用申请了VSync)
    for (const auto& consumer : consumers) {
        // 拷贝event 
        DisplayEventReceiver::Event copy = event;
        ......
        // 发送事件
        switch (consumer->postEvent(copy)) {
            ......
        }
    }
}

这里的逻辑很简单,就是发送一个VSYNC的事件,看看后续处理

# EventThread.cpp

status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
    constexpr auto toStatus = [](ssize_t size) {
        return size < 0 ? status_t(size) : status_t(NO_ERROR);
    };

    ATRACE_CALL();
    ......
    // 通过socket 同信的方式发送到应用到
    auto size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
    return toStatus(size);
}

到这里,应用端的Choreographer$FrameDisplayEventReceiver::onVsync就会执行一次回调了,也就是一次VSync来了,应用可以绘制UI了。

感觉逻辑到这似乎结束了,毕竟应用都收到

但是还有2个点

    1. 这一次分析 EventThread::threadMain 方法的时候最终是执行了 “continue” 说明还要再执行一次 EventThread::threadMain 方法
    1. 4.1.1 小节说了这次 VSYNS-app 产生的时候又触发申请了下一次的

5.3 continue 再次执行 while

由于执行了 continue ,所以又回到了 EventThread::threadMain 方法的下一次 while 语句。

# EventThread.cpp

    void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
        // 定义一个要消费 Vsync 事件的应用集合
        DisplayEventConsumers consumers;

        // 只要状态不是退出,则一直循环执行(没任务的时候内部会等待)
        while (mState != State::Quit) {
            // 定义 event
            std::optional<DisplayEventReceiver::Event> event;

            // mPendingEvents 的唯一事件上一次执行的时候被移除了,现在是空
            if (!mPendingEvents.empty()) {
                ......
            }
            // 是否有应用请求了 vsync
            bool vsyncRequested = false;

            // Find connections that should consume this event.
            auto it = mDisplayEventConnections.begin();
            while (it != mDisplayEventConnections.end()) {
                if (const auto connection = it->promote()) {
                    // 当前应用为 SingleSuppressCallback 了,所以 vsyncRequest 还是true
                    vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
                    // 当前没有event,下面不执行
                    if (event && shouldConsumeEvent(*event, connection)) {
                        ...... 
                    }

                    ++it;
                } else {
                    it = mDisplayEventConnections.erase(it);
                }
            }
            
            // 为空
            if (!consumers.empty()) {
                ......
            }

            {
                // vsyncRequested = true 
                State nextState;
                if (mVSyncState && vsyncRequested) {
                    // 设置 nextState = State::VSync
                    nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
                } else {
                    ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
                    nextState = State::Idle;
                }
    
                // 相同都为 State::VSync
                if (mState != nextState) {
                    ......
                }
    
                // 目前没有event
                if (event) {
                    continue;
                }

                // Wait for event or client registration/request.
                if (mState == State::Idle) {
                    // 当状态为Idle时,无期限等待
                    mCondition.wait(lock);
                } else {
                    // 根据当前状态设置超时时间:若为合成VSYNC状态则设置较短超时(16毫秒),其他情况设置为1000毫秒
                    const std::chrono::nanoseconds timeout =
                            mState == State::SyntheticVSync ? 16ms : 1000ms;
                    //再次进入等待
                    if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                        ......// 超时处理,暂时忽略
                        
                    }
                    ......// 超时处理,暂时忽略
                }
            }
        }
    }

这一次啥也没干,陷入了等待,等啥呢? 之前说VSyncRequest的几个枚举值的时候说了VSyncRequest::Single会触发2次VSync,现在只看到了一次,第二次呢?

第二次就是 4.1.1 触发的再一次申请VSYNC-app,篇幅原因,下一篇看第二次VSync的流程。

参考

blog.csdn.net/tkwxty/arti…

www.jianshu.com/p/5e9c558d1…

mp.weixin.qq.com/s/gAcBEqjYA…

source.android.com/docs/core/g…