Android系統Surface制的SurfaceFlinger服務的啟動過程分析

  在前面一篇文章中,我們簡要介紹瞭Android系統Surface機制中的SurfaceFlinger服務。SurfaceFlinger服務是在System進程中啟動的,並且負責統一管理設備的幀緩沖區。SurfaceFlinger服務在啟動的過程中,會創建兩個線程,其中一個線程用來監控控制臺事件,而另外一個線程用來渲染系統的UI。在本文中,我們就將詳細分析SurfaceFlinger服務的啟動過程。

        從前面Android系統進程Zygote啟動過程的源代碼分析一文可以知道,System進程是由Zygote進程啟動的,並且是以Java層的SystemServer類的靜態成員函數main為入口函數的。因此,接下來我們就從SystemServer類的靜態成員函數main開始,分析SurfaceFlinger服務的啟動過程,如圖1所示。

 

圖1 SurfaceFlinger服務的啟動過程

       SurfaceFlinger服務的啟動過程可以劃分為8個步驟,接下來我們就詳細分析每一個步驟。

       Step 1. SystemServer.main

[java]
public class SystemServer 

    …… 
 
    native public static void init1(String[] args); 
 
    public static void main(String[] args) { 
        …… 
 
        System.loadLibrary("android_servers"); 
        init1(args); 
    } 
 
    …… 

        這個函數定義在文件frameworks/base/services/java/com/android/server/SystemServer.java中。
        SystemServer類的靜態成員函數main首先將android_servers庫加載到System進程中來,接著調用另外一個靜態成員函數init1來啟動那些使用C++語言來實現的系統服務。

        SystemServer類的靜態成員函數init1是一個JNI方法,它是由C++層的函數android_server_SystemServer_init1來實現的,接下來我們就繼續分析它的實現。

        Step 2. SystemServer.init1

[cpp]
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) 

    system_init(); 

       這個函數定義在文件frameworks/base/services/jni/com_android_server_SystemServer.cpp 中。
       SystemServer類的靜態成員函數init1調用另外一個函數system_init來啟動那些使用C++語言來實現的系統服務,它的實現在文件frameworks/base/cmds/system_server/library/system_init.cpp中,如下所示:

[cpp]
extern "C" status_t system_init() 

    LOGI("Entered system_init()"); 
 
    sp<ProcessState> proc(ProcessState::self()); 
    …… 
 
    char propBuf[PROPERTY_VALUE_MAX]; 
    property_get("system_init.startsurfaceflinger", propBuf, "1"); 
    if (strcmp(propBuf, "1") == 0) { 
        // Start the SurfaceFlinger 
        SurfaceFlinger::instantiate(); 
    } 
 
    …… 
 
    if (proc->supportsProcesses()) { 
        LOGI("System server: entering thread pool.\n"); 
        ProcessState::self()->startThreadPool(); 
        IPCThreadState::self()->joinThreadPool(); 
        LOGI("System server: exiting thread pool.\n"); 
    } 
    return NO_ERROR; 

       函數首先獲得System進程中的一個ProcessState單例,並且保存在變量proc中,後面會通過調用它的成員函數supportsProcesses來判斷系統是否支持Binder進程間通信機制。我們知道,在Android系統中,每一個需要使用Binder進程間通信機制的進程內部都有一個ProcessState單例,它是用來和Binder驅動程序建立連接的,具體可以參考Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文。
       函數接下來就檢查系統中是否存在一個名稱為“system_init.startsurfaceflinger”的屬性。如果存在的話,就將它的值獲取回來,並且保存在緩沖區proBuf中。如果不存在的話,那麼函數property_get就會將緩沖區proBuf的值設置為“1”。當緩沖區proBuf的值等於“1”的時候,就表示需要在System進程中將SurfaceFlinger服務啟動起來,這是通過調用SurfaceFlinger類的靜態成員函數instantiate來實現的。

       函數最後檢查系統是否支持Binder進程間通信機制。如果支持的話,那麼接下來就會調用當前進程中的ProcessState單例的成員函數startThreadPool來啟動一個Binder線程池,並且調用當前線程中的IPCThreadState單例來將當前線程加入到前面所啟動的Binder線程池中去。從前面Android系統進程Zygote啟動過程的源代碼分析和Android應用程序進程啟動過程的源代碼分析兩篇文章可以知道,System進程前面在初始化運行時庫的過程中,已經調用過當前進程中的ProcessState單例的成員函數startThreadPool來啟動Binder線程池瞭,因此,這裡其實隻是將當前線程加入到這個Binder線程池中去。有瞭這個Binder線程池之後,SurfaceFlinger服務在啟動完成之後,就可以為系統中的其他組件或者進程提供服務瞭。

       假設系統存在一個名稱為“system_init.startsurfaceflinger”的屬性,並且它的值等於“1”,接下來我們就繼續分析SurfaceFlinger類的靜態成員函數instantiate的實現,以便可以瞭解SurfaceFlinger服務的啟動過程。由於SurfaceFlinger類的靜態成員函數instantiate是從父類BinderService繼承下來的,因此,接下來我們要分析的實際上是BinderService類的靜態成員函數instantiate的實現。

       Step 3. BinderService.instantiate

[cpp] 
template<typename SERVICE> 
class BinderService 

public: 
    …… 
 
    static void instantiate() { publish(); } 
 
    …… 
}; 
       這個函數定義在文件frameworks/base/include/binder/BinderService.h中。
       BinderService類的靜態成員函數instantiate的實現很簡單,它隻是調用BinderService類的另外一個靜態成員函數publish來繼續執行啟動SurfaceFlinger服務的操作。

       Step 4. BinderService.publish

[cpp]
template<typename SERVICE> 
class BinderService 

public: 
    static status_t publish() { 
        sp<IServiceManager> sm(defaultServiceManager()); 
        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE()); 
    } 
 
    …… 
}; 
       這個函數定義在文件frameworks/base/include/binder/BinderService.h中。
       BinderService是一個模板類,它有一個模板參數SERVICE。當BinderService類被SurfaceFlinger類繼承時,模板參數SERVICE的值就等於SurfaceFlinger。因此,BinderService類的靜態成員函數publish所執行的操作就是創建一個SurfaceFlinger實例,用來作為系統的SurfaceFlinger服務,並且將這個服務註冊到Service Manager中去,這樣系統中的其它組件或者進程就可以通過Service Manager來獲得SurfaceFlinger服務的Binder代理對象,進而使用它所提供的服務。Binder進程間通信機制中的服務對象的註冊過程可以參考Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文。

       接下來,我們就繼續分析SurfaceFlinger服務的創建過程。

       Step 5. new SurfaceFlinger

[cpp] 
SurfaceFlinger::SurfaceFlinger() 
    :   BnSurfaceComposer(), Thread(false), 
        …… 

    init(); 

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

       從前面Android系統Surface機制的SurfaceFlinger服務簡要介紹和學習計劃一文可以知道,SurfaceFlinger類繼承瞭BnSurfaceComposer類,而後者是一個實現瞭ISurfaceComposer接口的Binder本地對象類。此外,SurfaceFlinger類還繼承瞭Thread類,後者是用來創建一個線程的,這個線程就是我們在Android系統Surface機制的SurfaceFlinger服務簡要介紹和學習計劃一文中提到的UI渲染線程,它的線程執行體函數為SurfaceFlinger類的成員函數threadLoop。後面在分析SurfaceFlinger服務渲染UI的過程時,我們再分析SurfaceFlinger類的成員函數threadLoop的實現。註意,在初始化SurfaceFlinger的父類Thread時,傳進去的參數為false,表示先不要將SurfaceFlinger服務的UI渲染線程啟動起來,等到後面再啟動。

       SurfaceFlinger服務在創建的過程中,會調用SurfaceFlinger類的成員函數init來執行初始化的操作,接下來,我們就繼續分析它的實現。

       Step 6. SurfaceFlinger.init

[cpp]
void SurfaceFlinger::init() 

    LOGI("SurfaceFlinger is starting"); 
 
    // debugging stuff… 
    char value[PROPERTY_VALUE_MAX]; 
    property_get("debug.sf.showupdates", value, "0"); 
    mDebugRegion = atoi(value); 
    property_get("debug.sf.showbackground", value, "0"); 
    mDebugBackground = atoi(value); 
 
    LOGI_IF(mDebugRegion,       "showupdates enabled"); 
    LOGI_IF(mDebugBackground,   "showbackground enabled"); 

        這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
        SurfaceFlinger類的成員函數init的實現很簡單,它分別獲得系統中兩個名稱為“debug.sf.showupdates”和“debug.sf.showbackground”的屬性的值,並且分別保存在SurfaceFlinger類的成員變量mDebugRegion和mDebugBackground中。這兩個成員變量是與調試相關的,我們不關心。

        這一步執行完成之後,返回到前面的Step 4中,即BinderService類的靜態成員函數publish中,這時候在前面的Step 5中所創建的一個SurfaceFlinger實例就會被註冊到Service Manager中,這是通過調用Service Manager的Binder代理對象的成員函數addService來實現的。由於Service Manager的Binder代理對象的成員函數addService的第二個參數是一個類型為IBinder的強指針引用。從前面Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析一文可以知道,當一個對象第一次被一個強指針引用時,那麼這個對象的成員函數onFirstRef就會被調用。因此,接下來前面所創建的SurfaceFlinger實例的成員函數onFirstRef就會被調用,以便可以繼續執行初始化操作。

        Step 7. SurfaceFlinger.onFirstRef

[cpp] 
void SurfaceFlinger::onFirstRef() 

    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY); 
 
    // Wait for the main thread to be done with its initialization 
    mReadyToRunBarrier.wait(); 
}<span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space: normal;"> 
</span></span> 
       這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

       函數首先調用從父類繼承下來的成員函數run來啟動一個名秒為“SurfaceFlinger”的線程,用來執行UI渲染操作。這就是前面我們所說的UI渲染線程瞭。這個UI渲染線程創建完成之後,首先會調用SurfaceFlinger類的成員函數readyToRun來執行一些初始化操作,接著再循環調用SurfaceFlinger類的成員函數threadLoop來作為線程的執行體。

       mReadyToRunBarrier是SurfaceFlinger類的一個成員變量,它的類型是Barrier,用來描述一個屏障,是通過條件變量來實現的。我們可以把它看作是一個線程同步工具,即阻塞當前線程,直到SurfaceFlinger服務的UI渲染線程執行完成初始化操作為止。

       接下來,我們就繼續分析SurfaceFlinger類的成員函數readyToRun的實現,以便可以瞭解SurfaceFlinger服務的UI渲染線程的初始化過程。

       Step 8. SurfaceFlinger.oreadyToRun

       這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp文件中,用來初始化SurfaceFlinger服務的UI渲染線程,我們分段來閱讀:

[cpp] 
status_t SurfaceFlinger::readyToRun() 

    LOGI(   "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); 
    } 
        這段代碼首先創建瞭一個DisplayHardware對象hw,用來描述設備的顯示屏,並且用這個DisplayHardware對象來初始化SurfaceFlinger類的成員變量mGraphicPlanes所描述的一個GraphicPlane數組的第一個元素。在DisplayHardware對象hw的創建過程中,會創建另外一個線程,用來監控控制臺事件,即監控硬件幀緩沖區的睡眠和喚醒事件。在後面一篇文章中介紹SurfaceFlinger服務是如何管理硬件幀緩沖區時,我們就會看到這個控制臺事件監控線程的創建過程。
       我們接著往下閱讀代碼:

[cpp]
// create the shared control-block 
mServerHeap = new MemoryHeapBase(4096, 
        MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap"); 
LOGE_IF(mServerHeap==0, "can't create shared memory dealer"); 
 
mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase()); 
LOGE_IF(mServerCblk==0, "can't get to shared control block's address"); 
 
new(mServerCblk) surface_flinger_cblk_t; 
       這段代碼首先創建瞭一塊大小為4096,即4KB的匿名共享內存,接著將這塊匿名共享內存結構化為一個surface_flinger_cblk_t對象來訪問。這個surface_flinger_cblk_t對象就保存在SurfaceFlinger類的成員變量mServerCblk中。
       這塊匿名共享內存用來保存設備顯示屏的屬性信息,例如,寬度、高度、密度和每秒多少幀等信息,後面我們就會看到這塊匿名共享內存的初始化過程。為什麼會使用匿名共享內存來保存設備顯示屏的屬性信息呢?這是為瞭方便將這些信息傳遞給系統中的其它進程訪問的。系統中的其它進程可以通過調用調用SurfaceFlinger服務的代理對象的成員函數getCblk來獲得這塊匿名共享內存的內容。

       我們再接著往下閱讀代碼:

[cpp]
// initialize primary screen 
// (other display should be initialized in the same manner, but 
// asynchronously, as they could come and go. None of this is supported 
// yet). 
const GraphicPlane& plane(graphicPlane(dpy)); 
const DisplayHardware& hw = plane.displayHardware(); 
const uint32_t w = hw.getWidth(); 
const uint32_t h = hw.getHeight(); 
const uint32_t f = hw.getFormat(); 
hw.makeCurrent(); 
        這段代碼首先獲得SurfaceFlinger類的成員變量mGraphicPlanes所描述的一個GraphicPlane數組的第一個元素plane,接著再設置它的寬度、長度和像素格式等作息,最後再調用它裡面的一個DisplayHardware對象hw的成員函數makeCurrent來將它作為系統的主顯示屏。這個DisplayHardware對象hw是在前面第一段代碼中創建的,在創建的過程中,它會執行一些初始化操作,這裡將它設置為系統主顯示屏之後,後面就可以將系統的UI渲染在它上面瞭。在後面一篇文章中介紹SurfaceFlinger服務是如何管理硬件幀緩沖區時,我們再分析DisplayHardware類的成員函數makeCurrent的實現。
       我們繼續往下閱讀代碼:

[cpp] 
// initialize the shared control block 
mServerCblk->connected |= 1<<dpy; 
display_cblk_t* dcblk = mServerCblk->displays + dpy; 
memset(dcblk, 0, sizeof(display_cblk_t)); 
dcblk->w            = plane.getWidth(); 
dcblk->h            = plane.getHeight(); 
dcblk->format       = f; 
dcblk->orientation  = ISurfaceComposer::eOrientationDefault; 
dcblk->xdpi         = hw.getDpiX(); 
dcblk->ydpi         = hw.getDpiY(); 
dcblk->fps          = hw.getRefreshRate(); 
dcblk->density      = hw.getDensity(); 
       這段代碼將系統主顯示屏的屬性信息保存在前面所創建的一塊匿名共享內存中,以便可以將系統主顯示屏的屬性信息返回給系統中的其它進程訪問。
       我們再繼續往下閱讀代碼:

[cpp] 
// Initialize OpenGL|ES 
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 
glPixelStorei(GL_PACK_ALIGNMENT, 4); 
glEnableClientState(GL_VERTEX_ARRAY); 
glEnable(GL_SCISSOR_TEST); 
glShadeModel(GL_FLAT); 
glDisable(GL_DITHER); 
glDisable(GL_CULL_FACE); 
 
const uint16_t g0 = pack565(0x0F,0x1F,0x0F); 
const uint16_t g1 = pack565(0x17,0x2f,0x17); 
const uint16_t textureData[4] = { g0, g1, g1, g0 }; 
glGenTextures(1, &mWormholeTexName); 
glBindTexture(GL_TEXTURE_2D, mWormholeTexName); 
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, 
        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData); 
 
glViewport(0, 0, w, h); 
glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
glOrthof(0, w, h, 0, 0, 1); 
        這段代碼用來初始化OpenGL庫,因為SurfaceFlinger服務是通過OpenGL庫提供的API來渲染系統的UI的。這裡我們就不詳細分析OpenGL庫的初始化過程中,有興趣的讀者可以參考官方網站:http://cn.khronos.org/。
        我們再繼續往下閱讀最後一段代碼:

[cpp] 
    LayerDim::initDimmer(this, w, h); 
 
    mReadyToRunBarrier.open(); 
 
    /*
     *  We're now ready to accept clients…
     */ 
 
    // start boot animation 
    property_set("ctl.start", "bootanim"); 
 
    return NO_ERROR; 

        這段代碼做瞭三件事情。
        第一件事情是調用LayerDim類的靜態成員函數initDimmer來初始化LayerDim類。LayerDim類是用來描述一個具有顏色漸變功能的Surface的,這種類型的Surface與普通的Surface不一樣,前者是在後者的基礎上創建和渲染的。

        第二件事情是調用SurfaceFlinger類的成員變量mReadyToRunBarrier所描述的一個屏障的成員函數open來告訴System進程的主線程,即在前面的Step 7中正在等待的線程,SurfaceFlinger服務的UI渲染線程已經創建並且初始化完成瞭,這時候System進程的主線程就可以繼續向前執行其它操作瞭。

       第三件事情是調用函數property_set來設置系統中名稱為“ctl.start”的屬性,即將它的值設置為“bootanim”。從前面Android系統的開機畫面顯示過程分析一文可以知道,ctl.start是Android系統的一個控制屬性,當它的值等於““bootanim”的時候,就表示要啟動Android系統的開機動畫。從這裡就可以看出,當我們看到Android系統的開機動畫時,就說明Android系統的SurfaceFlinger服務已經啟動起來瞭。

       至此,我們就分析完成SurfaceFlinger服務的啟動過程中瞭。在分析過程中,有兩個比較重要的知識點:第一個知識點是系統主顯示屏的創建和初始化過程,第二個知識點是UI渲染線程的執行過程。在接下來的第一篇文章中,我們將詳細分析第一個知識點。在分析第一個知識點的過程中,會涉及到SurfaceFlinger服務的控制臺事件監控線程的創建過程,因此,結合Step 2提到的Binder線程,以及Step 7提到的UI渲染線程,我們將在接下來的第二篇文章中,綜合描述SurfaceFlinger服務的線程協作模型。有瞭前面的基礎知識之後,在接下來的第三篇文章中,我們就將詳細分析第二個知識點。敬請關註!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *