AndroidQ SurfaceFlinger进程对Vsync的接收与分发(下)

上一篇文章分析到了SurfaceFlinger进程接收到来自硬件的Vsync的处理流程,主要是在EventThread内部线程的threadMain函数中,这个函数中主要分析了对接收到的事件的处理,并没有分析它的来源,导致遗留了两个问题:1.mPendingEvents里的事件是怎么来的,2.setVSyncEnabled函数的具体作用

setVSyncEnabled函数的作用也分析了一部分,主要是添加或者移除监听器,它监听的是什么?是来自DispSync内部线程DispSyncThread捕捉到的Vsync,我们这篇文章要分析的是DispSyncThread对捕捉到Vsync信号之后的内部处理,DispSyncThread的threadLoop中会开启一个死循环,在捕捉到Vsync之后会通知监听器,所以本篇文章的分析分为两步:1.DispSyncThread如何捕捉Vsync,2.捕捉到Vsync之后如何通知监听器

首先来看步骤1,想要知道DispSyncThread如何捕捉Vsync必须先知道Vsync如何发送的,如何到DispSyncThread中的:

先来看看SurfaceFlinger的定义:

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

SurfaceFlinger继承BnSurfaceComposer,作为Binder Bn端,另外还实现了一个Callback,HWC2::ComposerCallback

我们来看看这个Callback定义:

//HWC2.h
class ComposerCallback {
 public:
    virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
                                   Connection connection) = 0;
    virtual void onRefreshReceived(int32_t sequenceId,
                                   hwc2_display_t display) = 0;
    virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
                                 int64_t timestamp) = 0;
    virtual ~ComposerCallback() = default;
};

注意看它定义的三个回调函数,分别对应三种事件类型,热插拔,屏幕刷新,Vsync信号,surfaceflinger实现了这三个回调方法,并且在init函数中通过如下代码最终将自己注册到了Hwc2的ComposerCallbackBridge中

mCompositionEngine->getHwComposer().registerCallback(this,
getBE().mComposerSequenceId);
来看看ComposerCallbackBridge的定义

class ComposerCallbackBridge : public Hwc2::IComposerCallback {
public:
    ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
            : mCallback(callback), mSequenceId(sequenceId) {}

    Return<void> onHotplug(Hwc2::Display display,
                           IComposerCallback::Connection conn) override
    {
        HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
        mCallback->onHotplugReceived(mSequenceId, display, connection);
        return Void();
    }

    Return<void> onRefresh(Hwc2::Display display) override
    {
        mCallback->onRefreshReceived(mSequenceId, display);
        return Void();
    }

    Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
    {
        mCallback->onVsyncReceived(mSequenceId, display, timestamp);
        return Void();
    }

我们可以看到ComposerCallbackBridge中有三个函数依次对应ComposerCallback中的三个回调函数,刚好ComposerCallbackBridge的某个函数被调用之后就会调到surfaceFlinger对应的某个回调函数中

而ComposerCallbackBridge的几个函数则是通过hal从硬件调用过来的,看不了代码也没必要进行分析,大概调用栈为:

hardware->BHwBinder->BnHwComposerCallback::onTransact->BnHwComposerCallback::_hidl_onVsync->ComposerCallbackBridge::onVsync->SurfaceFlinger::onVsyncReceived

所以SurfaceFlinger的onVsyncReceived函数最终接收的就是来自硬件的Vsync信号

继续来看看SurfaceFlinger的onVsyncReceived函数具体实现:

onVsyncReceived

void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                                     int64_t timestamp) {
    
    ......
    bool periodChanged = false;
    mScheduler->addResyncSample(timestamp, &periodChanged);
    if (periodChanged) {
        mVsyncModulator.onRefreshRateChangeDetected();
    }
}

接着调用mScheduler的addResyncSample函数

void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodChanged) {
    bool needsHwVsync = false;
    *periodChanged = false;
    { // Scope for the lock
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        if (mPrimaryHWVsyncEnabled) {
            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodChanged);
        }
    }
	.....
}

mPrimaryDispSync类型为DispSync,DispSync内部有一个线程DispSyncThread

DispSync.addResyncSample

bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) {
    ......
    mThread->updateModel(mPeriod, mPhase, mReferenceTime);
    ......
}

这个线程是surfaceFlinger进程中处理Vsync的源头,调用DispSyncThread的updateModel函数

mThread->updateModel

void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
        ......
        mCond.signal();
    }

通过C++的条件变量唤醒处于wait状态的线程

到这里第一步DispSyncThread捕捉Vsync分析完了,来看第二步,DispSyncThread的threadLoop函数

DispSyncThread.threadLoop

virtual bool threadLoop() {
        status_t err;
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        while (true) {
			....
            std::vector<CallbackInvocation> callbackInvocations;

           		.....

                if (mPeriod == 0) {
                    err = mCond.wait(mMutex);
                    if (err != NO_ERROR) {
                        
                        return false;
                    }
                    continue;
                }

                targetTime = computeNextEventTimeLocked(now);

                bool isWakeup = false;
               
                if (now < targetTime) {
                    if (targetTime == INT64_MAX) {
                        err = mCond.wait(mMutex);
                    } else {
                        
                        err = mCond.waitRelative(mMutex, targetTime - now);
                    }
				.....

                now = systemTime(SYSTEM_TIME_MONOTONIC);
				......
                callbackInvocations = gatherCallbackInvocationsLocked(now);
            }

            if (callbackInvocations.size() > 0) {
                fireCallbackInvocations(callbackInvocations);
            }
        }

        return false;
    }

DispSyncThread在启动时就会开启死循环,当没有事件时调用mCond.wait陷入wait状态,其实DispSyncThread和上一篇文章分析的EventThread内部线程是同样的工作机制,同样的死循环,依靠唤醒/等待完成所有工作,

DispSyncThread被唤醒之后,首先得到下一个Vsync信号的时间,如果大于当前时间now,则会继续等待,否则会调用gatherCallbackInvocationsLocked函数从mEventListeners中获取处理Vsync时间小于当前时间的监听器,获取之后再调用fireCallbackInvocations函数,此函数中再调用所以监听器的onDispSyncEvent函数

onDispSyncEvent这个回调函数我们上一篇文章分析过,是由DispSyncSource实现的,

DispSyncSource.onDispSyncEvent

void DispSyncSource::onDispSyncEvent(nsecs_t when) {
    VSyncSource::Callback* callback;
    {
        std::lock_guard lock(mCallbackMutex);
        callback = mCallback;
		....

    if (callback != nullptr) {
        callback->onVSyncEvent(when);
    }
}

DispSyncSource的onDispSyncEvent函数中又调用了回调函数onVSyncEvent,而onVSyncEvent这个回调则是由EventThread实现的,是在EventThread的构造函数中注册到DispSyncSource的
mVSyncSource->setCallback(this);

继续看EventThread的onVSyncEvent函数

EventThread.onVSyncEvent

void EventThread::onVSyncEvent(nsecs_t timestamp) {
    ......
    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count));
    mCondition.notify_all();
}

终于看到我们遗留的第一个问题了:mPendingEvents的事件是怎么来的?mPendingEvents中的事件是在DispSyncThread收到Vsync之后填充的,这里调用makeVSync构造了一个事件

makeVSync

DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
                                      uint32_t count) {
    DisplayEventReceiver::Event event;
    event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
    event.vsync.count = count;
    return event;
}

构造了一个DisplayEventReceiver::Event类型事件,类型为DISPLAY_EVENT_VSYNC,还有displayId,时间戳以及接收到的次数

我们可以发现VSync并不是一个实际的信号,更像是一条通知,EventThread收到通知之后自己构造一个Event,然后发送出去

VSync类型事件构造好了之后通过条件变量唤醒陷入wait状态的EventThread内部线程,这个线程的作用在前一篇文章就分析了,它会从mPendingEvents中拿到最头部事件调用dispatchEvent将事件分发给感兴趣的监听者,感兴趣的监听者即是向EventThread请求了Vsync的EventThreadConnection

dispatchEvent的实现很简单,最终就是通过gui::BitTube的sendObjects函数向mSendFd中写入数据,另一端监听了mReceiveFd的进程就能够收到消息,知道Vsync到来了,然后完成绘制工作

而我们遗留的问题2:setVSyncEnabled的作用就是开启或关闭对DispSyncThread发送的Vsync通知的监听,当我们不需要绘制UI时例如灭屏就会调用setVSyncEnabled(false)关闭监听,这样EventThread中就收不到任何Vsync事件,并通过条件变量的wait函数陷入等待

到这里通过四篇文章就大概分析完了VSync机制的工作原理

发布了49 篇原创文章 · 获赞 72 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_34211365/article/details/105239145