天天看點

Android幀緩沖區(Frame Buffer)硬體抽象層(HAL)子產品Gralloc的實作原理分析(1)

 前面在介紹Android系統的開機畫面時提到,Android裝置的顯示屏被抽象為一個幀緩沖區,而Android系統中的SurfaceFlinger服務就是通過向這個幀緩沖區寫入内容來繪制應用程式的使用者界面的。Android系統在硬體抽象層中提供了一個Gralloc子產品,封裝了對幀緩沖區的所有通路操作。本文将詳細分析Gralloc子產品的實作,為後續分析SurfaceFlinger服務的實作打下基礎。

        使用者空間的應用程式在使用幀緩沖區之間,首先要加載Gralloc子產品,并且獲得一個gralloc裝置和一個fb裝置。有了gralloc裝置之後,使用者空間中的應用程式就可以申請配置設定一塊圖形緩沖區,并且将這塊圖形緩沖區映射到應用程式的位址空間來,以便可以向裡面寫入要繪制的畫面的内容。最後,使用者空間中的應用程式就通過fb裝置來将前面已經準備好了的圖形緩沖區渲染到幀緩沖區中去,即将圖形緩沖區的内容繪制到顯示屏中去。相應地,當使用者空間中的應用程式不再需要使用一塊圖形緩沖區的時候,就可以通過gralloc裝置來釋放它,并且将它從位址空間中解除映射。接下來,我們就按照上述使用情景來分析Gralloc子產品的實作。

       1. Gralloc子產品的加載過程。

        每一個HAL子產品都有一個ID值,以這些ID值為參數來調用硬體抽象層提供的函數hw_get_module就可以将指定的子產品加載到記憶體來,并且獲得一個hw_module_t接口來打開相應的裝置。

        Gralloc子產品的ID值定義在hardware/libhardware/include/hardware/gralloc.h檔案中,如下所示:

#define GRALLOC_HARDWARE_MODULE_ID "gralloc"  

        函數hw_get_module實作在hardware/libhardware/hardware.c檔案中,如下所示:

/** Base path of the hal modules */  

#define HAL_LIBRARY_PATH1 "/system/lib/hw"  

#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"  

/** 

 * There are a set of variant filename for modules. The form of the filename 

 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants  

 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: 

 * 

 * led.trout.so 

 * led.msm7k.so 

 * led.ARMV6.so 

 * led.default.so 

 */  

static const char *variant_keys[] = {  

    "ro.hardware",  /* This goes first so that it can pick up a different 

                       file on the emulator. */  

    "ro.product.board",  

    "ro.board.platform",  

    "ro.arch"  

};  

static const int HAL_VARIANT_KEYS_COUNT =  

    (sizeof(variant_keys)/sizeof(variant_keys[0]));  

......  

int hw_get_module(const char *id, const struct hw_module_t **module)  

{  

    int status;  

    int i;  

    const struct hw_module_t *hmi = NULL;  

    char prop[PATH_MAX];  

    char path[PATH_MAX];  

    /* 

     * Here we rely on the fact that calling dlopen multiple times on 

     * the same .so will simply increment a refcount (and not load 

     * a new copy of the library). 

     * We also assume that dlopen() is thread-safe. 

     */  

    /* Loop through the configuration variants looking for a module */  

    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {  

        if (i < HAL_VARIANT_KEYS_COUNT) {  

            if (property_get(variant_keys[i], prop, NULL) == 0) {  

                continue;  

            }  

            snprintf(path, sizeof(path), "%s/%s.%s.so",  

                    HAL_LIBRARY_PATH1, id, prop);  

            if (access(path, R_OK) == 0) break;  

                     HAL_LIBRARY_PATH2, id, prop);  

        } else {  

            snprintf(path, sizeof(path), "%s/%s.default.so",  

                     HAL_LIBRARY_PATH1, id);  

        }  

    }  

    status = -ENOENT;  

    if (i < HAL_VARIANT_KEYS_COUNT+1) {  

        /* load the module, if this fails, we're doomed, and we should not try 

         * to load a different variant. */  

        status = load(id, path, module);  

    return status;  

}  

        函數hw_get_module依次在目錄/system/lib/hw和/vendor/lib/hw中查找一個名稱為"<MODULE_ID>.variant.so"的檔案,其中,<MODULE_ID>是一個子產品ID,而variant表示"ro.hardware"、"ro.product.board"、"ro.board.platform"和"ro.arch"四個系統屬性值之一。例如,對于Gralloc子產品來說,函數hw_get_module依次在目錄/system/lib/hw和/vendor/lib/hw中檢查是否存在以下四個檔案:

       gralloc.<ro.hardware>.so

       gralloc.<ro.product.board>.so

       gralloc.<ro.board.platform>.so

       gralloc.<ro.arch>.so

       隻要其中的一個檔案存在,  函數hw_get_module就會停止查找過程,并且調用另外一個函數load來将這個檔案加載到記憶體中來。另一方面,如果在/system/lib/hw和/vendor/lib/hw中均不存這些檔案,那麼函數hw_get_module就會在目錄/system/lib/hw中查找是否存在一個名稱為gralloc.default.so的檔案。如果存在的話,那麼也會調用函數load将它加載到記憶體中來。

本文轉自 Luoshengyang 51CTO部落格,原文連結:http://blog.51cto.com/shyluo/967056,如需轉載請自行聯系原作者

繼續閱讀