上一篇文章分析到了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機制的工作原理