2018年1月12日 星期五

從 BootAnimation 探索 SurfaceFlinger (五) 新章再開! SurfaceFlinger 與 DispSync 事件

前情提要


從 BootAnimation 的初始化到現在, 我們總共做了這幾件事情: 
1.) 透過 SurfaceComposerClient 跟 SurfaceFlinger 建立關係 (createConnection)
2.) 透過 SurfaceComposerClient 請 SurfaceFlinger 建立了一個 Layer 對象,
     在 Layer 的建構子生成了一個 BufferQueue, 它的消費者是 SurfaceFlinger,
     而生產者則回傳給了 SurfaceComposerClient
3.) SurfaceComposerClient 創建了一個 SurfaceControl, 並把生產者的角色交給它.
4.) SurfaceControl 會生成一個 Surface 對象, 並把生產者帶給它
     Surface 是本地的視窗介面,
     作為一個生產者, EGL 透過會 Surface 對象調用 dequeueBuffer 取得 GraphicBuffer 來寫入資料,
     完成寫入後再透過 queueBuffer 通知 SurfaceFlinger 有新的資料到來.

在前面的文章中, 我們只有簡單談到了 SurfaceFlinger 是作為一個 Service 被帶起, 還沒有深入的聊到它.
現在我們來看一下 SurfaceFlinger 的初始化流程:
// main_surfaceflinger.cpp
int main(int, char**) {
    ...
    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();
    ...
    // initialize before clients can connect
    flinger->init();

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

    // run in this thread
    flinger->run();

    return 0;
}

SurfaceFlinger 的建構子沒有做甚麼特別的處理,
不過不要忘記了 onFirstRef 函數, 這裡會初始化 MessageQueue (EventQueue )
前面在 createSurface 時, 我們有透過 mFlinger->postMessageSync(msg) 來傳遞 MessageCreateLayer 這個 message.
關於整個 MessageQueue 的 flow, 可以參考這張圖:


接下來我們看看 SurfaceFlinger 的 init 函數:

void SurfaceFlinger::init() {
    Mutex::Autolock _l(mStateLock);

    // initialize EGL for the default display
    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(mEGLDisplay, NULL, NULL);

    // start the EventThread
    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            vsyncPhaseOffsetNs, true, "app");
    mEventThread = new EventThread(vsyncSrc);
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, true, "sf");
    mSFEventThread = new EventThread(sfVsyncSrc);
    mEventQueue.setEventThread(mSFEventThread);

    ...

好的, 馬上又遇到了新朋友 DispSyncSource 跟 EventThread
這裡面帶入了一個 mPrimaryDispSync 參數
這是一個 DispSync 類型的變數, 建構子如下:
DispSync::DispSync() :
        mRefreshSkipCount(0),
        mThread(new DispSyncThread()) {
    
    mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);

    reset();
    beginResync();
}   

它又 new 了一個 DispSyncThread 並啟動之,
查看一下 threadLoop 的功能...
    DispSyncThread():
            mStop(false),
            mPeriod(0),
            mPhase(0),
            mWakeupLatency(0) {
    }

    virtual bool threadLoop() {
        status_t err;
        // 初始化 now 為系統時間
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        nsecs_t nextEventTime = 0;

        while (true) {
            // 有個 callback 的 vector, 後面一定會從某處取得 callbacks 並呼叫
            Vector<CallbackInvocation> callbackInvocations;

            nsecs_t targetTime = 0;

            { // Scope for lock
                Mutex::Autolock lock(mMutex);

                // 一開始是 false, 不管它
                if (mStop) {
                    return false;
                }

                // 一開始設為 0, 所以會進來等 condition
                // 看了一下會在 updateModel, addEventListener, removeEventListener 時進入
                // 又只有 updateModel 會修改到 mPeriod 的值, 所以一定是透過 updateModel 來啟動
                if (mPeriod == 0) {
                    err = mCond.wait(mMutex);
                    if (err != NO_ERROR) {
                        ALOGE("error waiting for new events: %s (%d)",
                                strerror(-err), err);
                        return false;
                    }
                    continue;
                }

                // 遍歷所有連上的 listener, 依據他們的 phase 計算出下一次 Event 到來的時間
                nextEventTime = computeNextEventTimeLocked(now);
                targetTime = nextEventTime;

                // Debug 用的參數, 可以不用管它
                bool isWakeup = false;

                // 等待 timeOut 自動喚醒, 如果是 timeOut 則標記為 isWakeup
                if (now < targetTime) {
                    err = mCond.waitRelative(mMutex, targetTime - now);

                    if (err == TIMED_OUT) {
                        isWakeup = true;
                    } else if (err != NO_ERROR) {
                        ALOGE("error waiting for next event: %s (%d)",
                                strerror(-err), err);
                        return false;
                    }
                }

                // 再次 update now
                now = systemTime(SYSTEM_TIME_MONOTONIC);

                // 遍歷全部註冊的 EventListener, 並帶入現在時刻
                // 如果他們的 NextEventTime 小於 now, 表示應該要觸發了
                callbackInvocations = gatherCallbackInvocationsLocked(now);
            }

            // 如果有 callback, 則觸發之
            if (callbackInvocations.size() > 0) {
                fireCallbackInvocations(callbackInvocations);
            }
        }

        return false;
    }

後面應該會看到有人透過 addEventListener 來註冊 Listener,
並且使用 updateModel 來啟動這個 thread.

這個 DispSync 被放入了 DispSyncSource 之中,
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
    const char* label) :
        mValue(0),
        mTraceVsync(traceVsync),
        mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
        mVsyncEventLabel(String8::format("VSYNC-%s", label)),
        mDispSync(dispSync),
        mCallbackMutex(),
        mCallback(),
        mVsyncMutex(),
        mPhaseOffset(phaseOffset),
        mEnabled(false) {}

比較重要的就是 mDispSync 與 mPhaseOffset 這兩個參數了
查看它的子函數, 果然 setPhaseOffset 會透過 mDispSync 來註冊 eventListener
另外還有一個函數 setVSyncEnabled 也可以來增加/刪除 eventListener
這裡帶入的 callback 是 static_cast<DispSync::Callback*>this,
Callback觸發的事件是 onDispSyncEvent
    virtual void onDispSyncEvent(nsecs_t when) {
        sp<VSyncSource::Callback> callback;
        {
            Mutex::Autolock lock(mCallbackMutex);
            callback = mCallback;

            if (mTraceVsync) {
                mValue = (mValue + 1) % 2;
                ATRACE_INT(mVsyncEventLabel.string(), mValue);
            }
        }

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

這裡會呼叫 mCallback成員
查看 member variable 可以發現 mCallback 這個成員會透過 setCallback 更新.
再查找之後可以發現是 EventThread::enableVSyncLocked 來設置的,
它設置 callback 之後還會註冊 listener 進去
void EventThread::enableVSyncLocked() {
#ifndef VSYNC_DIRECT_REFRESH // 我們沒有設置, 所以會進入
    // 當螢幕關閉時, mUserSoftware 才會是 true
    if (!mUseSoftwareVSync) {
        // never enable h/w VSYNC when screen is off
        if (!mVsyncEnabled) {
            mVsyncEnabled = true;
            mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
            mVSyncSource->setVSyncEnabled(true);
        }
    }
#endif
    mDebugVsyncEnabled = true;
    sendVsyncHintOnLocked();
}

這裡又把 this 給帶進來了, 我們看一下它的 onVSyncEvent:

void EventThread::onVSyncEvent(nsecs_t timestamp) {
    Mutex::Autolock _l(mLock);
    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
    mVSyncEvent[0].header.id = 0;
    mVSyncEvent[0].header.timestamp = timestamp;
    mVSyncEvent[0].vsync.count++;
    mCondition.broadcast();
}   

更新了 mVSyncEvent 的 type 與 timestamp, 並觸發了一個 mCondition.
這表示另外一邊一定會有人在等待這個 event 到來.

所以 mDispSync 的作用就是在啟動後, 每隔一段時間發出一個 event 給它的 listener 們
而目前看到 listener 是從 EventThread::enableVSyncLocked 註冊來的

回到 SurfaceFlinger, 我們現在知道有兩個 EventThread 被帶起來了,
為什麼會分成兩個呢? 其實從他們的名稱來看可見一斑:
一個是給 apps 用的 (通知每個 Layers 去畫圖)
另一個則是給 surfaceflinger 自己更新畫面用的

    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            vsyncPhaseOffsetNs, true, "app");
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, true, "sf");

在 EventThread::onFirstRef() 會啟動自身的 threadLoop(),
它在 threadLoop() 中持續等待 event (Vsync) 發生.
如果有 event 的話, 就將 event 發送給全部的 connection.
bool EventThread::threadLoop() {
    DisplayEventReceiver::Event event;
    Vector< sp<EventThread::Connection> > signalConnections;
    signalConnections = waitForEvent(&event);

    // dispatch events to listeners...
    const size_t count = signalConnections.size();
    for (size_t i=0 ; i<count ; i++) {
        const sp<Connection>& conn(signalConnections[i]);
        // now see if we still need to report this event
        status_t err = conn->postEvent(event);
        if (err == -EAGAIN || err == -EWOULDBLOCK) {
            // The destination doesn't accept events anymore, it's probably
            // full. For now, we just drop the events on the floor.
            // FIXME: Note that some events cannot be dropped and would have
            // to be re-sent later.
            // Right-now we don't have the ability to do this.
            ALOGW("EventThread: dropping event (%08x) for connection %p",
                    event.header.type, conn.get());
        } else if (err < 0) {
            // handle any other error on the pipe as fatal. the only
            // reasonable thing to do is to clean-up this connection.
            // The most common error we'll get here is -EPIPE.
            removeDisplayEventConnection(signalConnections[i]);
        }
    }
    return true;
}

剛好在第二個 EventThread 之中有建立了一個 Connection,
我們看到 mSFEventThread 會被 mEventQueue 作為它的 mEventThread 使用.

void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
    mEventThread = eventThread;
    // 生成一個 Connection, 裡面會生成 DataChannel
    mEvents = eventThread->createEventConnection();

    // 獲取 DataChannel, 並把它的 fd 加入 Looper 中
    // 這樣當 eventThread 被觸發時, Message Queue 就會收到新的 event
    mEventTube = mEvents->getDataChannel();
    mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,
            MessageQueue::cb_eventReceiver, this);
}   

sp<EventThread::Connection> EventThread::createEventConnection() const {
    return new Connection(const_cast<EventThread*>(this));
}   

// Connection 的建構子如下
EventThread::Connection::Connection(
        const sp<EventThread>& eventThread)
    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
{
}

sp<BitTube> EventThread::Connection::getDataChannel() const {
    return mChannel;
}

// 在 onFirstRef 將自己註冊給 mDisplayEventConnections
void EventThread::Connection::onFirstRef() {
    // NOTE: mEventThread doesn't hold a strong reference on us
    mEventThread->registerDisplayEventConnection(this);
}

// 這個 mDisplayEventConnections 將會在 EventThread 的 threadLoop 中使用
// 當 connection 
status_t EventThread::registerDisplayEventConnection(
        const sp<EventThread::Connection>& connection) {
    Mutex::Autolock _l(mLock);

    mDisplayEventConnections.add(connection);
    mCondition.broadcast();
    return NO_ERROR;
}

int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
    MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
    return queue->eventReceiver(fd, events);
}

int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
    ssize_t n;
    DisplayEventReceiver::Event buffer[8];
    while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
        for (int i=0 ; i<n ; i++) {
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
#if INVALIDATE_ON_VSYNC
                mHandler->dispatchInvalidate();
#else
                mHandler->dispatchRefresh();
#endif
                break;
            }
        }
    }
    return 1;
}

簡單整理一下:
MessageQueue 呼叫 mSFEventThread 生成了一個 Connection,
這個 Connection 會自動註冊進 mSFEventThread 之中.
EventThread 在 threadLoop 中等待 event 到來,
當 DispSyncSource 產生的 event 到來時, 發送給每個 Connection
Connection 收到 Event 後, 往自己的 mChannel 寫,
MessageQueue 的 Looper 就會被喚醒並且填入 Event, 並呼叫它的 callback function,
也就是從 addFd 帶進來的 MessageQueue::cb_eventReceiver (它現在被 SimpleLooperCallback 封裝起來)
在上面貼了一張 MessageQueue 是如何處理 Message 的流程圖,
在裡面 Looper 除了處理 Message 以外, 也會負責處理這些 Events, 實在是功能拔群呀 ⁽⁽ ◟(∗ ˊωˋ ∗)◞ ⁾⁾

明明只有五行 code ...為什麼分析起來會如此龐大呢... (¦3[▓▓]

下一篇, 令人熟悉的 Composer 又出現了, 鳩竟這個 Composer 是不是真的會做 Composer 該做的事情呢?
讓我們繼續....看...下....去..........

沒有留言:

張貼留言

不定參數印 log

From the UNIXProcess_md.c #ifdef DEBUG_PROCESS   /* Debugging process code is difficult; where to write debug output? */ static void deb...