Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的HAL相關庫搜索機制和原理學習

Android中的HAL相關庫搜索機制和原理學習

編輯:關於Android編程

本文均屬自己閱讀源碼的點滴總結,轉賬請注明出處謝謝。

歡迎和大家交流。qq:1037701636 email:[email protected]

Android源碼版本Version:4.2.2; 硬件平台 全志A31

在介紹FrameWork是不得不提的是HAL(硬件抽象層)一般是用來和特點的硬件平台進行交互的,所以不同的android平台主要的區別也就是在這個部分,HAL的好處在於一個FrameWork可以調用不同的HAL,只需要相關的HAL滿足一定接口規范即可。另一方面HAL的好處是可以屏蔽相關對底層硬件操作的應用代碼。

網上對HAL的介紹內容已經很多,這裡就簡單和大家分享我所深入去了解的HAL層的相關規范。

核心的幾個API:hw_get_module(), hw_get_module_by_class(), load()就這麼簡單,核心在hw_get_module_by_class(),來看其實現的過程代碼:

int hw_get_module_by_class(const char *class_id, const char *inst,
                           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];
    char name[PATH_MAX];

    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, 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

step1:關注變量variant_keys, 通過系統屬性獲取函數property_get()來獲取下面4個屬性變量在內存的系統屬性中維護的數值(其中系統屬性的創建和維護主要由init進程來完成)

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"
};

先來看ro.hardware,它一般是指定了系統板級的硬件如我這裡的sun6i, 那這個屬性變量在何處設置呢,首先出現的地方是在init進程裡面,依次調用如下:

1.get_hardware_name()——> fd = open("/proc/cpuinfo", O_RDONLY):搜索cpuinfo裡面的hardware字段,有的話就保存在hardware中

2.process_kernel_cmdline——>export_kernel_boot_props():這裡會對boot啟動時設置的屬性值查詢,對hardware有如下代碼:

 /* if this was given on kernel command line, override what we read
     * before (e.g. from /proc/cpuinfo), if anything */
    pval = property_get("ro.boot.hardware");
    if (pval)
        strlcpy(hardware, pval, sizeof(hardware));
    property_set("ro.hardware", hardware);

如果在boot時設置了ro.boot.hardware那麼hardware就重載從/proc/cpuinfo裡面讀取的數值,這樣整個ro.hardware的硬件系統屬性值就配置好了。

對於"ro.product.board"、 "ro.board.platform"、"ro.arch"這3個屬性變量,就要集中到android的屬性文件上來了,android系統集中的屬性文件有以下幾個:

android的基本屬性文件目錄: #define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop" 以上文件將會在init進程裡面得到進一步的解析,關注到如下的代碼:
queue_builtin_action(property_service_init_action, "property_service_init");//屬性服務的初始化
屬性服務初始化action被加入到action隊列等待執行,執行函數execute_one_command,最終會回調上面注冊的action內的property_service_init_action,這裡就能看到屬性服務的從文件內部讀取維護到內存中:
void start_property_service(void)
{
    int fd;

    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
可以看到會解析不同路徑下的prop屬性文件,包括下面要介紹的這個buil.prop 我們來看看/system/build.prop是由Android編譯時由編譯腳本build/core/Makefile和Shell腳本build/tools/buildinfo.sh來生成的,綜合了整個編譯配置環境下的平台相關變量,而這些變量往往在Android系統的關於設備信息中都能查看的到;
  3 ro.build.id=JDQ39
  4 ro.build.display.id=fiber_3g-eng 4.2.2 JDQ39 20140110 test-keys
  5 ro.build.version.incremental=20140110
  6 ro.build.version.sdk=17
  7 ro.build.version.codename=REL
  8 ro.build.version.release=4.2.2
  9 ro.build.date=2014年 01月 10日 星期五 16:03:07 CST
 10 ro.build.date.utc=1389340987
 11 ro.build.type=eng
 12 ro.build.user=root
 13 ro.build.host=linux
 14 ro.build.tags=test-keys
 15 ro.product.model=Softwinner
 16 ro.product.brand=Softwinner
 17 ro.product.name=fiber_3g
 18 ro.product.device=fiber-3g
 19 ro.product.board=exdroid
 20 ro.product.cpu.abi=armeabi-v7a
 21 ro.product.cpu.abi2=armeabi
 22 ro.product.manufacturer=unknown
 23 ro.product.locale.language=en
 24 ro.product.locale.region=US
 25 ro.wifi.channels=
 26 ro.board.platform=fiber
....
好了上面介紹了那麼多,其實已經涵蓋並跳躍了很多的內容,我們回歸到hw_get_module_by_class函數,下面就是確定在哪些目錄下進行優先的搜索,可以看到以下2個主要路徑: /** Base path of the hal modules */
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw" 故而可知,當前的hal庫一般即只能放在這下面,否則找不到程序肯定不能正常運行,的確在編譯時我們不得不去手寫Android.mk裡面添加cp指令,完成當前庫的編譯並copy到上述2個目錄,一般與硬件平台更密切的庫放於/vendor/lib/hw,比如gralloc.sun6i.so hwcomposer.sun6i.so等就是這樣被找到的。 step2. 在完成搜索並定位到了對應庫的路徑之後,下面就是動態加載 load函數,主要將庫文件加載到,HMI所在的地址: #define HAL_MODULE_INFO_SYM_AS_STR "HMI" handle = dlopen(path, RTLD_NOW); hmi = (struct hw_module_t *)dlsym(handle, sym); 這樣就獲取了當前庫文件的struct hal_module_info的信息即hw_m odule_t(內部有一個hw_module_methods_t* methods內部的open函數會向FW提供一個設備操作接口hw_devices_t),最終返回後就可以通過它操作相關的HAL中的封裝函數。
本文的重點是分析HAL的搜索以及定位HAL的過程,以便後續自己完成Android的定制。
handle = dlopen(path, RTLD_NOW);




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