Android系統Surface制的SurfaceFlinger服務的線程模型分析

   在前面兩篇文章中,我們分析瞭SurfaceFlinger服務的啟動過程以及SurfaceFlinger服務初始化硬件幀緩沖區的過程。從這兩個過程可以知道,SurfaceFlinger服務在啟動的過程中,一共涉及到瞭三種類型的線程,它們分別是Binder線程、UI渲染線程和控制臺事件監控線程。在本文中,我們就將詳細分SurfaceFlinger服務的線程模型,即上述三種類型的線程是如何運行和交互的。

        從Android系統Surface制的SurfaceFlinger服務的啟動過程分析一文可以知道,SurfaceFlinger服務是在System進程的主線程中啟動的。System進程的主線程在啟動系統的關鍵服務之前,會先啟動一個Binder線程池。這樣運行在System進程中的系統關系服務就可以與其它進程執行Binder進程間通信瞭。SurfaceFlinger服務雖然是由System進程的主線程來負責啟動的,但是最終它會運行在一個獨立的線程中。我們將這個獨立的線程稱為UI渲染線程,因為它負責渲染系統的UI。

        從Android系統Surface制的SurfaceFlinger服務對幀緩沖區(Frame Buffer)的管理分析一文可以知道,SurfaceFlinger服務的UI渲染線程的啟動的時候,會對系統的硬件幀緩沖區進行初始化。在初始化的過程,又會創建另外一個線程來監控硬件幀緩沖區的睡眠/喚醒狀態切換事件。為瞭方便描述,我們這個線程稱稱為控制臺事件監控線程。

        上述的三種類型的線程的啟動順序,可以通過圖1來描述,如下所示:

 

圖1 SurfaceFlinger服務的線程模型

       從圖1就可以清楚地看到,System進程的主線程負責啟動Binder線程池,以及UI渲染線程,而UI渲染線程又負責啟動控制臺事件監控線程。在這三種類型的線程中,UI渲染線程是主角,Binder線程和控制臺事件監控線程是配角。Binder線程池是為瞭讓其它進程,例如Android應用程序進程,可以與SurfaceFlinger服務進行Binder進程間通信的,有一部分通信所執行的操作便是讓UI渲染線程更新系統的UI。控制臺事件監控線程是為瞭監控硬件幀緩沖區的睡眠/喚醒狀態切換事件的。一旦硬件幀緩沖區要進入睡眠或者喚醒狀態,控制臺事件監控線程都需要通知UI渲染線程,以便UI渲染線程可以執行關閉或者啟動顯示屏的操作。

       接下來,為瞭弄清楚SurfaceFlinger服務的線程模型,我們就首先簡要分析UI渲染線程的運行模型,接著再分析Binder線程與UI渲染線程的交互過程,最後分析控制臺事件監控線程與UI渲染線程的交互過程。

       1. UI渲染線程的運行模型

       在前面Android系統Surface機制的SurfaceFlinger服務簡要介紹和學習計劃一文中提到,SurfaceFlinger服務的UI渲染線程有一個消息隊列。當消息隊列為空時,SurfaceFlinger服務的UI渲染線程就會進入睡眠等待狀態。一旦SurfaceFlinger服務的Binder線程接收到其它進程發送過來的渲染UI的請求時,它就會往SurfaceFlinger服務的UI渲染線程的消息隊列中發送一個消息,以便可以將SurfaceFlinger服務的UI渲染線程喚醒起來執行渲染的操作。同樣,一旦SurfaceFlinger服務的控制臺事件監控線程發現硬件幀緩沖區即將要進入睡眠或者喚醒狀態時,它就會往SurfaceFlinger服務的UI渲染線程的消息隊列中發送一個消息,以便SurfaceFlinger服務的UI渲染線程可以執行凍結或者解凍顯示屏的操作。

      從前面Android系統Surface制的SurfaceFlinger服務的啟動過程分析一文又可以知道,SurfaceFlinger服務的UI渲染線程是以SurfaceFlinger類的成員函數threadLoop為線程執行體的,即SurfaceFlinger服務的UI渲染線程會不斷地循環執行SurfaceFlinger類的成員函數threadLoop。接下來,我們就通過SurfaceFlinger類的成員函數threadLoop的實現來分析SurfaceFlinger服務的UI渲染線程的運行模型,如下所示:

[cpp] 
bool SurfaceFlinger::threadLoop() 

    waitForEvent(); 
 
    // check for transactions 
    if (UNLIKELY(mConsoleSignals)) { 
        handleConsoleEvents(); 
    } 
 
    if (LIKELY(mTransactionCount == 0)) { 
        // if we're in a global transaction, don't do anything. 
        const uint32_t mask = eTransactionNeeded | eTraversalNeeded; 
        uint32_t transactionFlags = getTransactionFlags(mask); 
        if (LIKELY(transactionFlags)) { 
            handleTransaction(transactionFlags); 
        } 
    } 
 
    // post surfaces (if needed) 
    handlePageFlip(); 
 
    const DisplayHardware& hw(graphicPlane(0).displayHardware()); 
    if (LIKELY(hw.canDraw() && !isFrozen())) { 
 
#ifdef USE_COMPOSITION_BYPASS 
        if (handleBypassLayer()) { 
            unlockClients(); 
            return true; 
        } 
#endif 
 
        // repaint the framebuffer (if needed) 
        const int index = hw.getCurrentBufferIndex(); 
        GraphicLog& logger(GraphicLog::getInstance()); 
 
        logger.log(GraphicLog::SF_REPAINT, index); 
        handleRepaint(); 
 
        // inform the h/w that we're done compositing 
        logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index); 
        hw.compositionComplete(); 
 
        logger.log(GraphicLog::SF_SWAP_BUFFERS, index); 
        postFramebuffer(); 
 
        logger.log(GraphicLog::SF_REPAINT_DONE, index); 
    } else { 
        // pretend we did the post 
        hw.compositionComplete(); 
        usleep(16667); // 60 fps period 
    } 
    return true; 

        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
        從前面Android應用程序請求SurfaceFlinger服務渲染Surface的過程分析一文可以知道,SurfaceFlinger類的成員函數threadLoop的工作過程如下所示:

        1. 調用SurfaceFlinger類的成員函數waitForEvent中檢查SurfaceFlinger服務的UI渲染線程的消息隊列是否為空。如果不為空,那麼就會馬上返回來執行其它的操作,否則的話,SurfaceFlinger服務的UI渲染線程就會進入睡眠等狀態,直到被SurfaceFlinger服務的Binder線程或者控制臺事件監控線程喚醒為止。

        2. 當SurfaceFlinger服務的UI渲染線程被控制臺事件監控線程喚醒時,SurfaceFlinger類的成員變量mConsoleSignals的值就會不等於0。在這種情況下,SurfaceFlinger類的成員函數threadLoop就會調用另外一個成員函數handleConsoleEvents來處理控制臺事件。後面在分析SurfaceFlinger服務的UI渲染線程和控制臺事件監控線程的交互過程時,我們再分析這個成員函數的實現。

        3. SurfaceFlinger類的成員變量mTransactionCount用來描述SurfaceFlinger服務是否正在執行事務。如果SurfaceFlinger服務正在執行事務,那麼SurfaceFlinger類的成員變量mTransactionCount的值就會大於0。怎麼理解SurfaceFlinger服務所執行的事務是什麼呢?這些事務是用來處理系統的顯示屬性的。這些屬性劃分為兩種類型。一種類型是與整個顯示屏屬性相關的,例如屏幕旋轉方向發生瞭變化,另一外類型是與某一個應用程序的Surface相關的,例如某一個Surface的大小或者Z軸位置發生瞭變化。一般來說,每當系統的顯示屬性發生瞭變化的時候,SurfaceFlinger服務的UI渲染線程都需要馬上刷新系統UI,以便可以反映真實情況。但是,為瞭減少屏幕的閃爍,有時候可以將多個屬性變化組合成一個事務來刷新系統UI。例如,我們可以在修改瞭一個Surface的大小和Z軸位置之後,才要求SurfaceFlinger服務的UI渲染線程去刷新系統UI,這樣就可以減少一個刷新系統UI的操作。因此,隻有當SurfaceFlinger類的成員變量mTransactionCount的值的等於0的時候,,SurfaceFlinger類的成員函數threadLoop才會判斷系統的顯示屬性是否發生瞭變化。如果發生瞭變化,那麼就會調用另外一個成員函數handleTransaction來進一步處理。在接下來的一篇文章中分析SurfaceFlinger服務的UI渲染過程時,我們就詳細分析這個成員函數的實現。

        4.  SurfaceFlinger服務的UI渲染線程接下來調用SurfaceFlinger類的成員函數handlePageFlip來通知各個應用程序的Surface將接下來要渲染的圖形緩沖區設置為當前激活的圖形緩沖區,以便接下來可以渲染到硬件幀緩沖區中去。我們同樣會在接下來的一篇文章中分析SurfaceFlinger服務的UI渲染過程時,詳細分析這個成員函數的實現。

        5. 如果SurfaceFlinger服務的UI渲染線程目前隻有一個Surface需要渲染,並且SurfaceFlinger類在編譯時,指定瞭USE_COMPOSITION_BYPASS宏,那麼SurfaceFlinger類的成員函數threadLoop就會直接調用另外一個成員函數handleBypassLayer來將這個Surface直接渲染到硬件幀緩沖區中去。這是一個優化操作,避免執行接下來的Surface合成操作。

        6. 如果SurfaceFlinger服務的UI渲染線程目前有多個Surface需要渲染,或者SurfaceFlinger類在編譯時沒指定USE_COMPOSITION_BYPASS宏,那麼SurfaceFlinger類的成員函數threadLoop接下來就會調用另外一個成員函數handleRepaint來將各個Surface的圖形緩沖區合成起來,以便接下來可以渲染到硬件幀緩沖區中去。Surface的合成操作比較復雜,因為它涉及到可見性計算等。我們同樣會在接下來的一篇文章中分析SurfaceFlinger服務的UI渲染過程時,詳細分析這個成員函數的實現。

       7. 要渲染的各個Surface的圖形緩沖區被合成之後,SurfaceFlinger類的成員函數threadLoop接下來前面獲得的用來描述系統主顯示屏的DisplayHardware對象hw的成員函數compositionComplete來通知HAL層Gralloc模塊中的fb設備,以便這個fb設備可以在Surface合成操作完成時執行一些邏輯。這一步是可選的,取決於HAL層Gralloc模塊中的fb設備是否需要接收這個Surface合成完成通知。

       8. 上述步驟都執行完成之後,SurfaceFlinger類的成員函數threadLoop最後就可以調用SurfaceFlinger類的成員函數postFramebuffer來將合成後得到的圖形緩沖區渲染到硬件幀緩沖區去瞭,這樣就可以將系統的最新UI渲染出來,或者說刷新瞭系統的UI。

       在本小節中,我們隻關註第1步的處理過程,即SurfaceFlinger類的成員函數waitForEvent的實現,以便可以瞭解SurfaceFlinger服務的UI渲染線程是如何圍繞它的消息隊列來運行的。

       SurfaceFlinger類的成員函數waitForEvent的實現如下所示:

[cpp]
void SurfaceFlinger::waitForEvent() 

    while (true) { 
        nsecs_t timeout = -1; 
        const nsecs_t freezeDisplayTimeout = ms2ns(5000); 
        if (UNLIKELY(isFrozen())) { 
            // wait 5 seconds 
            const nsecs_t now = systemTime(); 
            if (mFreezeDisplayTime == 0) { 
                mFreezeDisplayTime = now; 
            } 
            nsecs_t waitTime = freezeDisplayTimeout – (now – mFreezeDisplayTime); 
            timeout = waitTime>0 ? waitTime : 0; 
        } 
 
        sp<MessageBase> msg = mEventQueue.waitMessage(timeout); 
 
        // see if we timed out 
        if (isFrozen()) { 
            const nsecs_t now = systemTime(); 
            nsecs_t frozenTime = (now – mFreezeDisplayTime); 
            if (frozenTime >= freezeDisplayTimeout) { 
                // we timed out and are still frozen 
                LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d", 
                        mFreezeDisplay, mFreezeCount); 
                mFreezeDisplayTime = 0; 
                mFreezeCount = 0; 
                mFreezeDisplay = false; 
            } 
        } 
 
        if (msg != 0) { 
            switch (msg->what) { 
                case MessageQueue::INVALIDATE: 
                    // invalidate message, just return to the main loop 
                    return; 
            } 
        } 
    } 

       這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

       在分析這個函數的實現之前,我們首先瞭解一下SurfaceFlinger類的三個成員變量mFreezeDisplay、mFreezeDisplayTime和mFreezeCount的含義。

       外部進程,例如,應用程序進程,可以請求SurfaceFlinger服務將顯示屏凍結,這時候SurfaceFlinger類的成員變量mFreezeDisplay的值就會等於true。當顯示屏被凍結時,SurfaceFlinger服務同時也會記錄被凍結的起始時間,記錄在SurfaceFlinger類的成員變量mFreezeDisplayTime中。另一方面,SurfaceFlinger服務在修改某一個Surface的顯示屬性時,例如,修改它的大小時,如果發現顯示屏此時正處於被凍結的狀態,這時候就會將SurfaceFlinger類的成員變量mFreezeCount的值增加1,表示這個Surface也需要凍結顯示屏。

       從SurfaceFlinger類的成員函數threadLoop的實現可以知道,SurfaceFlinger服務都會調用SurfaceFlinger類的另外一個成員函數isFrozen來判斷顯示屏是否處於凍結狀態。如果是的話,那麼SurfaceFlinger服務是不可以執行渲染UI的操作的。SurfaceFlinger類的成員函數isFrozen的實現如下所示:

[cpp] 
class SurfaceFlinger : 
        public BinderService<SurfaceFlinger>, 
        public BnSurfaceComposer, 
        protected Thread 

    …… 
 
private: 
    …… 
 
            inline bool isFrozen() const { 
                return (mFreezeDisplay || mFreezeCount>0) && mBootFinished; 
            } 
 
    …… 
}; 
        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.h中。
        SurfaceFlinger類的另外一個成員變量mBootFinished用來表示系統是否已經啟動完成的。從前面Android系統的開機畫面顯示過程分析一文可以知道,當系統啟動完成時,第三個開機畫面,即開動動畫,就會被停止,同時SurfaceFlinger類的成員變量mBootFinished的值會被設置為true。從SurfaceFlinger類的成員函數isFrozen的實現也可以看出,隻有當系統啟動完成之後,顯示屏才會有凍結的概念。由於在系統啟動的過程中,顯示屏都是依次被三個開機畫面獨占的,而在獨占的期間,不會出現同時去修改顯示屬性的問題,因此就不需要去凍結顯示屏。

        由於將顯示屏凍結的目的一般是為瞭修改顯示屏的顯示屬性,例如修改某一個Surface的大小或者修改顯示並的旋轉方向等,因此,通過SurfaceFlinger類的兩個成員變量mFreezeDisplay和mFreezeCount,SurfaceFlinger服務就可以將多個顯示屬性變化合並在一起去渲染UI,避免單獨為每一個顯示屬性變化執行一次UI渲染操作。單獨為每一個顯示屬性變化執行一次UI渲染操作會出現什麼情況呢?假如有兩個顯示屬性是同時發生變化的,那麼執行兩次UI渲染操作就會可能導致沖突,從而造成一些畫面上的誤差。

       理解瞭SurfaceFlinger類的三個成員變量mFreezeDisplay、mFreezeDisplayTime和mFreezeCount的含義之後,接下來我們就可以分析SurfaceFlinger類的成員函數waitForEvent的實現瞭。

       當消息隊列為空時,SurfaceFlinger服務的UI渲染線程每一次進行睡眠等待狀態的默認時間被設置為5000毫秒,保存在變量freezeDisplayTimeout中。但是如果顯示屏當前正處於凍結狀態,那麼這個等待的時間就會從默認值減去已經被凍結的時間。這樣做的目的是避免顯示屏長時間被凍結而導致UI不能被渲染,即相當於是將顯示屏的最長凍結時間設置為5000毫秒。

       最終得到的等待時間就保存在變量timeout中,接下來SurfaceFlinger類的成員函數waitForEvent就會調用成員變量mEventQueue所描述的一個消息隊列的成員函數waitMessage來檢查是否有新的消息需要處理。如果沒有,那麼SurfaceFlinger服務的UI渲染線程就會進入到睡眠等待狀態中去,直到消息隊列有新的消息需要處理或者等待超時為止。

       SurfaceFlinger服務的UI渲染線程從SurfaceFlinger類的成員變量mEventQueue所描述的一個消息隊列的成員函數waitMessage返回來時,如果有新的消息需要處理,那麼變量msg就指向這個需要處理的新消息,即變量msg的值不等於0。目前SurfaceFlinger服務的UI渲染線程隻處理一種類型為MessageQueue::INVALIDATE的消息,因此,變量msg所指向的消息的類型為MessageQueue::INVALIDATE時,SurfaceFlinger服務的UI渲染線程就會從SurfaceFlinger類的成員函數waitForEvent中返回到調用它的成員函數threadLoop中去,以便可以處理控制臺事件或者渲染UI的操作。

       註意,當SurfaceFlinger服務的UI渲染線程從SurfaceFlinger類的成員變量mEventQueue所描述的一個消息隊列的成員函數waitMessage返回來時,如果這時候顯示屏仍然處於凍結狀態,那麼SurfaceFlinger類的成員函數waitForEvent就需要檢查顯示屏的凍結時間是否已經大於等於5000毫秒。如果大於等於的話,那麼就會自動對顯示屏執行解凍操作,即分別將SurfaceFlinger類的成員變量mFreezeDisplayTime、mFreezeCount和mFreezeDisplay的值重置為0、0和false。

        SurfaceFlinger類的成員變量mEventQueue所描述的一個消息隊列的類型為MessageQueue,實現在文件frameworks/base/services/surfaceflinger/MessageQueue.cpp,它與Android應用程序線程的消息隊列的實現思路是類似的,不過會更簡單一些。簡單來說,這個消息隊列就是由一個消息列表以及一個條件變量組成。當消息列表為空時,調用MessageQueue類的成員函數waitMessage的線程就會在MessageQueue類內部的條件變量上進入睡眠等狀態。而當其它線程向這個消息隊列添加一個新消息的時候,就會通過MessageQueue類內部的條件變量來將前面正在等待的線程喚醒起來,以它可以將前面加入到它的消息隊列中的新消息取出來處理。

        至此,我們就分析完成SurfaceFlinger服務的UI渲染線程的運行模型瞭,在下一篇文章中我們還會繼續詳細分析這個線程是如何執行UI渲染操作的,接下來我們接著分析Binder線程與UI渲染線程的交互過程。

        2. Binder線程與UI渲染線程的交互過程

        前面提到,System進程在啟動SurfaceFlinger服務之前,首先會啟動一個Binder線程池。Binder線程池的啟動過程可以參考Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文。System進程中的Binder線程池啟動起來之後,其它進程,例如Android應用程序進程,就可以請求SurfaceFlinger服務來渲染系統的UI瞭。

        以Android系統的開機動畫應用程序bootanim為例,當它需要刷新自己的UI時,就會通過它所運行在的進程的SurfaceClient單例的成員函數signalServer來向SurfaceFlinger服務發送一個Binder進程間通信請求,這一點可以參考Android應用程序請求SurfaceFlinger服務渲染Surface的過程分析一文。接下來,我們就從SurfaceClient類的成員函數signalServer來分析SurfaceFlinger服務的Binder線程與UI渲染線程的交互過程。

       SurfaceClient類的成員函數signalServer的實現如下所示:

[cpp] 
class SurfaceClient : public Singleton<SurfaceClient>   
{   
    // all these attributes are constants   
    sp<ISurfaceComposer> mComposerService;   
    ……   
   
public:   
    ……   
   
    void signalServer() const {   
        mComposerService->signal();   
    }   
};   
        這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。
        SurfaceClient類的成員變量mComposerService指向的是一個類型為BpSurfaceComposer的Binder代理對象,這個Binder代理對象引用瞭SurfaceFlinger服務,因此,SurfaceClient類的成員函數signalServer實際上就是通過BpSurfaceComposer類的成員函數signal來向SurfaceFlinger服務發送一個進程間通信請求。

        BpSurfaceComposer類的成員函數signal的實現如下所示:

[cpp]
class BpSurfaceComposer : public BpInterface<ISurfaceComposer> 

public: 
    …… 
 
    virtual void signal() const 
    { 
        Parcel data, reply; 
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); 
        remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY); 
    } 
}; 
        這個函數定義在文件frameworks/base/libs/surfaceflinger_client/ISurfaceComposer.cpp中。
        從這裡就可以看出,BpSurfaceComposer類的成員函數signal所執行的操作就是向SurfaceFlinger服務發送一個類型為BnSurfaceComposer::SIGNAL的進程間通信請求,而SurfaceFlinger服務是在SurfaceFlinger類的成員函數signal中處理類型為BnSurfaceComposer::SIGNAL的進程間通信請求的,如下所示:

[cpp] 
void SurfaceFlinger::signal() const { 
    // this is the IPC call 
    const_cast<SurfaceFlinger*>(this)->signalEvent(); 

        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
        SurfaceFlinger類的成員函數signal調用瞭另外一個成員函數signalEvent來進一步處理類型為BnSurfaceComposer::SIGNAL的進程間通信請求的,如下所示:

[cpp]
void SurfaceFlinger::signalEvent() { 
    mEventQueue.invalidate(); 

       這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
       前面提到,SurfaceFlinger類的成員變量mEventQueue指向的是SurfaceFlinger服務的UI渲染線程的消息隊列,這個消息隊列的類型為MessageQueue。SurfaceFlinger類的成員函數signalEvent要執行的操作便是向SurfaceFlinger服務的UI渲染線程的消息隊列發送一個類型為MessageQueue::INVALIDATE的消息,這是通過調用MessageQueue類的成員函數invalidate來實現的,如下所示:

[cpp] 
status_t MessageQueue::invalidate() { 
    Mutex::Autolock _l(mLock); 
    mInvalidate = true; 
    mCondition.signal(); 
    return NO_ERROR; 

       這個函數定義在文件frameworks/base/services/surfaceflinger/MessageQueue.cpp中。
       MessageQueue類的成員函數invalidate並不是真的向SurfaceFlinger服務的UI渲染線程的消息隊列發送一個消息,而是將MessageQueue的類成員變量mInvalidate的值設置為true,並且通過MessageQueue類的成員變量mCondition所描述的一個條件變量來將SurfaceFlinger服務的UI渲染線程喚醒。當SurfaceFlinger服務的UI渲染線程被喚醒時,就會檢查MessageQueue的類成員變量mInvalidate是否為true。如果是的話,那麼就會獲得一個類型為MessageQueue::INVALIDATE的消息,這個消息最終是在SurfaceFlinger類的成員函數threadLoop中處理的,如前面第1部分的內容所示。

       至此,我們就分析完成SurfaceFlinger服務的Binder線程與UI渲染線程的交互過程瞭,接下來我們再分析SurfaceFlinger服務的控制臺事件監控線程與UI渲染線程的交互過程。

       3. 控制臺事件監控線程與UI渲染線程的交互過程

       從前面Android系統Surface機制的SurfaceFlinger服務對幀緩沖區(Frame Buffer)的管理分析一文可以知道,SurfaceFlinger服務的控制臺事件監控線程是以DisplayEventThread類的成員函數threadLoop為執行體的,即SurfaceFlinger服務的控制臺事件監控線程會不斷地循環調用DisplayEventThread類的成員函數threadLoop,以便可以監控硬件幀緩沖區的睡眠/喚醒狀態切換事件。

       DisplayEventThread類的成員函數threadLoop的實現如下所示:

[cpp] 
bool DisplayHardwareBase::DisplayEventThread::threadLoop() 

    int err = 0; 
    char buf; 
    int fd; 
 
    fd = open(kSleepFileName, O_RDONLY, 0); 
    do { 
      err = read(fd, &buf, 1); 
    } while (err < 0 && errno == EINTR); 
    close(fd); 
    LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno)); 
    if (err >= 0) { 
        sp<SurfaceFlinger> flinger = mFlinger.promote(); 
        LOGD("About to give-up screen, flinger = %p", flinger.get()); 
        if (flinger != 0) { 
            mBarrier.close(); 
            flinger->screenReleased(0); 
            mBarrier.wait(); 
        } 
    } 
    fd = open(kWakeFileName, O_RDONLY, 0); 
    do { 
      err = read(fd, &buf, 1); 
    } while (err < 0 && errno == EINTR); 
    close(fd); 
    LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno)); 
    if (err >= 0) { 
        sp<SurfaceFlinger> flinger = mFlinger.promote(); 
        LOGD("Screen about to return, flinger = %p", flinger.get()); 
        if (flinger != 0) 
            flinger->screenAcquired(0); 
    } 
    return true; 

        這個函數定義在文件frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp中。
        從前面Android系統Surface機制的SurfaceFlinger服務對幀緩沖區(Frame Buffer)的管理分析一文可以知道,DisplayEventThread類的成員變量kSleepFileName要麼指向文件/sys/power/wait_for_fb_sleep,要麼是指向文件/sys/android_power/wait_for_fb_sleep,而DisplayEventThread類的成員變量kWakeFileName要麼指向文件/sys/power/wait_for_fb_wake,要麼指向文件/sys/android_power/wait_for_fb_wake。

        文件/sys/power/wait_for_fb_sleep和文件/sys/android_power/wait_for_fb_sleep是用來監控硬件幀緩沖區的睡眠事件的,而文件/sys/power/wait_for_fb_wake和文件/sys/android_power/wait_for_fb_wake是用來監控硬件幀緩沖區的喚醒事件的。文件/sys/power/wait_for_fb_sleep和文件/sys/power/wait_for_fb_wake是硬件幀緩沖區控制臺提供的新式接口,而文件/sys/android_power/wait_for_fb_sleep和文件/sys/android_power/wait_for_fb_wake是件幀緩沖區控制臺提供的舊式接口。

        DisplayEventThread類的成員函數threadLoop首先是監控硬件幀緩沖區的睡眠事件,這是通過監控文件kSleepFileName的內容來實現的,即首先調用函數open來打開文件kSleepFileName,然後再調用函數read來檢查這個文件是否有內容可讀。當文件kSleepFileName有新的內容可讀時,那麼就說明硬件幀緩沖區要進入睡眠狀態瞭,這時候SurfaceFlinger服務的控制臺事件監控線程就需要通知UI渲染線程來釋放系統的顯示屏。

        DisplayEventThread類的成員變量mFlinger指向瞭系統中的SurfaceFlinger服務,因此,DisplayEventThread類的成員函數threadLoop就可以調用它的成員函數screenReleased來通知SurfaceFlinger服務的UI渲染線程來釋放系統的顯示屏。由於DisplayEventThread類的成員變量mFlinger是一個類型為SurfaceFlinger的弱指針,因此,在使用它之前,首先要調用它的成員函數promote來將它升級為一個強指針flinger。如果升級成功,那麼才說明它所指向的SurfaceFlinger服務還活著。弱指針升級為強指針的原理可以參考前面Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析一文。

        SurfaceFlinger服務的控制臺事件監控線程調用SurfaceFlinger類的成員函數screenReleased來通知UI渲染線程來釋放系統的顯示屏之後,就會通過DisplayEventThread類的成員變量mBarrier所描述的一個屏障的成員函數wait來進入到睡眠等待狀態,直到被SurfaceFlinger服務的UI渲染線程喚醒為止。接下來,我們就通過SurfaceFlinger類的成員函數screenReleased來分析SurfaceFlinger服務的UI渲染線程是如何釋放系統的顯示屏以及喚醒控制臺事件監控線程的。

        SurfaceFlinger類的成員函數screenReleased的實現如下所示:

[cpp]
void SurfaceFlinger::screenReleased(int dpy) 

    // this may be called by a signal handler, we can't do too much in here 
    android_atomic_or(eConsoleReleased, &mConsoleSignals); 
    signalEvent(); 

        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
        SurfaceFlinger類的成員函數screenReleased的實現很簡單,它首先將SurfaceFlinger類的成員變量mConsoleSignals的eConsoleReleased位設置為1,接著再通過SurfaceFlinger類的成員函數signalEvent來喚醒UI渲染線程。從前面第1部分的內容可知道,UI渲染線程被喚醒之後,就會調用SurfaceFlinger類的成員函數handleConsoleEvents來處理硬件幀緩沖區的睡眠事件。

        SurfaceFlinger類的成員函數handleConsoleEvents處理硬件幀緩沖區的睡眠事件的代碼如下所示:

[cpp] 
void SurfaceFlinger::handleConsoleEvents() 

    // something to do with the console 
    const DisplayHardware& hw = graphicPlane(0).displayHardware(); 
 
    int what = android_atomic_and(0, &mConsoleSignals); 
    …… 
 
    if (mDeferReleaseConsole && hw.isScreenAcquired()) { 
        // We got the release signal before the acquire signal 
        mDeferReleaseConsole = false; 
        hw.releaseScreen(); 
    } 
 
    if (what & eConsoleReleased) { 
        if (hw.isScreenAcquired()) { 
            hw.releaseScreen(); 
        } else { 
            mDeferReleaseConsole = true; 
        } 
    } 
 
    mDirtyRegion.set(hw.bounds()); 

        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

        SurfaceFlinger類的成員函數handleConsoleEvents處理硬件幀緩沖區睡眠事件的過程如下所示:

        1. 首先檢查SurfaceFlinger類的成員變量mDeferReleaseConsole的值是否等於true,並且系統顯示屏當前是否處於可訪問的狀態。如果均是的話,那麼就說明有一個延遲執行的釋放系統顯示屏的操作在等待執行,因此,這時候就會調用用來描述系統顯示屏的一個DisplayHardware對象的成員函數releaseScreen來釋放系統顯示屏,並且將SurfaceFlinger類的成員變量mDeferReleaseConsole的值設置為false,表示這個延遲執行的釋放系統顯示屏的操作已經被執行瞭。

        2  接著檢查系統顯示屏當前是否處於可訪問的狀態。如果是的話,那麼就直接調用用來描述系統顯示屏的一個DisplayHardware對象的成員函數releaseScreen來釋放系統顯示屏,否則的話,就會將SurfaceFlinger類的成員變量mDeferReleaseConsole的值設置為true,表示要延遲執行一個釋放系統顯示屏的操作,因為系統顯示屏當前是處於釋放的狀態的。

        3. 最後將系統顯示屏的臟區域mDirtyRegion設置為整個顯示屏的大小,表示接下來要刷新整個顯示屏的UI,這是因為硬件幀緩沖區的狀態發生瞭變化,即要從喚醒狀態進入睡眠狀態瞭。

        判斷系統顯示屏是否處於可訪問狀態是通過調用DisplayHardware類的成員函數isScreenAcquired來實現的,而DisplayHardware類的成員函數isScreenAcquired是從父類DisplayHardwareBase類繼承下來的,因此,接下來我們就繼續分析DisplayHardwareBase類的成員函數isScreenAcquired的實現,如下所示:

[cpp]
bool DisplayHardwareBase::isScreenAcquired() const 

    return mScreenAcquired; 

       這個函數定義在文件frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp中。
       當硬件幀緩沖區處於喚醒狀態時,SurfaceFlinger服務就可以訪問系統顯示屏,而硬件幀緩沖區處於是否處於喚醒狀態是記錄在DisplayHardwareBase類的成員變量mScreenAcquired中的,因此,當DisplayHardwareBase類的成員變量mScreenAcquired中的值等於true時,就表示SurfaceFlinger服務可以訪問系統顯示屏。

       釋放系統顯示屏的操作是通過調用DisplayHardware類的成員函數releaseScreen來實現的,而DisplayHardware類的成員函數releaseScreen是從父類DisplayHardwareBase類繼承下來的,因此,接下來我們就繼續分析DisplayHardwareBase類的成員函數releaseScreen的實現,如下所示:

[cpp]
void DisplayHardwareBase::releaseScreen() const 

    status_t err = mDisplayEventThread->releaseScreen(); 
    if (err >= 0) { 
        mScreenAcquired = false; 
    } 

       這個函數定義在文件frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp中。
       DisplayHardwareBase類的成員函數releaseScreen首先調用其成員變量mDisplayEventThread所描述的一個控制臺事件監控線程的成員函數releaseScreen來執行釋放系統顯示屏的操作。如果釋放成功,那麼接下來就會繼續將DisplayHardwareBase類的成員變量mScreenAcquired的值設置為false,以表示系統顯示屏處於不可訪問狀態。

       DisplayHardwareBase類的成員變量mDisplayEventThread的類型為DisplayEventThread,因此,接下來我們就繼續分析DisplayEventThread的成員函數releaseScreen的實現,看看它是如何執行釋放系統顯示屏的操作的,如下所示:

[cpp] 
status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const 

    mBarrier.open(); 
    return NO_ERROR; 

       這個函數定義在文件frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp中。
       DisplayEventThread類的成員函數releaseScreen的實現很簡單,它隻是將睡眠其成員變量mBarrier所描述的一個屏障的線程喚醒。從前面的描述可以知道,當前正在執行的DisplayEventThread類的成員函數releaseScreen的線程為SurfaceFlinger服務的UI渲染線程,而正在DisplayEventThread類成員變量mBarrier所描述的一個屏障的線程為SurfaceFlinger服務的控制臺事件監控線程。因此,經過這一步之後,SurfaceFlinger服務的控制臺事件監控線程就被喚醒瞭。

       SurfaceFlinger服務的控制臺事件監控線程被喚醒之後,回到DisplayEventThread類的成員函數threadLoop中,我們繼續分析它是如何監控硬件幀緩沖區的喚醒事件的。

       DisplayEventThread類的成員函數threadLoop是通過監控文件kWakeFileName的內容來監控硬件幀緩沖區的喚醒事件的,即首先調用函數open來打開文件kWakeFileName,然後再調用函數read來檢查這個文件是否有內容可讀。當文件kWakeFileName有新的內容可讀時,那麼就說明硬件幀緩沖區要進入喚醒狀態瞭,這時候SurfaceFlinger服務的控制臺事件監控線程就需要通知UI渲染線程來獲取系統的顯示屏,即將系統的顯示屏的狀態設置為可訪問。

       前面提到,DisplayEventThread類的成員變量mFlinger指向瞭系統中的SurfaceFlinger服務,因此,DisplayEventThread類的成員函數threadLoop就可以調用它的成員函數screenAcquired來通知SurfaceFlinger服務的UI渲染線程來將獲取系統的顯示屏。

       SurfaceFlinger類的成員函數screenAcquired的實現如下所示:

[cpp] 
void SurfaceFlinger::screenAcquired(int dpy) 

    // this may be called by a signal handler, we can't do too much in here 
    android_atomic_or(eConsoleAcquired, &mConsoleSignals); 
    signalEvent(); 

        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
        SurfaceFlinger類的成員函數screenAcquired的實現很簡單,它首先將SurfaceFlinger類的成員變量mConsoleSignals的eConsoleAcquired位設置為1,接著再通過SurfaceFlinger類的成員函數signalEvent來喚醒UI渲染線程。從前面第1部分的內容可知道,UI渲染線程被喚醒之後,就會調用SurfaceFlinger類的成員函數handleConsoleEvents來處理硬件幀緩沖區的喚醒事件。
        SurfaceFlinger類的成員函數handleConsoleEvents處理硬件幀緩沖區的喚醒事件的代碼如下所示:
[cpp] 
void SurfaceFlinger::handleConsoleEvents() 

    // something to do with the console 
    const DisplayHardware& hw = graphicPlane(0).displayHardware(); 
 
    int what = android_atomic_and(0, &mConsoleSignals); 
    if (what & eConsoleAcquired) { 
        hw.acquireScreen(); 
        // this is a temporary work-around, eventually this should be called 
        // by the power-manager 
        SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode); 
    } 
 
    …… 
 
    mDirtyRegion.set(hw.bounds()); 

        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
        SurfaceFlinger類的成員函數handleConsoleEvents處理硬件幀緩沖區喚醒事件的過程如下所示:
        1.  首先調用用來描述系統顯示屏的一個DisplayHardware對象的成員函數acquireScreen來將系統顯示屏的狀態設置為可訪問。
        2. 接著再調用SurfaceFlinger類的靜態成員函數turnElectronBeamOn來點亮屏幕。在點亮屏幕的時候,通過參數mElectronBeamAnimationMode來表示要顯示一個屏幕點亮動畫。
        3. 最後將系統顯示屏的臟區域mDirtyRegion設置為整個顯示屏的大小,表示接下來要刷新整個顯示屏的UI,這是因為硬件幀緩沖區的狀態發生瞭變化,即要從睡眠狀態進入喚醒狀態瞭。
        將系統顯示屏的狀態設置為可訪問是通過調用DisplayHardware類的成員函數acquireScreen來實現的,而DisplayHardware類的成員函數acquireScreen是從父類DisplayHardwareBase類繼承下來的,因此,接下來我們就繼續分析DisplayHardwareBase類的成員函數acquireScreen的實現,如下所示:
[cpp] 
void DisplayHardwareBase::acquireScreen() const 

    status_t err = mDisplayEventThread->acquireScreen(); 
    if (err >= 0) { 
        mScreenAcquired = true; 
    } 

       這個函數定義在文件frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp中。
       DisplayHardwareBase類的成員函數acquireScreen首先調用其成員變量mDisplayEventThread所描述的一個控制臺事件監控線程的成員函數acquireScreen來執行獲取系統顯示屏的操作。如果獲取成功,那麼接下來就會繼續將DisplayHardwareBase類的成員變量mScreenAcquired的值設置為true,以表示系統顯示屏處於可訪問狀態。
       DisplayHardwareBase類的成員變量mDisplayEventThread的類型為DisplayEventThread,它的成員函數acquireScreen是從父類DisplayEventThreadBase繼承下來的,因此,接下來我們就繼續分析DisplayEventThreadBase的成員函數acquireScreen的實現,看看它是如何執行獲取系統顯示屏的操作的,如下所示:
[cpp] 
class DisplayHardwareBase 

    …… 
 
private: 
    class DisplayEventThreadBase : public Thread { 
        …… 
    public: 
        …… 
 
        virtual status_t acquireScreen() const { return NO_ERROR; }; 
        …… 
    }; 
 
    …… 
}; 
       這個函數定義在文件frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h中。
       從前面的描述可以知道,當前正在執行的DisplayEventThreadBase類的成員函數acquireScreen的線程為SurfaceFlinger服務的UI渲染線程,由於硬件幀緩沖區喚醒之後,它就可以自動地獲得系統的顯示屏瞭,並且它不需要與SurfaceFlinger服務的控制臺事件監控線程進行交互,因此,DisplayEventThreadBase類的成員函數acquireScreen什麼也不用做,直接返回一個成功碼NO_ERROR給調用者就可以瞭。
       至此,我們就分析完成SurfaceFlinger服務的控制臺事件監控線程與UI渲染線程的交互過程瞭,整個SurfaceFlinger服務的線程模型也分析完成瞭。理解瞭SurfaceFlinger服務的線程模型之後,在接下來的一篇文章中,我們就可以集中火力來分析SurfaceFlinger服務的UI渲染線程是如何將系統UI渲染到硬件幀緩沖區中去的瞭,敬請關註!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。