原文出處——>[Android系統Surface機制的SurfaceFlinger服務的線程模型分析](http://blog.csdn.net/luoshengyang/article/details/8062945)
在前面兩篇文章中,我們分析了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渲染線程的運行模型,如下所示:
~~~
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的實現如下所示:
~~~
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的實現如下所示:
~~~
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的實現如下所示:
~~~
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的實現如下所示:
~~~
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的進程間通信請求的,如下所示:
~~~
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的進程間通信請求的,如下所示:
~~~
void SurfaceFlinger::signalEvent() {
mEventQueue.invalidate();
}
~~~
這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
前面提到,SurfaceFlinger類的成員變量mEventQueue指向的是SurfaceFlinger服務的UI渲染線程的消息隊列,這個消息隊列的類型為MessageQueue。SurfaceFlinger類的成員函數signalEvent要執行的操作便是向SurfaceFlinger服務的UI渲染線程的消息隊列發送一個類型為MessageQueue::INVALIDATE的消息,這是通過調用MessageQueue類的成員函數invalidate來實現的,如下所示:
~~~
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的實現如下所示:
~~~
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的實現如下所示:
~~~
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處理硬件幀緩沖區的睡眠事件的代碼如下所示:
~~~
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的實現,如下所示:
~~~
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的實現,如下所示:
~~~
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的實現,看看它是如何執行釋放系統顯示屏的操作的,如下所示:
~~~
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的實現如下所示:
~~~
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處理硬件幀緩沖區的喚醒事件的代碼如下所示:
~~~
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的實現,如下所示:
~~~
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的實現,看看它是如何執行獲取系統顯示屏的操作的,如下所示:
~~~
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渲染到硬件幀緩沖區中去的了,敬請關注!
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析