Android-View绘制原理(02)-VSync原理之SurfaceFlinger篇

前面一篇文章从整体介绍View绘制的流程,其中一点就是绘制的起始点就是界面收到了Vsync之后,开始新一帧的绘制,所以可以说, 是vsync触发了绘制。收到vsync信号后的处理我们已经清楚了,现在我们分析以下sync是怎么产生的,以及怎么消费的。

1. 从 16ms说起

我们16ms这个时间应该是印象深刻了,我们经常听到在大部分屏幕的刷新频率是60Hz的情况下,那每一帧的时间就约16ms,如果应用程序在收到一次vsync信号开始绘制,16毫秒内没有绘制完毕,就会出现丢帧,卡顿。确实如此,但是这听起来却有些难以理解,绘制慢一点怎么就影响到到屏幕刷新了,它不是按照屏幕的硬件60Hz频率刷的吗?为什么会丢呢?丢了为什么会卡顿呢?究竟vsync什么时候来?

2. Vsync的作用

这不是本文的重点,只是作为背景知识介绍一下。假设一下以下的情况:

  • app每秒钟匀速生成120张图片,但是屏幕每秒只能匀速显示60张。结果是120张中只有60张展示,步调相同的情况下,偶数张被忽略,即丢帧,app多生成的60张属于浪费CPU,CPU完全可以生产1张后休眠一会,节约资源
  • app每秒钟生成30张,但是屏幕每秒钟刷新60次。结果是第二次刷新时展示的内容是上一次生产的,屏幕完全可以刷新一次休息一次,减少耗电。
  • app每秒生成60张,屏幕每秒钟刷新60次,但是步调不一致,屏幕显示完上半屏内容的时候,新的显示数据来了,下半屏幕将显示新的内容,形成画面撕裂。

这3个问题就是因为生产显示数据和消费显示数据不一致导致的。因此需要将二者进行同步。

  • app需要更新内容时通知屏幕开始刷新,否则屏幕不作刷新;
  • 屏幕显示完了通知app可以生产新数据,app进行绘制,否则app不做绘制;
  • 屏幕显示完成前,也不做显示数据的更新,防止画面撕裂。

这个同步就是Vsync。其实vsync并不是我们想象的那样,屏幕每16ms刷新一次,然后每16毫秒就发送一次sync(屏幕是否一直是每16ms就无条件刷新一次,暂时还无法从代码里得到证实),事实是如果界面没有事件,比如点击,动画,焦点等需要展示新内容操作,比如一个界面展示一个文本后,没有任何用户交互,这个段时间内就不会有sync信号出现。这很好理解,一个静态的页面在那里不停绘制相同的内容,肯定是浪费电的,这对手机来说是至关重要的。只有当内容是需要一直在变化的,比如在连续滑动的界面,动画和游戏等才有vsync信号持续出现,而至于一个静态的图片展示页面是没有Vsync信号的。

假设一个电影文件里1秒钟记录了60张图片,如果屏幕刷新率只有30次,如果没有sync,那电影文件里一张展示一张不展示,如果人的眼睛特别灵敏的话,就会发现画面不连贯,不展示的那些帧就是所谓的丢帧

在软件里,和电影不一样,每一帧都是运算后画出来的,理论上来说通过VSync来控制后,不存在丢帧的情况,也就是生产出来的每一帧都会被展示,但是会出现卡顿不连贯,比如第N帧耗时比较多的时候,当前帧(N-1)展示时间就相应增加,而(N+1)帧开始时间会相应延迟,相应计算出来的变化就过大。从视觉上看就是屏幕一直停在某个画面,但是画面变化时一下又变得很大,最后在给定时间内展示的帧数也比预期的少。比如一个动画,设置总的时间是1000毫米,移动距离600像素,如果每帧绘制很快,那总共可以展示60帧,第一帧16ms移动到10,第二帧32ms移动到20…第60帧移动到600,这就是很流畅的,帧数60次。这个位移值是一个时间的函数(不是次数的函数),它是动画当前的时间减去启动时间,再去算动画时长的位移,如果每帧执行的时间变成32s,显示时就是第一帧32ms帧20,第二帧64ms帧40… 这就导致第一帧展示了32ms(时间变长了),而且第二帧直接从20移动到40(变化太大了),帧数也只有30次,相当于“丢失”了30帧。如果是不均匀的变化,那么界面的抖动就更加的难以接受。所以Vsync并不能避免丢帧卡顿的情况。它只能避免屏幕撕裂,以及减少资源的浪费

下面正式进入vsync的技术分析。

3. Vsync流程

整体来看,Vsync的流程可以分为SurfaceFlinger 层的Vsync信号产生流程,App层的监听流程和触发流程。

  • Vsync信号的产生流程,主要包括sufacefinger对HAL层注册回调以及处理,并开启一个EventThread来分发Vsync信号
  • App在展示UI的时候,注册监听获取Vsync的通知
  • Vsync在surfaceflinger产生后,并不会直接上报,而是在等待UI层的通知,UI层触发后底层启动事件分发,然后UI层收到Vsync才开始绘制

下面我们沿着这个流程来看看每个环节的实现。本片文章首先分析surfaceflinger部分,介绍Vsync的架构基础

4. SurfaceFlinger层的实现

这一节里面主要会介绍到以下的内容

  • 作为背景,介绍surfaceFligger 的启动和初始化
  • HWComposer 关于vsync的接口
  • Schedualer, EventThread ,MessageQueue , 事件分发

4.1. SurfaceFlinger的初始化

代码编译后,它是一个独立的可执行程序打包到镜像文件里,路径是/system/bin/surfaceflinger,在Init的时候启动
frameworks/native/services/surfaceflinger/surfaceflinger.rc

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    capabilities SYS_NICE
    onrestart restart zygote
    task_profiles HighPerformance
    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0

Init的流程就不讲了,我们直接进入它到main函数
frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

int main(int, char**) {
    
    sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
    flinger->init();

    // publish surface flinger
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);

    if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
        ALOGW("Couldn't set to SCHED_FIFO: %s", strerror(errno));
    }

    flinger->run();

    return 0;
}

通过工厂来创建SurfaceFlinger的实例
frameworks/native/services/surfaceflinger/SurfaceFlingerFactory.cpp

sp<SurfaceFlinger> createSurfaceFlinger() {
    static DefaultFactory factory;

    return new SurfaceFlinger(factory);
}

这个factory是默认的DefaultFactory,定义在frameworks/native/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp

SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
      : mFactory(factory),
      ...
}

SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
    ...
}

其他服务暂时略去,仅仅看一下surfaceflinger的启动,创建一个SurfaceFlinger对象,然后调用init初始化,之后注册到servicemanager,供远程访问,最后执行run启动服务,这里主要就是构造方法和init 方法。SurfaceFligger的父类或者接口包含以下几个:

class SurfaceFlinger : public BnSurfaceComposer,
                       public PriorityDumper,
                       private IBinder::DeathRecipient,
                       private HWC2::ComposerCallback,
                       private ISchedulerCallback {
...

}
  • BnSurfaceComposer是作为ISurfaceComposer的服务端桩
  • HWC2::ComposerCallback 作为HWComposer的回调,主要包含onComposerHalVsync等方法,定义在frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.h
  • ISchedulerCallback,作为Scheduler的回调,主要包含setVsyncEnabled方法定义在frameworks/native/services/surfaceflinger/Scheduler/Scheduler.h。

上面的定义说明,我们可以大致认为 SurfaceFlinger对象会被注册到HWComposer去,在HWComposer端收到硬件的Vsync后,会回调SurfaceFlinger的onComposerHalVsync方法;同时SurfaceFlinger对象会被注册到Scheduler中去,在适当时候会回调setVsyncEnabled方法。下面看看是如果这些代码是关联起来的。

4.1.1. init
void SurfaceFlinger::init() {

    mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));
    mCompositionEngine->getHwComposer().setCallback(this);
    ...
    processDisplayHotplugEventsLocked();
    ..
}

这里首先调用了factory.createHWComposer方法去创建一个HWComposer,然后再调用setCallback(this)完成SurfaceFlinger与HWComposer的关联。然后调用processDisplayHotplugEventsLocked方法,处理屏幕热插拔事件,处理包含内置屏幕在内初始化

void SurfaceFlinger::processDisplayHotplugEventsLocked() {
    for (const auto& event : mPendingHotplugEvents) {
        ...
        if (event.connection == hal::Connection::CONNECTED) {
               ...
                if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
                    initScheduler(state);
                }
                ...
            } else {
               ...
            }
       }
}

如果找到了内置显示器,则调用initScheduler

void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
    ...
    // start the EventThread
    mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
    const auto configs = mVsyncConfiguration->getCurrentConfigs();
    const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
    mAppConnectionHandle =
            mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
                                         /*workDuration=*/configs.late.appWorkDuration,
                                         /*readyDuration=*/configs.late.sfWorkDuration,
                                         impl::EventThread::InterceptVSyncsCallback());
    mSfConnectionHandle =
            mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),
                                         /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
                                         /*readyDuration=*/configs.late.sfWorkDuration,
                                         [this](nsecs_t timestamp) {
                                             mInterceptor->saveVSyncEvent(timestamp);
                                         });

    mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
                           configs.late.sfWorkDuration);

   ...
}
  • getFactory().createScheduler(*mRefreshRateConfigs, *this) 第二个参数的类型是ISchedulerCallback,此处传入this,于是将SurfaceFlingger 和Scheduler关联了起来。

  • 创建好Schdueler之后,连续调用createConnection创建了一个名叫“app”的mAppConnectionHandle 和 “appSf”的mSfConnectionHandle,他们的类型是ConnectionHandle。

  • 然后调用mEventQueue->initVsync 初始化Vsync.

4.1.2. Schduler

我们接着看看上面创建的两个ConnectionHandle创建的细节
frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp

Scheduler::ConnectionHandle Scheduler::createConnection(
        const char* connectionName, frametimeline::TokenManager* tokenManager,
        std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
    auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
    auto throttleVsync = makeThrottleVsyncCallback();
    auto getVsyncPeriod = makeGetVsyncPeriodFunction();


    auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
                                                           std::move(interceptCallback),
                                                           std::move(throttleVsync),
                                                           std::move(getVsyncPeriod));
    return createConnection(std::move(eventThread));
}

先根据名称(就是app,或者appSf)调用makePrimaryDispSyncSource来生成一个DispSyncSource对象,以此对象为参数生成EventThread对象,然后调用createConnection生成一个ConnectionHandle.


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());

    std::lock_guard<std::mutex> lock(mConnectionsLock);
    mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
    return handle;
}

ConnectionHandle 关联一个Connection,这个Connect持有一个通过createConnectionInternal创建出来的connect,它实际上是一个EventThreadConnection。所以可以认为Scheduler::createConnection实际上创建了一个EventThread,然后与这个EventThread了一个连接.最后将这个关系保存到dispatcher的mConnections变量。

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

调用eventThread的createEventConnection
frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

sp<EventThreadConnection> EventThread::createEventConnection(
        ResyncCallback resyncCallback,
        ISurfaceComposer::EventRegistrationFlags eventRegistration) const {
    return new EventThreadConnection(const_cast<EventThread*>(this),
                                     IPCThreadState::self()->getCallingUid(),
                                     std::move(resyncCallback), eventRegistration);
}

创建的EventThreadConnection是一个Binder对象,所以可以同归Binder再不同进程间传递,它有两个重要方法,

  • postEvent,通知有一个新的Vsync可以发送到UI层。
  • requestNextVsync ,UI 层跨进程通知SurfaceFlinger准备下一次Vsync。
class EventThreadConnection : public BnDisplayEventConnection {
        virtual status_t postEvent(const DisplayEventReceiver::Event& event);
        void requestNextVsync() override; // asynchronous
        ...
}

所以EventThread也是起起着两个作用,它无限循环,然后根据需要执行postEvent或者requestNextVsync。

4.1.3. EventQueue

创建了ConnectionHandle后,后面调用了mEventQueue->initVsync。
frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp

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

这里只是将MessageQueue::vsyncCallback这个方法与mVsync绑定,在后面mVsync.registration.schedule的时候,会触发MessageQueue::vsyncCallback方法。
mVsync是一个结构体,定义在frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.h

struct Vsync {
        frametimeline::TokenManager* tokenManager = nullptr;
        std::unique_ptr<scheduler::VSyncCallbackRegistration> registration;

        std::mutex mutex;
        TracedOrdinal<std::chrono::nanoseconds> workDuration
                GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
        std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0};
        bool scheduled GUARDED_BY(mutex) = false;
        std::optional<nsecs_t> expectedWakeupTime GUARDED_BY(mutex);
        TracedOrdinal<int> value = {"VSYNC-sf", 0};
    };

4.2 EventThread

EventThread是Vsync中非常重要的一个类,我们单独来分析一下。

4.2.1 初始化
EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
                         android::frametimeline::TokenManager* tokenManager,
                         InterceptVSyncsCallback interceptVSyncsCallback,
                         ThrottleVsyncCallback throttleVsyncCallback,
                         GetVsyncPeriodFunction getVsyncPeriodFunction)
      : mVSyncSource(std::move(vsyncSource)),
        mTokenManager(tokenManager),
        mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
        mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
        mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)),
        mThreadName(mVSyncSource->getName()) {

    LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr,
            "getVsyncPeriodFunction must not be null");

    mVSyncSource->setCallback(this);

    mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
        std::unique_lock<std::mutex> lock(mMutex);
        threadMain(lock);
    });
   ....

构造函数里主要作了两件事情

  • 自己作为mVSyncSource的callback,当mVSyncSource上有事件时,会调用EventThread的onVSyncEvent方法,它的定义在
    frameworks/native/services/surfaceflinger/Scheduler/EventThread.h
class VSyncSource {
public:
    class Callback {
    public:
        virtual ~Callback() {}
        virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
                                  nsecs_t deadlineTimestamp) = 0;
    };
...
}
  • 开启一个线程去执行threadMain方法。这是事件分发的核心方法,它无限循环,去检查pendingEvents,有的话就执行
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    DisplayEventConsumers consumers;

    while (mState != State::Quit) {
        std::optional<DisplayEventReceiver::Event> event;

        // Determine next event to dispatch.
        if (!mPendingEvents.empty()) {
            event = mPendingEvents.front();
            mPendingEvents.pop_front();

            switch (event->header.type) {
                ...
                case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
                    if (mInterceptVSyncsCallback) {
                        mInterceptVSyncsCallback(event->header.timestamp);
                    }
                    break;
            }
        }

        bool vsyncRequested = false;

        // Find connections that should consume this event.
        auto it = mDisplayEventConnections.begin();
        while (it != mDisplayEventConnections.end()) {
            if (const auto connection = it->promote()) {
                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;

                if (event && shouldConsumeEvent(*event, connection)) {
                    consumers.push_back(connection);
                 }
        ...
        }

        if (!consumers.empty()) {
            dispatchEvent(*event, consumers);
            consumers.clear();
        }
       ...
        if (event) {
            continue;
        }

        // Wait for event or client registration/request.
        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.
            const std::chrono::nanoseconds timeout =
                    mState == State::SyntheticVSync ? 16ms : 1000ms;
            if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                if (mState == State::VSync) {
                    ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);
                    std::string debugInfo = "VsyncSource debug info:\n";
                    mVSyncSource->dump(debugInfo);
                    // Log the debug info line-by-line to avoid logcat overflow
                    auto pos = debugInfo.find('\n');
                    while (pos != std::string::npos) {
                        ALOGW("%s", debugInfo.substr(0, pos).c_str());
                        debugInfo = debugInfo.substr(pos + 1);
                        pos = debugInfo.find('\n');
                    }
                }

                LOG_FATAL_IF(!mVSyncState);
                const auto now = systemTime(SYSTEM_TIME_MONOTONIC);
                const auto deadlineTimestamp = now + timeout.count();
                const auto expectedVSyncTime = deadlineTimestamp + timeout.count();
                const int64_t vsyncId = [&] {
                    if (mTokenManager != nullptr) {
                        return mTokenManager->generateTokenForPredictions(
                                {now, deadlineTimestamp, expectedVSyncTime});
                    }
                    return FrameTimelineInfo::INVALID_VSYNC_ID;
                }();
                mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,
                                                   ++mVSyncState->count, expectedVSyncTime,
                                                   deadlineTimestamp, vsyncId));
            }
        }
    }
}

  • mPendingEvents 是收到的事件,其中就包括Vsync事件DISPLAY_EVENT_VSYNC
  • mDisplayEventConnections 这个集合里面记录的是事件的消费者,也就是远程连接过来的app,
  • dispatchEvent 将事件分发给消费者,
  • mCondition.wait,等待下一次处理。
4.2.2 mPendingEvents

这是收集到事件,事件是从那里来的,后来会再分析。

4.2.3 mDisplayEventConnections

这是Vsync的消费者,就是远程连接过来的app。app如何连接过来的,将在后面章节分析。前面提到EventThreadConnection是继承自BnDisplayEventConnection,所以它可以重写onFirstRef方法,(当远程连接读取到这个binder的时候会发送BC_ACQUIRE这个命令,增加服务端的引用,从而会调用到onFirstRef方法)

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);

    // this should never happen
    auto it = std::find(mDisplayEventConnections.cbegin(),
            mDisplayEventConnections.cend(), connection);
    if (it != mDisplayEventConnections.cend()) {
        ALOGW("DisplayEventConnection %p already exists", connection.get());
        mCondition.notify_all();
        return ALREADY_EXISTS;
    }

    mDisplayEventConnections.push_back(connection);
    mCondition.notify_all();
    return NO_ERROR;
}

如果不存在这个connection,就把它加入到mDisplayEventConnections,从这里可以看到,一旦有app连接过来,就会成为Vsync的消费者。并且调用了mCondition.notify_all();唤醒等待的线程(就是EventThread开启的那个线程)

4.2.4 dispatchEvent

当存在消费者也有Vsync事件的时候,就会进行分发

void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                const DisplayEventConsumers& consumers) {
    for (const auto& consumer : consumers) {
        DisplayEventReceiver::Event copy = event;
        if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
            copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
        }
        switch (consumer->postEvent(copy)) {
          ...
        }
    }
}

分发之调用的consumer->postEvent(copy),这个consumer就是上面加入的EventThreadConnection对象。它的postEvent如下:

status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
     ...
    auto size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
    return toStatus(size);
}

mChannel 的类型是BitTube,保存的是EventThreadConnection中记录的文件描述符,这个文件描述符会复制到连接过来的app进程.然后调用DisplayEventReceiver::sendEvents(&mChannel, &event, 1)方法,

ssize_t DisplayEventReceiver::sendEvents(Event const* events, size_t count) {
    return DisplayEventReceiver::sendEvents(mDataChannel.get(), events, count);
}

ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
        Event const* events, size_t count)
{
    return gui::BitTube::sendObjects(dataChannel, events, count);
}

frameworks/native/libs/gui/BitTube.cpp

ssize_t BitTube::sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize) {
    const char* vaddr = reinterpret_cast<const char*>(events);
    ssize_t size = tube->write(vaddr, count * objSize);

    // should never happen because of SOCK_SEQPACKET
    LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
                        "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were "
                        "sent!)",
                        count, objSize, size);

    // ALOGE_IF(size<0, "error %d sending %d events", size, count);
    return size < 0 ? size : size / static_cast<ssize_t>(objSize);
}

ssize_t BitTube::write(void const* vaddr, size_t size) {
    ssize_t err, len;
    do {
        len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
        // cannot return less than size, since we're using SOCK_SEQPACKET
        err = len < 0 ? errno : 0;
    } while (err == EINTR);
    return err == 0 ? len : -err;
}

通过调用系统函数send向与消费者关联的文件描述符FD发送信号,于是完成Vsync的分发

4.2.5 mCondition.wait(lock);

当pendingEvents为空的时候,就会调用mCondition.wait(lock);等待有新的Vsync或者新的Client进入。这个有两个逻辑。 如果UI上一直没有请求同步的话nextState = State::Idle;

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

那么wait是没有时间限制的,否则的话wait有超时时间,超时之后,会发出一个模拟的Vsync信号

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.
            const std::chrono::nanoseconds timeout =
                    mState == State::SyntheticVSync ? 16ms : 1000ms;
            if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                ...
                mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,
                                                   ++mVSyncState->count, expectedVSyncTime,
                                                   deadlineTimestamp, vsyncId));
            }
        }

也就是说mCondition.notify_all有很多场景,如果UI已经请求Vsync了,但是底层并没有VSync产生的话,会生成一个Vsync加入到pendingEvents中,进而再下一次循环中dispatch出去。

5. HWComposer

HWComposer会通过HAL接口向硬件注册回调接口,这样硬件上报的Vsync就可以转发SurfaceFlinger 来处理. HWComposer的创建是在这里:
frameworks/native/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp

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

对应的构造方法是:

HWComposer::HWComposer(const std::string& composerServiceName)
      : HWComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {}

HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer)
      : mComposer(std::move(composer)),
        ...
{}

构造的时候会同时创建一个Hwc2::impl::Composer,保存在HWComposer.mComposer字段中。这个Hwc2::impl::Composer定义在:
frameworks/native/services/surfaceflinger/DisplayHardware/ComposerHal.h

public:
    virtual ~Composer() = 0;

    virtual std::vector<IComposer::Capability> getCapabilities() = 0;
    virtual std::string dumpDebugInfo() = 0;

    virtual void registerCallback(const sp<IComposerCallback>& callback) = 0;
     ...

  }

它有一个registerCallback 注册回调

void Composer::registerCallback(const sp<IComposerCallback>& callback)
{
    android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
    auto ret = [&]() {
        if (mClient_2_4) {
            return mClient_2_4->registerCallback_2_4(callback);
        }
        return mClient->registerCallback(callback);
    }();
    if (!ret.isOk()) {
        ALOGE("failed to register IComposerCallback");
    }
}

这个里是通过mClient_2_4来注册这个callback,这个mClient_2_4就是屏幕硬件Hwbinder的客户端,它通信的另一端就是硬件厂商按照HWbinder的接口提供的一个服务,所以到这里就是与硬件的界限。通过把这个callback传递到硬件,我们就可以收到硬件上的Vsync信号。通过一层一层的回调,就会回到SurfaceFlingger实现的onComposerHalVsync方法

void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
                                        std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
   ...
    mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed);
    if (periodFlushed) {
        modulateVsync(&VsyncModulator::onRefreshRateChangeCompleted);
    }
}

它会调用mScheduler->addResyncSample添加的一个采样时间数据,这个采样数据经过一些算法处理后,会决定这个硬件的vsync是否需要上报到app,以及是否需要打开和关闭硬件的Vsync. 这个算法比较复杂,这里就不展开了。如果需要上报的话,它会把periodFlushed 这个指针设置为true

void Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
                                bool* periodFlushed) {
    bool needsHwVsync = false;
    *periodFlushed = false;
    { // Scope for the lock
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        if (mPrimaryHWVsyncEnabled) {
            needsHwVsync = mVsyncSchedule.controller->addHwVsyncTimestamp(timestamp, hwcVsyncPeriod,
                                                                          periodFlushed);
        }
    }

    if (needsHwVsync) {
        enableHardwareVsync();
    } else {
        disableHardwareVsync(false);
    }
}

当periodFlushed 设置为true时,继续执行modulateVsync(&VsyncModulator::onRefreshRateChangeCompleted);
frameworks/native/services/surfaceflinger/SurfaceFlinger.h

void modulateVsync(Handler handler, Args... args) {
        if (const auto config = (*mVsyncModulator.*handler)(args...)) {
            const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
            setVsyncConfig(*config, vsyncPeriod);
        }
    }

这里的handler实质是传入的VsyncModulator::onRefreshRateChangeCompleted,处理完刷新率变化之后执行setVsyncConfig

void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config,
                                    nsecs_t vsyncPeriod) {
    mScheduler->setDuration(mAppConnectionHandle,
                            /*workDuration=*/config.appWorkDuration,
                            /*readyDuration=*/config.sfWorkDuration);
    mScheduler->setDuration(mSfConnectionHandle,
                            /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
                            /*readyDuration=*/config.sfWorkDuration);
    mEventQueue->setDuration(config.sfWorkDuration);
}

这里通过mScheduler和EventQueue的setDuration方法做了什么事情呢?

void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds workDuration,
                            std::chrono::nanoseconds readyDuration) {
    android::EventThread* thread;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        RETURN_IF_INVALID_HANDLE(handle);
        thread = mConnections[handle].thread.get();
    }
    thread->setDuration(workDuration, readyDuration);
}

进一步调用了EventThread.setDuration

void EventThread::setDuration(std::chrono::nanoseconds workDuration,
                              std::chrono::nanoseconds readyDuration) {
    std::lock_guard<std::mutex> lock(mMutex);
    mVSyncSource->setDuration(workDuration, readyDuration);
}

进一步调用 mVSyncSource->setDuration

void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
                                 std::chrono::nanoseconds readyDuration) {
    std::lock_guard lock(mVsyncMutex);
    mWorkDuration = workDuration;
    mReadyDuration = readyDuration;

    // If we're not enabled, we don't need to mess with the listeners
    if (!mEnabled) {
        return;
    }

    mCallbackRepeater->start(mWorkDuration, mReadyDuration);
}

mCallbackRepeater的mRegistration绑定的是DispSyncSource::onVsyncCallback,因此start方法最后会执行这个onVsyncCallback

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());
void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
                                     nsecs_t readyTime) {
    VSyncSource::Callback* callback;
    {
        std::lock_guard lock(mCallbackMutex);
        callback = mCallback;
    }
    if (callback != nullptr) {
        callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
    }
}

进而执行到DispSyncSource.mCallback.onVSyncEvent方法,而DispSyncSource.mCallback的callback实质是EventThread,

EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
                         android::frametimeline::TokenManager* tokenManager,
                         InterceptVSyncsCallback interceptVSyncsCallback,
                         ThrottleVsyncCallback throttleVsyncCallback,
                         GetVsyncPeriodFunction getVsyncPeriodFunction)
      : mVSyncSource(std::move(vsyncSource)) {
        ...
    mVSyncSource->setCallback(this);
    ....
}

所以回调将进入到EventThread.onVSyncEvent方法,我们前面介绍了,EventThread是Vsync的核心类

void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
                               nsecs_t deadlineTimestamp) {
    ...

    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
                                       expectedVSyncTimestamp, deadlineTimestamp, vsyncId));
    mCondition.notify_all();
}

这里我们可以看到,调用了makeVSync生成一个Event并加入到mPendingEvents后面,然后调用mCondition.notify_all(),通知等待的线程,继续执行Event的分发方法threadMain,前面已经介绍过了,这里就不再赘述。

以后有时间再介绍关闭和打开Vsync这个逻辑,它相对比较简单。

6 总结

我们这篇文章主要介绍了Vsync在SurfaceFlinger的实现原理。

  • 在SurfaceFlingger初始化时,会向HWComposer注册回调,HWComposer会通过HWBinder向硬件测注册回调。
  • SurfaceFlinger搭建好处理Vsync的基础设施,初始化Scheduler,DispVsyncSoure以及最重要的EventThread。 EventThread的threadMain方法无限循环处理pendingEvents,对Vsync类型的Event分发到消费者,通过往消费者的FD写数据,通知APP有Vsync信号到来。pendingEvents中的消息处理完了,分发线程等待mCondition的通知。
  • 当HWComposer收到硬件通过HWBinder回调onVSyncEvent时,会通过SurfaceFlinger的onVSyncEvent最终调用到EventThread的onVSyncEvent,于是调用makeVSync生成Vsync的Event, 添加到pendingEvents,然后再调用mCondition.notify_all()唤起等待中的分发线程。

到这里SurfaceFlinger就搭建好的Vsync的基础框架,但还等待客户端的请求,这个内容将在下一篇文章中继续分析。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值