Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android幀緩沖區狀態監控過程源碼分析

Android幀緩沖區狀態監控過程源碼分析

編輯:關於Android編程

SurfaceFlinger服務在啟動的時候,會創建一個線程來監控由內核發出的幀緩沖區硬件事件。每當幀緩沖區要進入睡眠狀態時,內核就會發出一個睡眠事件,這時候SurfaceFlinger服務就會執行一個釋放屏幕的操作;而當幀緩沖區從睡眠狀態喚醒時,內核就會發出一個喚醒事件,這時候SurfaceFlinger服務就會執行一個獲取屏幕的操作。

status_t SurfaceFlinger::readyToRun()
{
    ALOGI( "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");
    // we only support one display currently
    int dpy = 0;
    {
        // initialize the main display
        GraphicPlane& plane(graphicPlane(dpy));
        DisplayHardware* const hw = new DisplayHardware(this, dpy);
        plane.setDisplayHardware(hw);
    }
	...
	//啟動顯示屏睡眠/喚醒狀態監控
	hw.startSleepManagement();
	...
}
在SurfaceFlinger啟動過程中,將創建一個DisplayHardware對象,在構造DisplayHardware的父類DisplayHardwareBase對象時,會創建一個線程,用來監控硬件幀緩沖區的睡眠和喚醒事件。我們知道,在構造一個子類對象時,首先會調用父類的構造函數,因此在構造DisplayHardware對象時,首先會執行DisplayHardwareBase的構造函數:

DisplayHardwareBase::DisplayHardwareBase(const sp& flinger,
        uint32_t displayIndex) 
{
    mScreenAcquired = true;
	//創建一個幀緩存區狀態監控線程
    mDisplayEventThread = new DisplayEventThread(flinger);
}
DisplayEventThread線程用於監控硬件幀緩存區的狀態,其構造函數如下:

DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
        const sp& flinger)
    : Thread(false), mFlinger(flinger) {
}
當SurfaceFlinger服務初始化完成後,在SurfaceFlinger的readyToRun()函數最後,將調用DisplayHardware對象Hw的startSleepManagement()函數來啟動DisplayEventThread線程

void DisplayHardwareBase::startSleepManagement() const {
    if (mDisplayEventThread->initCheck() == NO_ERROR) {
        mDisplayEventThread->run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
    } else {
        ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist");
    }
}
當硬件幀緩沖區被打開時,幀緩沖區驅動程序就會創建/sys/power/wait_for_fb_sleep和/sys/power/wait_for_fb_wake文件,用來通知用戶空間顯示屏即將要進入睡眠/喚醒狀態。函數首先調用initCheck()函數來檢查/sys/power/wait_for_fb_sleep和/sys/power/wait_for_fb_wake文件是否存在,如果文件存在,則啟動DisplayEventThread線程,DisplayEventThread線程的執行過程如下:

bool DisplayHardwareBase::DisplayEventThread::threadLoop() {
	//等待硬件幀緩沖區fb進入睡眠狀態,如果fb進入睡眠,函數返回,否則函數阻塞
    if (waitForFbSleep() == NO_ERROR) {
        sp flinger = mFlinger.promote();
        ALOGD("About to give-up screen, flinger = %p", flinger.get());
		//如果硬件幀緩沖區fb進入睡眠狀態,則通知SurfaceFlinger釋放顯示屏
        if (flinger != 0) {
            flinger->screenReleased();
        }
		//等待硬件幀緩沖區fb進入喚醒狀態,如果fb被喚醒,函數返回,否則函數阻塞
        if (waitForFbWake() == NO_ERROR) {
            ALOGD("Screen about to return, flinger = %p", flinger.get());
			//如果硬件幀緩沖區fb被喚醒,則通知SurfaceFlinger獲取顯示屏
            if (flinger != 0) {
                flinger->screenAcquired();
            }
			//線程循環執行threadLoop()函數
            return true;
        }
    }
    // error, exit the thread
    return false;
}
在DisplayEventThread線程執行過程中,通過waitForFbSleep()和waitForFbWake()函數分別等待硬件幀緩沖區的睡眠/喚醒,當fb進入睡眠時,調用SurfaceFlinger的screenReleased()函數釋放顯示屏;當fb被喚醒時,調用SurfaceFlinger的screenAcquired()函數來獲取顯示屏。首先介紹fb睡眠監控過程:

status_t DisplayHardwareBase::DisplayEventThread::waitForFbSleep() {
    int err = 0;
    char buf;
	//kSleepFileName = "/sys/power/wait_for_fb_sleep";
    int fd = open(kSleepFileName, O_RDONLY, 0);
    // if the file doesn't exist, the error will be caught in read() below
    do {
		//讀取"/sys/power/wait_for_fb_sleep"文件,如果文件不存在或者正確讀取文件內容,該函數退出循環
        err = read(fd, &buf, 1);
    } while (err < 0 && errno == EINTR);
    close(fd);
    ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
    return err < 0 ? -errno : int(NO_ERROR);
}
我們知道,當硬件幀緩沖區fb進入睡眠狀態時,fb驅動程序會通過寫/sys/power/wait_for_fb_sleep文件來告知用戶空間的應用程序當前硬件幀緩沖fb的狀態,因此,DisplayEventThread線程只需讀取/sys/power/wait_for_fb_sleep文件內容就可以判斷fb是否進入睡眠狀態。當fb進入睡眠狀態時,DisplayEventThread線程就可以讀取到/sys/power/wait_for_fb_sleep文件的內容,waitForFbSleep函數返回,否則循環讀取/sys/power/wait_for_fb_sleep文件。同樣,當硬件幀緩沖區fb被喚醒時,fb驅動程序會通過寫/sys/power/wait_for_fb_wake文件來告知用戶空間的應用程序當前硬件幀緩沖fb的狀態:

status_t DisplayHardwareBase::DisplayEventThread::waitForFbWake() {
    int err = 0;
    char buf;
	//kWakeFileName  = "/sys/power/wait_for_fb_wake";
    int fd = open(kWakeFileName, O_RDONLY, 0);
    // if the file doesn't exist, the error will be caught in read() below
    do {
		//讀取"/sys/power/wait_for_fb_wake"文件,如果文件不存在或者正確讀取文件內容,該函數退出循環
        err = read(fd, &buf, 1);
    } while (err < 0 && errno == EINTR);
    close(fd);
    ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
    return err < 0 ? -errno : int(NO_ERROR);
}
當fb被喚醒時,DisplayEventThread線程就可以讀取到/sys/power/wait_for_fb_wake文件的內容,waitForFbWake函數返回,否則循環讀取/sys/power/wait_for_fb_wake文件。到此我們就知道DisplayEventThread線程是如何獲取硬件幀緩沖區fb的狀態,一旦DisplayEventThread線程監控到硬件幀緩沖區fb發生喚醒/睡眠狀態切換,那麼就會它通知SurfaceFlinger來處理。

1. 顯示屏釋放過程


當fb進入睡眠時,DisplayEventThread線程將調用SurfaceFlinger的screenReleased()函數來釋放顯示屏:

void SurfaceFlinger::screenReleased() {
    class MessageScreenReleased : public MessageBase {
        SurfaceFlinger* flinger;
    public:
        MessageScreenReleased(SurfaceFlinger* flinger) : flinger(flinger) { }
        virtual bool handler() {
            flinger->onScreenReleased();
            return true;
        }
    };
    sp msg = new MessageScreenReleased(this);
    postMessageSync(msg);
}
在Android SurfaceFlinger服務的消息循環過程源碼分析中介紹了SurfaceFlinger維護的消息循環過程。這裡定義了一種釋放顯示屏的消息類型MessageScreenReleased,並通過postMessageSync()函數向SurfaceFlinger的消息隊列同步發送一個MessageScreenReleased消息,由於發送的是一個同步消息,因此該函數將等待SurfaceFlinger的消息循環處理完該消息後才返回。當MessageScreenReleased消息被發送到SurfaceFlinger的消息隊列後,SurfaceFlinger的消息循環將調用該消息的處理函數handler(),在MessageScreenReleased消息處理函數handler()中又繼續調用SurfaceFlinger的onScreenReleased()函數來釋放顯示屏:

void SurfaceFlinger::onScreenReleased() {
    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    if (hw.isScreenAcquired()) {
		//將顯示屏釋放轉交給EventThread線程處理
        mEventThread->onScreenReleased();
		//設置DisplayHardwareBase類的成員變量mScreenAcquired為false
        hw.releaseScreen();
    }
}

函數首先調用EventThread線程的onScreenReleased()函數來喚醒EventThread線程,並且關閉VSync事件。

void EventThread::onScreenReleased() {
    Mutex::Autolock _l(mLock);
    if (!mUseSoftwareVSync) {
        // disable reliance on h/w vsync
        mUseSoftwareVSync = true;
        mCondition.broadcast();
    }
}
而當顯示屏處於睡眠狀態時,DisplayHardwareBase類的成員變量mScreenAcquired的值就會等於false,表示SurfaceFlinger服務不可以訪問顯示屏。
void DisplayHardwareBase::releaseScreen() const {
    mScreenAcquired = false;
}

2. 顯示屏獲取過程


當fb被喚醒時,DisplayEventThread線程將調用SurfaceFlinger的screenAcquired()函數來獲取顯示屏:
void SurfaceFlinger::screenAcquired() {
    class MessageScreenAcquired : public MessageBase {
        SurfaceFlinger* flinger;
    public:
        MessageScreenAcquired(SurfaceFlinger* flinger) : flinger(flinger) { }
        virtual bool handler() {
            flinger->onScreenAcquired();
            return true;
        }
    };
    sp msg = new MessageScreenAcquired(this);
    postMessageSync(msg);
}
這裡定義了一種獲取顯示屏的消息類型MessageScreenAcquired,同樣往SurfaceFlinger的消息隊列中同步發送一個MessageScreenAcquired消息,SurfaceFlinger的消息循環將調用該消息的handler()函數來處理該消息,在該消息的處理函數handler()中,調用SurfaceFlinger的onScreenAcquired()函數來獲取顯示屏:
void SurfaceFlinger::onScreenAcquired() {
    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    hw.acquireScreen();
    mEventThread->onScreenAcquired();
    // this is a temporary work-around, eventually this should be called
    // by the power-manager
    SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
    // from this point on, SF will process updates again
    repaintEverything();
}
首先調用DisplayHardware對象hw的acquireScreen()函數設置DisplayHardwareBase類的成員變量mScreenAcquired的值就會等於true,表示SurfaceFlinger服務可以訪問顯示屏。
void DisplayHardwareBase::acquireScreen() const {
    mScreenAcquired = true;
}
接著調用EventThread的onScreenAcquired()函數來喚醒EventThread線程,並打開VSync事件發送器。
void EventThread::onScreenAcquired() {
    Mutex::Autolock _l(mLock);
    if (mUseSoftwareVSync) {
        // resume use of h/w vsync
        mUseSoftwareVSync = false;
        mCondition.broadcast();
    }
}
然後調用SurfaceFlinger的turnElectronBeamOn()函數點亮顯示屏
status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode)
{
    class MessageTurnElectronBeamOn : public MessageBase {
        SurfaceFlinger* flinger;
        int32_t mode;
        status_t result;
    public:
        MessageTurnElectronBeamOn(SurfaceFlinger* flinger, int32_t mode)
            : flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
        }
        status_t getResult() const {
            return result;
        }
        virtual bool handler() {
            Mutex::Autolock _l(flinger->mStateLock);
            result = flinger->turnElectronBeamOnImplLocked(mode);
            return true;
        }
    };
    postMessageAsync( new MessageTurnElectronBeamOn(this, mode) );
    return NO_ERROR;
}
和前面SurfaceFlinger處理顯示屏的釋放、獲取類似,也是為顯示屏點亮處理定義類型為MessageTurnElectronBeamOn的消息,並向SurfaceFlinger消息隊列中發送一個該類型的消息,有一點不同的是,這裡的消息采用異步方式發送。SurfaceFlinger消息循環將調用該消息的處理函數handler來點亮顯示屏,在消息處理函數中又調用SurfaceFlinger的turnElectronBeamOnImplLocked函數來完成顯示屏的點亮處理。
status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode)
{
    DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
	//通過DisplayHardwareBase類的成員變量mScreenAcquired來判斷當前顯示屏是否可用
    if (hw.canDraw()) {
        // we're already on
        return NO_ERROR;
    }
	//是否需要顯示動畫
    if (mode & ISurfaceComposer::eElectronBeamAnimationOn) {
        electronBeamOnAnimationImplLocked();
    }
    //設置髒區域為整個屏幕大小
    mDirtyRegion.set(hw.bounds());
	//請求VSync事件
    signalTransaction();
    return NO_ERROR;
}
該函數通過調用signalTransaction()函數來請求下一次VSync事件
void SurfaceFlinger::signalTransaction() {
    mEventQueue.invalidate();
}
變量mEventQueue的類型為MessageQueue,因此這裡調用MessageQueue的invalidate()函數
void MessageQueue::invalidate() {
    mEvents->requestNextVsync();
}
在Android SurfaceFlinger對VSync信號的處理過程分析中介紹了SurfaceFlinger通過Connection來接收EventThread線程分發的VSync事件,這裡調用Connection的requestNextVsync()函數請求EventThread線程分發下一次的VSync事件。
void EventThread::Connection::requestNextVsync() {
    mEventThread->requestNextVsync(this);
}
通過喚醒EventThread線程來請求下一次VSync事件
void EventThread::requestNextVsync(const sp& connection) {
    Mutex::Autolock _l(mLock);
    if (connection->count < 0) {
        connection->count = 0;
        mCondition.broadcast();
    }
}
回到onScreenAcquired()函數,最後調用repaintEverything()函數請求刷新顯示屏。
void SurfaceFlinger::repaintEverything() {
    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    const Rect bounds(hw.getBounds());
    setInvalidateRegion(Region(bounds));
    signalTransaction();
}

DisplayHardwareBase類用來控制SurfaceFlinger服務是否能夠在顯示屏上渲染UI。當DisplayHardwareBase類的成員函數canDraw的返回值等於true時,就表示SurfaceFlinger服務可以在顯示屏上渲染系統的UI,否則就不可以。DisplayEventThreadBase類的創建一個名稱為“DisplayEventThread”的線程,用來監控fb的睡眠/喚醒狀態切換事件。這個線程循環調用DisplayEventThread類的成員函數threadLoop來監控fb的睡眠/喚醒狀態切換事件,並根據fb的狀態通知SurfaceFlinger釋放或獲取顯示屏。


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved