显示图形系统分析之SurfaceFlinger和VSync信号

2,744 阅读9分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

SurfaceFlinger和VSync信号

在显示图形系统中,有一个很重要的概念--VSync信号,垂直同步信号,HWC利用硬件或者软件产生的持续Vsync信号去触发SF和UI去做绘图相关的工作,让绘图工作充分利用每个Vsync信号间隔的时间

hal层Composer回调函数

在SurfaceFlinger初始化的过程中,会初始化一个HWComposer指针对象,然后调用这个对象的setConfiguration函数

void HWComposer::setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) {
    // ......
    mRegisteredCallback = true;
    sp<ComposerCallbackBridge> callbackBridge(
            new ComposerCallbackBridge(callback, sequenceId, mComposer->isVsyncPeriodSwitchSupported()));
    mComposer->registerCallback(callbackBridge);
}

在这个函数中,通过初始化ComposerCallbackBridge指针对象,为android::hwc2::Composer对象注册一个回调类,其实从ComposerCallbackBridge类的名称,我们也可以看到,这个类对象起了一个桥梁的作用,即将接收到的回调信号传递给回调类处理,那么此处具体是做什么呢? 为了便于理解,先绘制一个类图结构如下: 图片.png 从这张图来看,

  1. ComposerCallbackBridge类继承了hal::IComposerCallback类,IComposerCallback类的命名空间在hal,也就是说它是一个hal层的Composer回调类,
  2. ComposerCallbackBridge有一个参数mCallback是一个ComposerCallback对象,SurfaceFlinger类继承自这个ComposerCallback类,而setConfiguration函数传入的第一个参数为SurfaceFlinger对象,因此此处,ComposerCallbackBridge的参数mCallback是一个指向SurfaceFlinger的指针
  3. ComposerCallbackBridge类关联的是hal层的IComposerCallback类和frameworks-native层的ComposerCallback对象,而此处是SurfaceFlinger对象

而我们再查看ComposerCallbackBridge类函数的具体实现

class ComposerCallbackBridge : public hal::IComposerCallback {
public:
    ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId, bool vsyncSwitchingSupported)
          : mCallback(callback),
            mSequenceId(sequenceId),
            mVsyncSwitchingSupported(vsyncSwitchingSupported) {}

    android::hardware::Return<void> onHotplug(hal::HWDisplayId display, hal::Connection conn) override {
        mCallback->onHotplugReceived(mSequenceId, display, conn);
        return android::hardware::Void();
    }

    android::hardware::Return<void> onRefresh(hal::HWDisplayId display) override {
        mCallback->onRefreshReceived(mSequenceId, display);
        return android::hardware::Void();
    }

    android::hardware::Return<void> onVsync(hal::HWDisplayId display, int64_t timestamp) override {
        if (!mVsyncSwitchingSupported) {
            mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
        } else {
            ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring.");
        }
        return android::hardware::Void();
    }

    android::hardware::Return<void> onVsync_2_4(hal::HWDisplayId display, int64_t timestamp,
                                                hal::VsyncPeriodNanos vsyncPeriodNanos) override {
        if (mVsyncSwitchingSupported) {
            mCallback->onVsyncReceived(mSequenceId, display, timestamp,
                                       std::make_optional(vsyncPeriodNanos));
        } else {
            ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
        }
        return android::hardware::Void();
    }

    android::hardware::Return<void> onVsyncPeriodTimingChanged(
            hal::HWDisplayId display,
            const hal::VsyncPeriodChangeTimeline& updatedTimeline) override {
        mCallback->onVsyncPeriodTimingChangedReceived(mSequenceId, display, updatedTimeline);
        return android::hardware::Void();
    }

    android::hardware::Return<void> onSeamlessPossible(hal::HWDisplayId display) override {
        mCallback->onSeamlessPossible(mSequenceId, display);
        return android::hardware::Void();
    }

private:
    ComposerCallback* mCallback;
    const int32_t mSequenceId;
    const bool mVsyncSwitchingSupported;
};

也就是说,hal层发出的IComposerCallback类中的回调信号,最终的处理均是在SurfaceFlinger对象中的对应回调函数中处理

SurfaceFlinger::init函数

在SurfaceFlinger初始化的时候,

  1. 通过HWComposer的setConfiguration函数,会引起驱动Composer向Frameworks发送一个插拔显示设备的信号事件,在frameworks的SurfaceFligner::onHotplugReceived回调函数中处理,
  2. 然后通过processDisplayHotplugEventsLocked函数,来运行这个设备热插拔事件,
  3. 而在这个函数中,会通过initScheduler函数来初始化Scheduler对应的相关操作

因此,我们首先需要查看下initScheduler函数的具体功能

void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) {
    // ......
    // start the EventThread
    // 初始化Scheduler对象
    mScheduler = getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
                                         *mRefreshRateConfigs, *this);
    // 初始化两个ConnectionHandle对象
    mAppConnectionHandle =
            mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app,
                                         impl::EventThread::InterceptVSyncsCallback());
    mSfConnectionHandle =
            mScheduler->createConnection("sf", mPhaseConfiguration->getCurrentOffsets().late.sf,
                                         [this](nsecs_t timestamp) {
                                             mInterceptor->saveVSyncEvent(timestamp);
                                         });
    // 设置EventQueue的ConnectionHandle
    mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
    mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle,
                            mPhaseConfiguration->getCurrentOffsets());
    // 启动一个RegionSamplingThread对象
    mRegionSamplingThread =
            new RegionSamplingThread(*this, *mScheduler,
                                     RegionSamplingThread::EnvironmentTimingTunables());
    // Dispatch a config change request for the primary display on scheduler
    // initialization, so that the EventThreads always contain a reference to a
    // prior configuration.
    //
    // This is a bit hacky, but this avoids a back-pointer into the main SF
    // classes from EventThread, and there should be no run-time binder cost
    // anyway since there are no connected apps at this point.
    // 设置VSYNC信号周期
    const nsecs_t vsyncPeriod =
            mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).getVsyncPeriod();
    mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, primaryDisplayId.value,
                                              currentConfig, vsyncPeriod);
}

这段代码的初始化,我们在默认DisplayDevice显示设备加载流程分析文章有分析过这个Scheduler对象的初始化流程,只是上篇关注点在显示设备加载上,而忽略了其他初始化流程,因此本篇将从另一个方向来分析下这个初始化流程

从此前篇章分析中,在SurfaceFlinger::initScheduler函数,主要是做了:

  1. 初始化一个Scheduler指针对象,在这个初始化中,顺便初始化了Scheduler的两个参数,mPrimaryDispSync和mEventControlThread,分别对应的是VSyncReactor对象和EventControlThread对象
  2. 初始化两个ConnectionHandle,分别对应的是SF和APP
  3. 设置SurfaceFlinger的MessageQueue的消息处理文件句柄
  4. 初始化一个RegionSamplingThread线程,并启动这个线程
  5. Scheduler的onPrimaryDisplayConfigChanged回调函数的调用,启动EventThread消息机制

Scheduler初始化流程

此处直接借助类图和时序图来说明其具体流程

图片.png

图片.png

从如上的Scheduler初始化流程的类图和时序图来看,这边主要的工作如下:

  1. 在Scheduler的初始化过程中,首先通过调用Scheduler的createDispSync函数初始化了一个VSyncReactor指针对象,VSyncReactor继承自android::DispSync对象,同时VSyncReactor对象中包含两个参数mTracker和mDispatch,它们分别是继承自VSyncTracker类的VSyncPredictor指针对象,以及继承自VSyncDispatch类的VSyncDispatchTimerQueue指针对象
std::unique_ptr<DispSync> createDispSync(bool supportKernelTimer) {
    // TODO (140302863) remove this and use the vsync_reactor system.
    if (property_get_bool("debug.sf.vsync_reactor", true)) {
        // TODO (144707443) tune Predictor tunables.
        static constexpr int defaultRate = 60;
        static constexpr auto initialPeriod =
                std::chrono::duration<nsecs_t, std::ratio<1, defaultRate>>(1);
        static constexpr size_t vsyncTimestampHistorySize = 20;
        static constexpr size_t minimumSamplesForPrediction = 6;
        static constexpr uint32_t discardOutlierPercent = 20;
        // 初始化VSyncPredictor对象,此类继承自VSyncTracker类
        auto tracker = std::make_unique<
                scheduler::VSyncPredictor>(std::chrono::duration_cast<std::chrono::nanoseconds>(
                                                   initialPeriod)
                                                   .count(),
                                           vsyncTimestampHistorySize, minimumSamplesForPrediction,
                                           discardOutlierPercent);

        static constexpr auto vsyncMoveThreshold =
                std::chrono::duration_cast<std::chrono::nanoseconds>(3ms);
        static constexpr auto timerSlack =
                std::chrono::duration_cast<std::chrono::nanoseconds>(500us);
        // 初始化VSyncDispatchTimerQueue指针对象,此类继承自VSyncDispatch类
        auto dispatch = std::make_unique<
                scheduler::VSyncDispatchTimerQueue>(std::make_unique<scheduler::Timer>(), *tracker,
                                                    timerSlack.count(), vsyncMoveThreshold.count());

        static constexpr size_t pendingFenceLimit = 20;
        // 返回一个VSyncReactor对象,此类继承自android::DispSync类
        // 注意,此处返回的android::DispSync类跟else分支中的android::impl::DispSync不是同一个类
        return std::make_unique<scheduler::VSyncReactor>(std::make_unique<scheduler::SystemClock>(),
                                                         std::move(dispatch), std::move(tracker),
                                                         pendingFenceLimit, supportKernelTimer);
    } else {
        return std::make_unique<impl::DispSync>("SchedulerDispSync",
                                                sysprop::running_without_sync_framework(true));
    }
}
  1. 同时,在Scheduler初始化过程中,直接初始化了一个EventControlThread指针对象,在这个对象的初始化过程中,会启动一个线程并调用其threadMain函数,在这个函数中,有一个while循环,这个while循环中,首先会调用SurfaceFlinger在createScheduler过程中传递的第一个参数对应的函数指针,最终会调用SurfaceFlinger::setPrimaryVsyncEnabled函数(第一次设置VSyncEnabled为false),此后会调用mCondition的wait函数,等待对应的VsyncEnabled状态变化时再次调用SurfaceFlinger::setPrimaryVsyncEnabled函数
EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
      : mSetVSyncEnabled(std::move(function)) {
    pthread_setname_np(mThread.native_handle(), "EventControlThread");

    pid_t tid = pthread_gettid_np(mThread.native_handle());
    setpriority(PRIO_PROCESS, tid, ANDROID_PRIORITY_URGENT_DISPLAY);
    set_sched_policy(tid, SP_FOREGROUND);
}

void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
    auto keepRunning = true;
    auto currentVsyncEnabled = false;

    while (keepRunning) {
        // SurfaceFlinger中调用SurfaceFlingerDefaultFactory::createScheduler时传入的第一个参数
        // 最终会调用到SurfaceFlinger::setPrimaryVsyncEnabled函数
        mSetVSyncEnabled(currentVsyncEnabled);

        std::unique_lock<std::mutex> lock(mMutex);
        // 等待其他部分唤醒
        mCondition.wait(lock, [this, currentVsyncEnabled, keepRunning]() NO_THREAD_SAFETY_ANALYSIS {
            // 条件满足时释放lock锁后继续运行
            return currentVsyncEnabled != mVsyncEnabled || keepRunning != mKeepRunning;
        });
        currentVsyncEnabled = mVsyncEnabled;
        keepRunning = mKeepRunning;
    }
}

创建ConnectionHandle

看这个流程中的类图和时序图: 图片.png

图片.png

从如上的类图和流程图来看,在这个过程中

  1. Scheduler的createConnection函数
    • 首先初始化了一个DispSyncSource类对象,这个DispSyncSource类继承自VSyncSource类和android::DispSync::Callback回调类,同时其包含了一个参数名为mDispSync的指针指向在Scheduler初始化过程中初始化的一个VSyncReactor对象
    • 创建一个EventThread对象,并且其包含了一个参数名为mVSyncSource的指针指向刚刚创建的DispSyncSource对象,且包含一个名称为mInterceptVSyncsCallback的指针参数指向Scheduler调用createConnection函数时传入的第三个参数对应的函数指针
    • 在创建EevntThread对象的同时,设置DispSyncSource指针对象的Callback为当前的EventThread
    • 同时在EventThread构造函数中启动一个线程,并且调用EventThread::threadMain函数,在这个函数中,主要操作处理接收一些显示设备传递的一些Event(如插拔事件或者VSYNC事件等)
    • 最终,EventThread::threadMain函数mCondition.wait(lock)处于等待堵塞状态
    • 调用EventThread对象的createEventConnection函数,初始化一个EventThreadConnection对象,并且这个对象中包含参数名为mEventThread的指针参数指向刚刚创建的EventThread对象,resyncCallback指针参数指向一个在Scheduler调用EventThread::createEventConnection函数时传递的第一个函数指针参数
    • 初始化EventThreadConnection对象的过程中,会调用其onFirstRefs函数,在这个函数中会调用EventThread::registerDisplayEventConnection函数,从而最终触发EventThread::threadMain的同步条件
Scheduler::ConnectionHandle Scheduler::createConnection(
        const char* connectionName, nsecs_t phaseOffsetNs,
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
    // 初始化一个DispSyncSource指针对象
    auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs);
    // 初始化一个EventThread指针对象
    auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
                                                           std::move(interceptCallback));
    return createConnection(std::move(eventThread));
}

Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) {
    const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
    ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
    
    auto connection =
            createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
    // 在创建EventThreadConnection指针对象和EventThread指针对象作为values值添加到mConnections
    mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
    return handle;
}

sp<EventThreadConnection> Scheduler::createConnectionInternal(
        EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
    return eventThread->createEventConnection([&] { resync(); }, configChanged);
}

sp<EventThreadConnection> EventThread::createEventConnection(
        ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const {
    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
                                     configChanged);
}

EventThreadConnection::EventThreadConnection(EventThread* eventThread,
                                             ResyncCallback resyncCallback,
                                             ISurfaceComposer::ConfigChanged configChanged)
      : resyncCallback(std::move(resyncCallback)),
        mConfigChanged(configChanged),
        mEventThread(eventThread),
        mChannel(gui::BitTube::DefaultSize) {}
        
void EventThreadConnection::onFirstRef() {
    // NOTE: mEventThread doesn't hold a strong reference on us
    mEventThread->registerDisplayEventConnection(this);
}

status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
    std::lock_guard<std::mutex> lock(mMutex);

    // ......
    // 为mDisplayEventConnections添加参数,这样EventThread::threadMain函数在唤醒的时候就会执行对应的代码
    // 但是,此时如果追踪下去代码,会发现,EventThread::threadMain函数依旧会被堵塞,因为mPendingEvents中依旧无数据
    mDisplayEventConnections.push_back(connection);
    // 唤醒mCondition,此处是EventThread::threadMain函数中阻塞
    mCondition.notify_all();
    return NO_ERROR;
}
  1. 在SurfaceFlinger中调用MessageQueue::setEventConnection函数,进而调用Looper::addFd函数,从而将SurfaceFlinger的消息处理和此处的EventThread进行关联,当EventThread接收到Composer驱动发出的Event消息,则会在MessageQueue::cb_eventReceiver函数中进行最终的处理
// 注意,此处关联的是SF对应的EventThreadConnection指针对象
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));

void MessageQueue::setEventConnection(const sp<EventThreadConnection>& connection) {
    // ......
    mEvents = connection;
    // 设置mEventTube为对应EventThreadConnection的mChannal通道
    mEvents->stealReceiveChannel(&mEventTube);
    // 将EventThreadConnection指针对象的receive fd,并且设置的回调函数为MessageQueue::cb_eventReceiver函数
    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
                   this);
}

初始化Display设备

同样地,先来一张初始化显示设备的时序图 图片.png 从这张图中也能看到,在SurfaceFlinger的init中,通过initializeDisplays函数初始化对应的显示设备,在此期间,设置DisplayDevice的PowerMode状态为PowerMode::ON,然后在Scheduler中设置mHWVsyncAvailable参数的值为true,表明当前Composer驱动或者HWComposer的硬件VSYNC已经准备完成,此后设置VSyncReactor(继承自DispSync类)的VSYNC Period值,显示设备的VSYNC信号启动上报。

驱动VSync信号上报

在前述的分析中,我们知道,Hal层的Composer信号通过HWComposer的ComposerCallbackBridge指针对象中的回调函数,传递到SurfaceFlinger的回调函数,因此当硬件VSYNC信号上报时,触发了ComposerCallbackBridge指针对象的onVsync函数回调,继而调用了SurfaceFlinger的onVsyncReceived函数回调,即

图片.png

SurfaceFlinger接收到硬件VSYNC信号回调函数onVsyncReceived后通过Scheduler的addResyncSample构建硬件模型Sample,确认是否需要开启或者关闭硬件驱动VSYNC信号的触发