天天看點

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

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

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中,如下所示:

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

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

template<typename SERVICE>
class BinderService
{
public:
    static status_t publish() {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
    }
    ......
};      

      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

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

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");
    mDebug 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

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>      

      函數首先調用從父類繼承下來的成員函數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渲染線程,我們分段來閱讀:

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服務是如何管理硬體幀緩沖區時,我們就會看到這個控制台事件監控線程的建立過程。

      我們接着往下閱讀代碼:

// 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來獲得這塊匿名共享記憶體的内容。

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

// 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的實作。

      我們繼續往下閱讀代碼:

// 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();      

      這段代碼将系統主顯示屏的屬性資訊儲存在前面所建立的一塊匿名共享記憶體中,以便可以将系統主顯示屏的屬性資訊傳回給系統中的其它程序通路。

      我們再繼續往下閱讀代碼:

// 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/。

       我們再繼續往下閱讀最後一段代碼:

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服務已經啟動起來了。

繼續閱讀