理解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...

相关推荐
_李小白2 小时前
【Android FrameWork】延伸阅读:SurfaceFlinger线程
android
csdn12259873363 小时前
JetPack Compose 入门先搞清楚
android·compose·jetpack
liang_jy3 小时前
Android LaunchMode
android·面试
阿里云云原生4 小时前
Android App 崩溃排查实战:如何利用 RUM 完整数据与符号化技术定位问题?
android·阿里云·云原生·rum
过期动态5 小时前
JDBC高级篇:优化、封装与事务全流程指南
android·java·开发语言·数据库·python·mysql
没有了遇见7 小时前
Android 音乐播放器之MotionLayout实现View流畅变换
android
TheNextByte18 小时前
在 PC 和Android之间同步音乐的 4 种方法
android
君莫啸ོ8 小时前
Android基础-Activity属性 android:configChanges
android
TimeFine8 小时前
Android AI解放生产力(七):更丰富的AI运用前瞻
android
保持低旋律节奏9 小时前
linux——进程状态
android·linux·php