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

1. 前言

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

-- 服装学院的IT男

本篇为 VSync 系列的第二篇,主要介绍"app appsf sf"是如何注册回调到 VSyncDispatchTimerQueue 下的 mCallbacks 中的。

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

VSync 系列目录:

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

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

正文

在分析之前,我们需要先了解 SurfaceFlinger::initScheduler 方法。

scss 复制代码
# SurfaceFlinger.cpp

    void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {
        // 避免重复初始化
        if (mScheduler) {
            mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
            return;
        }
        // 是一个Fps对象,其中存储了刷新率fps和刷新周期period
        const auto currRefreshRate = display->getActiveMode()->getFps();
        mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
                                                                        hal::PowerMode::OFF);
        // 封装了不同刷新率下的VSync配置信息
        mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate);
        mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs());

        ......
        // 重点* 1.1 创建 Scheduler
        mScheduler = std::make_unique<scheduler::Scheduler>(static_cast<ICompositor&>(*this),
                                                            static_cast<ISchedulerCallback&>(*this),
                                                            features);
        {
            auto configs = display->holdRefreshRateConfigs();
            if (configs->kernelIdleTimerController().has_value()) {
                features |= Feature::kKernelIdleTimer;
            }
            // 重点* 1.2 初始化 VsyncSchedule
            mScheduler->createVsyncSchedule(features);
            mScheduler->setRefreshRateConfigs(std::move(configs));
        }
        setVsyncEnabled(false);
        mScheduler->startTimers();
        // 当前设备下,SurfaceFlinger 相关的配置
        const auto configs = mVsyncConfiguration->getCurrentConfigs();
        const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
        // 重点* 2.1 app 注册回调
        mAppConnectionHandle =
                mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
                                            /*workDuration=*/configs.late.appWorkDuration,
                                            /*readyDuration=*/configs.late.sfWorkDuration,
                                            impl::EventThread::InterceptVSyncsCallback());
        // 重点* 2.2 appSf 注册回调
        mSfConnectionHandle =
                mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),
                                            /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
                                            /*readyDuration=*/configs.late.sfWorkDuration,
                                            [this](nsecs_t timestamp) {
                                                mInterceptor->saveVSyncEvent(timestamp);
                                            });
        // 重点* 2.3 sf 注册回调
        mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
                            configs.late.sfWorkDuration);
        ......
    }

本篇需要关注"2.1 2.2 2.3"这三个流程,其中 appsf 和 app 的注册回调的调用是一样的,以 app 为例分析即可。

本篇目的:

    1. app 和 appsf 是如何注册到 mCallbacks
    1. 各自传递的 VSync 回调是什么。

本篇分析的代码中会出现多个回调,很容易就绕晕了,建议心里就牢记着两个回调:分别是定时结束后如何回调给应用和 SurfaceFlinger 的。

1 app appsf 向 VsyncDispatch 注册回调

rust 复制代码
# Scheduler.cpp

    // connectionName 为对应的名字,这里就是 "app" 或 "appSf"
    ConnectionHandle Scheduler::createConnection(
            const char* connectionName, frametimeline::TokenManager* tokenManager,
            std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
            impl::EventThread::InterceptVSyncsCallback interceptCallback) {
        // 1. 构建出 DispSyncSource 对象
        auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
        auto throttleVsync = makeThrottleVsyncCallback();
        auto getVsyncPeriod = makeGetVsyncPeriodFunction();

        // 2. 创建出对应的线程 "app" 和 "appsf"
        auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
                                                            std::move(interceptCallback),
                                                            std::move(throttleVsync),
                                                            std::move(getVsyncPeriod));
        // 3.构建一个Connection保存并返回
        return createConnection(std::move(eventThread));
    }
    

这里有三个步骤:

    1. 创建 DispSyncSource
    1. 创建 EventThread
    1. 构建 Connection 保存并返回

比较重要的是 DispSyncSource 和 EventThread 的创建,一个是 app 的 VSync 信号源,1个是处理 VSYNC-app 与具体应用工作的。

1.1 DispSyncSource 的创建

rust 复制代码
# Scheduler.cpp

    std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
            const char* name, std::chrono::nanoseconds workDuration,
            std::chrono::nanoseconds readyDuration, bool traceVsync) {
        // 创建 DispSyncSource
        return std::make_unique<scheduler::DispSyncSource>(mVsyncSchedule->getDispatch(),
                                                        mVsyncSchedule->getTracker(), workDuration,
                                                        readyDuration, traceVsync, name);
    }
    1. 实际返回的是 DispSyncSource,说明其是 VSyncSource 的子类
    1. 传递了 VsyncDispatch 和 VsyncTracker,说明这个类也会处理 VSync 相关逻辑
    1. 传递了 name,这个对象不是单例,而且只有 "app"和"appsf",说明这个类服务于应用相关的 VSync

注意这里还传递了 workDuration 和 readyDuration 两个关键的时间进去,先看一下 DispSyncSource 的头文件。

对 DispSyncSource 有了个大概的了解后看看其构造:

less 复制代码
# DispSyncSource.cpp

    DispSyncSource::DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
                                std::chrono::nanoseconds workDuration,
                                std::chrono::nanoseconds readyDuration, bool traceVsync,
                                const char* name)
        : mName(name), // 当前DispSyncSource的名字
            mValue(base::StringPrintf("VSYNC-%s", name), 0), // trace 的值
            mTraceVsync(traceVsync),
            mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
            mVSyncTracker(vSyncTracker),
            mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
            mReadyDuration(readyDuration) {
        
        // 构建CallbackRepeater 
        mCallbackRepeater =
                std::make_unique<CallbackRepeater>(vSyncDispatch,
                                                std::bind(&DispSyncSource::onVsyncCallback, this,
                                                            std::placeholders::_1,
                                                            std::placeholders::_2,
                                                            std::placeholders::_3),
                                                name, workDuration, readyDuration,
                                                std::chrono::steady_clock::now().time_since_epoch());
}
    1. 这里看到 trace 的名字是 ("VSYNC-%s", name),和 VSYNC-app,VSYNC-appsf 对上了
    1. 对 mName,VSyncTracker 以及 workDuration,readyDuration 等变量做初始化赋值
    1. 初始化 mCallbackRepeater (构建 CallbackRepeater )

其他的几个成员变量都是传参过来的,mCallbackRepeater 则是需要构建,注意这里传递过去的回调是 DispSyncSource::onVsyncCallback ,还有其他参数也很重要。

1.1.1 回调:DispSyncSource::onVsyncCallback

本篇分析的就是这些回调的关系,所以代码中出现的回调肯定是要重点看看的。

arduino 复制代码
# DispSyncSource.cpp


// 重点* 1. 设置mCallback值
void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
    std::lock_guard lock(mCallbackMutex);
    mCallback = callback;
}

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

    VSyncSource::Callback* callback;
    {
        std::lock_guard lock(mCallbackMutex);
        // mCallback 赋值给 callback
        callback = mCallback;
    }
    
    // 重点* 2. 控制 Trace 的值
    if (mTraceVsync) {
        mValue = (mValue + 1) % 2;
    }

    if (callback != nullptr) {
        // 重点* 3. 执行Vsync 回调
        callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
    }
}

这里有三个重点:

    1. mCallback 的类型是 VSyncSource::Callback ,在头文件定义,在 DispSyncSource::setCallback 赋值,这个方法调用的地方在后面构建 EventThread 的时候
    1. 在 Trace 上看到 VSYNC-app VSYNC-appsf 起伏的原因就在这,我们知道一次起伏代表来了一次 VSync ,所以 DispSyncSource::onVsyncCallback 的执行就说明触发了 VSync 。
    1. 这里执行的其实是 EventThread::onVSyncEvent 方法,也就是将 VSync 发送到 EventThread 中做后续处理。

可以暂且就把 EventThread 这个类当成应用接收 VSync 的类。

SurfaceFlinger 有一篇很经典的文章(www.jianshu.com/p/5e9c558d1... VsyncDispatch 与 EventThread 之间的桥梁"就是这个意思。

VsyncDispatch 可以理解为 SW-VSYNC 产生的地方,然后分别要给到应用和 SurfaceFlinger ,应用这边的类是 EventThread ,这么一看 DispSyncSource 确实是"桥梁"。

DispSyncSource 下的 mCallback 变量也很重要,上面的截图里有介绍。

1.2 CallbackRepeater 的构建

CallbackRepeater 定义在 DispSyncSource.cpp 下,说明其也是服务于 DispSyncSource 的。 看类名像是处理回调的,构建的时候也确实传递了 DispSyncSource::onVsyncCallback 。

php 复制代码
# DispSyncSource.cpp 

class CallbackRepeater {
public:
    CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
                     std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
                     std::chrono::nanoseconds notBefore)
          : mName(name),
            mCallback(cb), // DispSyncSource::onVsyncCallback
            // 构造 VSyncCallbackRegistration
            mRegistration(dispatch,
                          std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
                                    std::placeholders::_2, std::placeholders::_3),
                          mName),
            mStarted(false),
            mWorkDuration(workDuration), // workDuration
            mReadyDuration(readyDuration), // readyDuration
            mLastCallTime(notBefore) {}
}

这里又有两个回调相关的逻辑:

    1. 参数 cb 是 VSyncDispatch::Callback 类型,看到传递过来的时候是将 DispSyncSource::onVsyncCallback 和 DispSyncSource 构造出来的对象,现在将其赋值给了 mCallback
    1. 触发构建 VSyncCallbackRegistration,传递了 CallbackRepeater::callback

这边也有两个疑问:

    1. 这里的 mCallback 又是什么?
    1. 这里的 mCallback 和 CallbackRepeater::callback 又有什么联系?

1.2.1 CallbackRepeater下的mCallback是什么

这里的 mCallback 是 VSyncDispatch::Callback 类型

php 复制代码
# DispSyncSource.cpp 
class CallbackRepeater {
private:
    ......
    // mCallback 的定义
    scheduler::VSyncDispatch::Callback mCallback;
    ......
};

看看 VSyncDispatch::Callback 的定义:

vbnet 复制代码
# VSyncDispatch.h

class VSyncDispatch {
public:
     * A callback that can be registered to be awoken at a given time relative to a vsync event.
     *  VSync 时间,看传值好像是上一次的(不确定是这次还是上次)
     * \param [in] vsyncTime:        The timestamp of the vsync the callback is for.
     * 唤醒时间,定时器结束时间然后开始产生VSync
     * \param [in] targetWakeupTime: The timestamp of intended wakeup time of the cb.
     * 应用这一帧绘制完成的时间,同时也是SF开始合成的时间
     * \param [in] readyTime:        The timestamp of intended time where client needs to finish
     *                               its work by.
     */
    // 定义Callback类型别名
    using Callback =
            std::function<void(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime)>;
......
}

说明这个 Callback 是一个 VSync 来的回调函数,里面还有3个时间。 在结合上面赋值的代码,也就是说执行这个 mCallback 的时候就会执行到 DispSyncSource::onVsyncCallback 方法(3个参数也对上了)。

1.2.2 CallbackRepeater下的mCallback和CallbackRepeater::callback的联系

arduino 复制代码
# 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 的时候会做两件事:

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

这两步都很重要,一个是触发 VSync 的分发一个是触发下一次的申请(mStarted = true 的话)。

那么当前问题的答案就是:CallbackRepeater::callback 执行的时候会触发 mCallback 的执行,也就执行到了 DispSyncSource::onVsyncCallback 。

1.3 VSyncCallbackRegistration 的创建

回到主流程继续看 VSyncCallbackRegistration 的创建,VSyncCallbackRegistration 的定义在也是在 VSyncDispatch 头文件中,代码如下

arduino 复制代码
# VSyncDispatch.h
/*
 * Helper class to operate on registered callbacks. It is up to user of the class to ensure
 * that VsyncDispatch lifetime exceeds the lifetime of VSyncCallbackRegistation.
 */
class VSyncCallbackRegistration {
public:
    ......

    // See documentation for VSyncDispatch::schedule.
    ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming);

    // See documentation for VSyncDispatch::cancel.
    CancelResult cancel();

private:
    std::reference_wrapper<VSyncDispatch> mDispatch;
    VSyncDispatch::CallbackToken mToken;
    bool mValidToken;
};

根据注释,这个类是一个 VSyncDispatch 的帮助类,主要是有个 schedule 和 cancel 2个方法,分别对应应用请求和取消 VSync ,看注释调用的还是 VSyncDispatch 对应的方法。另外还有几个对象也要留意。

回到代码流程,触发 VSyncCallbackRegistration 构建的地方是在 VSyncDispatchTimerQueue.cpp 文件中,代码如下:

css 复制代码
# VSyncDispatchTimerQueue.cpp

    VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
                                                        VSyncDispatch::Callback callback,
                                                        std::string callbackName)
        : mDispatch(dispatch),
            mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),
            mValidToken(true) {}
    1. mDispatch 赋值初始化
    1. 执行 VSyncDispatchTimerQueue::registerCallback 方法

根据之前的代码调用,这里的callback就是CallbackRepeater::callback。现在又作为参数传递到 VSyncDispatchTimerQueue::registerCallback 方法中。

目前涉及到这几个类的类图关系如下:

其中 VSyncCallbackRegistration 也持有 VSyncDispatch 的对象,而 VSyncDispatch 的类图之前也画过了。

如果把他们集合起来,就有下面这样一个关系:

1.4 app,appsf 最终的注册(VSyncDispatchTimerQueue::registerCallback)

继续回到代码流程,VSyncDispatchTimerQueue 是 VSyncDispatch 子类,其实现了 registerCallback 方法。

c 复制代码
# VSyncDispatchTimerQueue.cpp

    VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
            Callback callback, std::string callbackName) {

        std::lock_guard lock(mMutex);
        return CallbackToken{
                mCallbacks
                        .emplace(++mCallbackToken,
                                std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
                                                                                std::move(callback),
                                                                                mMinVsyncDistance))
                        .first->first};
    }
    1. 构建 VSyncDispatchTimerQueueEntry 对象,三个回调(app, appsf, sf)都是其对象
    1. 添加到 mCallbacks 中,等 SW-VSYNC 来了就会遍历这个集合里的三个 VSyncDispatchTimerQueueEntry 对象把 SW-Vsync 进行细分。
    1. 这里的回调 callback 是 CallbackRepeater::callback

VSyncDispatchTimerQueueEntry 的构造方法如下:

c 复制代码
# VSyncDispatchTimerQueue.cpp

VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
                                                           VSyncDispatch::Callback callback,
                                                           nsecs_t minVsyncDistance)
      : mName(std::move(name)),
        mCallback(std::move(callback)),
        mMinVsyncDistance(minVsyncDistance) {}

# VSyncDispatchTimerQueue.h

class VSyncDispatchTimerQueueEntry {
......
private:
    const std::string mName;
    const VSyncDispatch::Callback mCallback;
}

这里看到 VSyncDispatchTimerQueueEntry 下又有一个 mCallback 是 VSyncDispatch::Callback 类型,根据传值是执行的 CallbackRepeater::callback 。

当定时结束执行 VSyncDispatchTimerQueue::timerCallback 来产生 VSync 的时候,本质上执行的就是 VSyncDispatchTimerQueueEntry::callback 方法。

arduino 复制代码
# VSyncDispatchTimerQueue.cpp

// 定时结束执行
void VSyncDispatchTimerQueue::timerCallback() {
    ....... // 遍历 mCallbacks 发送 VSync
    //本质就是执行对应的 VSyncDispatchTimerQueueEntry::callback
}

void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
                                            nsecs_t deadlineTimestamp) {
    ......
    // 实际上调的是mCallback ,构建时赋值
    mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);

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

可以看到,就是触发了这个 mCallback ,根据之前的的代码逻辑,会执行到 DispSyncSource::onVsyncCallback ,进而执行到 EventThread::onVSyncEvent 。

1.5 app appsf 线程的创建

前面的分析都是在 Scheduler::createConnection 方法中执行 Scheduler::makePrimaryDispSyncSource 的调用链,在执行完这个方法后还会执行 EventThread 的创建。 看名字是要创建一个线程了,代码逻辑如下:

scss 复制代码
# EventThread.cpp

    EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
                            android::frametimeline::TokenManager* tokenManager,
                            InterceptVSyncsCallback interceptVSyncsCallback,
                            ThrottleVsyncCallback throttleVsyncCallback,
                            GetVsyncPeriodFunction getVsyncPeriodFunction)
        : mVSyncSource(std::move(vsyncSource)), // 1. 初始化mVSyncSource
            mTokenManager(tokenManager),
            mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
            mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
            mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)),
            mThreadName(mVSyncSource->getName()) { // 2.1 线程名变量赋值

        LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr,
                "getVsyncPeriodFunction must not be null");
        // 3. 设置回调 DispSyncSource
        mVSyncSource->setCallback(this);
        // 4. 创建线程
        mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
            std::unique_lock<std::mutex> lock(mMutex);
            threadMain(lock);
        });
        // 2.2 设置线程名
        pthread_setname_np(mThread.native_handle(), mThreadName);
        ......
    }

这里有四个重点:

    1. EventThread 内也有 DispSyncSource 的对象
    1. 获取线程名并设置给当前线程,也就是"app"和"appsf"
    1. 调用 DispSyncSource::setCallback 把 EventThread::onVSyncEvent 作为回调传递到 DispSyncSource 中
    1. 创建并启动线程,内部执行 threadMain 方法,这个方法也是后面应用端申请 Vsync 的核心方法。

可以看到 EventThread 下启动了自己的线程,命名就是"app"和"appsf",这个通过shell 命令也能确认。

除了线程,还要再看一下之前提到的 DispSyncSource::setCallback 方法,因为这个方法才是真正处理 VSYNC-app 和 VSYNC-appsf 的地方。

php 复制代码
# DispSyncSource.cpp
    // 定义回调
    scheduler::VSyncDispatch::Callback mCallback;   

    void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
        std::lock_guard lock(mCallbackMutex);
        // 赋值
        mCallback = callback;
    }

现在就把所有的回调都串起来了。

根据分析,这里的 DispSyncSource::setCallback 其实就是把 EventThread::onVSyncEvent 设置给了 DispSyncSource 下的 mCallback

这里可能会好奇,参数 callback 是 VSyncSource::Callback 类型,怎么可以传 EventThread::onVSyncEvent 呢? 这个在 EventThread 头文件里有注释:

arduino 复制代码
# EventThread.h
class EventThread : public android::EventThread, private VSyncSource::Callback {
    ......
    // Implements VSyncSource::Callback
    void onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) override;
}

1.6 总结

这部分的主线就是整理 app 是如何向 VsyncDispatch 注册回调的,过程中涉及到各个类的创建。

1.6.1 回调的整理

在代码的分析过程中出现了各种"回调",很容易就晕了。 所以要抓住一个主线:VSyncDispatchTimerQueue::timerCallback 是如何回调到 EventThread::onVSyncEvent 的。

1.6.2 调用栈整理

这部分的调用链如下:

arduino 复制代码
SurfaceFlinger::initScheduler
    Scheduler::init                 -- Scheduler初始化
    Scheduler::createVsyncSchedule  -- VsyncSchedule 初始化
    Scheduler::createConnection     -- app appsf 注册回调
        Scheduler::makePrimaryDispSyncSource
            DispSyncSource::init    -- 创建DispSyncSource
                CallbackRepeater::init
                    VSyncCallbackRegistration::VSyncCallbackRegistration  -- DispSyncSource::onVsyncCallback 作为回调
                        VSyncDispatchTimerQueue::registerCallback  -- app,appsf 注册到mCallbacks中
                            VSyncDispatchTimerQueueEntry::init     -- 创建对应的Entry
                                VSyncDispatchTimerQueue.mCallbacks::emplace  --添加到mCallbacks
        EventThread::init
            DispSyncSource::setCallback    -- 把EventThread::onVSyncEvent 设置到DispSyncSource下的mCallbacks

最后再补充一下VSyncDispatchTimerQueueEntry和EventThread类图:

2 sf 向VsyncDispatch注册回调

sf 的注册就相对简单了,代码如下: 在 SurfaceFlinger::initScheduler 调用了 "mScheduler->initVsync" 这部分的逻辑代码定义如下:

arduino 复制代码
Scheduler.h
// 继承impl::MessageQueue
class Scheduler : impl::MessageQueue {
    // 定义别名
    using Impl = impl::MessageQueue;
    ......
    using Impl::initVsync;
    ......
}

所以真正执行的是 MessageQueue::initVsync 方法。

php 复制代码
# native\services\surfaceflinger\Scheduler\MessageQueue.cpp

    void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
                                frametimeline::TokenManager& tokenManager,
                                std::chrono::nanoseconds workDuration) {
        setDuration(workDuration);
        mVsync.tokenManager = &tokenManager;
        // 创建VSyncCallbackRegistration,名字是 sf
        mVsync.registration = std::make_unique<
                scheduler::VSyncCallbackRegistration>(dispatch,
                                                    std::bind(&MessageQueue::vsyncCallback, this,
                                                                std::placeholders::_1,
                                                                std::placeholders::_2,
                                                                std::placeholders::_3),
                                                    "sf");
        ......
    }

这里构建了一个 VSyncCallbackRegistration 对象,传递了 MessageQueue::vsyncCallback 作为回调,这个回调也是最终 sf 收到的回调

相对于 app 的注册,直接就创建 VSyncCallbackRegistration 对象,并没有 DispSyncSource 和 CallbackRepeater 的创建。

而后面的代码就和 app 的注册逻辑一样了。

css 复制代码
# VSyncDispatchTimerQueue.cpp
    VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
                                                        VSyncDispatch::Callback callback,
                                                        std::string callbackName)
        : mDispatch(dispatch),
            mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),
            mValidToken(true) {}

可以看到到了这里又是调用了 VSyncDispatchTimerQueue::registerCallback 方法,和 app ,appsf 注册监听是一样的。

c 复制代码
# VSyncDispatchTimerQueue.cpp

    VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
            Callback callback, std::string callbackName) {

        std::lock_guard lock(mMutex);
        return CallbackToken{
                mCallbacks
                        .emplace(++mCallbackToken,
                                std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
                                                                                std::move(callback),
                                                                                mMinVsyncDistance))
                        .first->first};
    }
    1. 构建出一个 VSyncDispatchTimerQueueEntry 对象
    1. 将其放到了 mCallbacks 中

sf 的回调逻辑就简单很多

2.1 Trace :Vsync-sf 的输出

void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) { ATRACE_CALL(); // Trace VSYNC-sf Trace处理 mVsync.value = (mVsync.value + 1) % 2; { std::lock_guard lock(mVsync.mutex); mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime); mVsync.scheduledFrameTime.reset(); }

scss 复制代码
const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
        {targetWakeupTime, readyTime, vsyncTime});
// SurfaceFlinger 后续处理
mHandler->dispatchFrame(vsyncId, vsyncTime);

}

Trace 上 VSYNC-sf 有波动,然后 SurfaceFlinger 就开始做合成工作。

3 总结

本篇介绍了 app 和sf 向 VsyncDispatch 注册回调的过程,这部分的代码有点绕,特别是涉及到了多个类的关系和多个回调。 这部分的代码可以不用很清楚,个人觉得知道以下三点就好:

    1. 定时结束触发的是 VSyncDispatchTimerQueue::timerCallback
    1. app 接收 Vsync-app 的方法是 DispSyncSource::onVsyncCallback
    1. sf 接收 Vsync-sf 的方法是 MessageQueue::vsyncCallback

其他的逻辑相对来说就没那么重要了,有个印象即可,必要时在当前文章能走到对应的代码逻辑就好。

下面对本篇的内容做个小结。 注册是在开机过程中初始化 SurfaceFlinger 触发 SurfaceFlinger::initScheduler 方法开始的。 调用链如下:

arduino 复制代码
SurfaceFlinger::initScheduler
    Scheduler::init                 -- Scheduler初始化
    Scheduler::createVsyncSchedule  -- VsyncSchedule 初始化
        VsyncSchedule::emplace
            VsyncSchedule::init
                VsyncSchedule::createTracker           -- VsyncTracker
                VsyncSchedule::createDispatch          -- VsyncDispatch(节拍器)
                    Timer::Timer                       -- 定时器创建
                    VSyncDispatchTimerQueue::init  
                VsyncSchedule::createController        -- VsyncController
    Scheduler::createConnection     -- app appsf 注册回调
        Scheduler::makePrimaryDispSyncSource
            DispSyncSource::init    -- 创建DispSyncSource传入VSyncDispatch
                CallbackRepeater::init
                    VSyncCallbackRegistration::VSyncCallbackRegistration  -- DispSyncSource::onVsyncCallback 作为回调
                        VSyncDispatchTimerQueue::registerCallback  -- app,appsf 注册到mCallbacks中
                            VSyncDispatchTimerQueueEntry::init
                                VSyncDispatchTimerQueue.mCallbacks::emplace  --添加到mCallbacks
        EventThread::init
            DispSyncSource::setCallback    -- 把 EventThread::onVSyncEvent 设置到DispSyncSource下的mCallbacks
    MessageQueue::initVsync      -- sf 注册回调
        VSyncCallbackRegistration::VSyncCallbackRegistration
            VSyncDispatchTimerQueue::registerCallback -- 注册到mCallbacks中
                VSyncDispatchTimerQueueEntry::init
                    VSyncDispatchTimerQueue.mCallbacks::emplace
    1. 都是在 SurfaceFlinger::initScheduler 开始触发的
    1. Scheduler 创建后会创建 VsyncSchedule ,这个类会触发3个关键类的创建,特别是节拍器 VsyncDispatch
    1. 产生 SW-Vsync 的地方是在 VsyncDispatch ,定时结束后执行 VSyncDispatchTimerQueue::timerCallback
    1. app appsf sf 都会创建一个 VSyncDispatchTimerQueueEntry 对象,然后注册到 VSyncDispatchTimerQueue 下的 mCallbacks 中
    1. app appsf 的注册相对复杂,以 DispSyncSource 为桥梁,然后在创建 VSyncCallbackRegistration 完成后续的注册
    1. sf 的注册相对简单一些,直接创建 VSyncCallbackRegistration 完成后续的注册
    1. app appsf 注册的回调函数是 DispSyncSource::onVsyncCallback ,且最终会调用到 EventThread::onVSyncEvent
    1. sf 注册是回调函数是 MessageQueue::vsyncCallback

当 VsyncDispatch(节拍器)产生 Vsync 的时候就会触发子类 VSyncDispatchTimerQueue 下的 mCallbacks 遍历,把 VSync 时间传递给集合下的每个元素。 目前已知的是这个 mCallbacks 下面有三个元素 app appsf sf。前面两个为线程,sf 为 MessageQueue 类型。

app,appsf,sf注册回调流程图如下:

相同点就是都会通过 VSyncCallbackRegistration 完成注册,并且构建对应的 VSyncDispatchTimerQueueEntry 对象再添加到 VSyncDispatchTimerQueue 下的 mCallbacks 中。

参考:

<千里马学框架-SurfaceFlinger>

www.jianshu.com/p/5e9c558d1...

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

相关推荐
恋猫de小郭1 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab2 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe7 小时前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农15 小时前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少15 小时前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker15 小时前
一杯美式搞定 Kotlin 空安全
android·kotlin
三少爷的鞋16 小时前
Android 协程时代,Handler 应该退休了吗?
android
火柴就是我1 天前
让我们实现一个更好看的内部阴影按钮
android·flutter
阿懂在掘金1 天前
defineModel 是进步还是边界陷阱?双数据源组件的选择逻辑
vue.js·源码阅读
砖厂小工1 天前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github