Android HAL層實現與調用

AndroidHAL層實現與調用

1.HAL層實現

     在這篇文章中我們討論下HAL層代碼的簡單組成,以及jni是如何調用HAL層代碼。文章盡量避免瞭一些無用信息,直接寫有實際的東西。

    在這裡我用一個簡單的HAL層代碼(電子防眩目的hal代碼)來開始我們的講解。

     在一個hal代碼中主要的工作是實現一個名為HAL_MODULE_INFO_SYM的module實例,其結構定義為

[cpp]
<span xmlns="http://www.w3.org/1999/xhtml" style="">  
struct lcd_reflect_module_t { 
 
    struct hw_module_t common; 
 
};</span> 

可以看到這個結構的名字是隨意的,一般用(模塊名_module_t)來表示,可以看到它隻有一個成員變量hw_module_t,也就是說主要的工作就是填充這個hw_module_t這個結構瞭。

[cpp]
<span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""> 
const struct lcd_reflect_module_t HAL_MODULE_INFO_SYM = { 
 
    .common = { 
 
        .tag = HARDWARE_MODULE_TAG, 
 
        .version_major = 1, 
 
        .version_minor = 0, 
 
        .id = LCD_REFLECT_HARDWARE_MODULE_ID, 
 
        .name = "LCD Reflect", 
 
        .author = "Archermind Tech.", 
 
        .methods = &lcd_reflect_module_methods, 
 
    } 
 
}; 
</span></span> 

tag:需要指定為HARDWARE_MODULE_TAG,不能修改

id:指定為HALStub的moduleID,這裡#defineLCD_REFLECT_HARDWARE_MODULE_ID "lcdreflect"

接下來就要實現另外一個重要的結構瞭—structhw_module_methods_t methods.

來看一下這個結構體的定義:

[cpp]
<span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""> 
typedef struct hw_module_methods_t { 
 
    /** Open a specific device */ 
 
    int (*open)(const struct hw_module_t* module, const char* id, 
 
            struct hw_device_t** device); 
 
} hw_module_methods_t; 
</span></span> 

    可以看到其中隻有一個open函數指針,作為module的callback。

     前面我們已經接觸瞭兩個重要的結構體,hw_module_t和hw_module_methods_t,下面我們還需要來看一下hal層中第三個重要的結構體hw_device_t。

     下面我們來看一下hw_module_methods_t中的open函數lcd_reflect_module_methods。

[cpp]
<span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""> 
static int 
 
lcd_reflect_open(const struct hw_module_t *module, 
 
              const char *name, struct hw_device_t **device) 
 

 
    int status = -EINVAL; 
 
 
 
    LOGV("lcd_reflect_open\n"); 
 
    if (!strcmp(name, LCD_REFLECT_HARDWARE)) { 
 
        struct lcd_reflect_device_t *dev; 
 
 
 
        dev = malloc(sizeof (*dev)); 
 
        memset(dev, 0, sizeof (*dev)); 
 
 
 
        dev->common.tag = HARDWARE_DEVICE_TAG; 
 
        dev->common.version = 0; 
 
        dev->common.module = (struct hw_module_t *)module; 
 
        dev->common.close = lcd_reflect_close; 
 
 
 
        *device = &dev->common; 
 
 
 
        dev->get_level = &lcd_reflect_get_level; 
 
        dev->set_level = &lcd_reflect_set_level; 
 
        dev->get_state = &lcd_reflect_get_state; 
 
        dev->set_state = &lcd_reflect_set_state; 
 
 
 
        status = 0; 
 
    } 
 
    return status; 
 
}</span></span> 

    可以看到hw_device_t作為open的形參傳入open函數中,並且我們還發現瞭另外一個結構體structlcd_reflect_device_t*dev;這個結構是我們模塊自己定義的,用於存放一些我們模塊需要的操作,jni層中就是通過這個結構體來調用hal層中提供的接口的。看一下它的定義。

[cpp]
<span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""> 
struct lcd_reflect_device_t { 
 
    struct hw_device_t common; 
 
 
 
    /**
 
     * Get the mxc_reflect state
 
     *
 
     * Returns: 0 on success, error code on failure
 
     */ 
 
    int (*get_state)(struct lcd_reflect_device_t *dev, 
 
                     int *stat); 
 
 
 
    /**
 
     * Set the mxc_reflect state
 
     *
 
     * Returns: 0 on success, error code on failure
 
     */ 
 
    int (*set_state)(struct lcd_reflect_device_t *dev, 
 
                     int stat); 
 
 
 
    /**
 
     * Get the mxc_reflect level
 
     *
 
     * Returns: 0 on success, error code on failure
 
     */ 
 
    int (*get_level)(struct lcd_reflect_device_t *dev, 
 
                    int *level); 
 
 
 
    /**
 
     * Set the mxc_reflect state
 
     *
 
     * Returns: 0 on success, error code on failure
 
     */ 
 
    int (*set_level)(struct lcd_reflect_device_t *dev, 
 
                    int level); 
 
};</span></span> 

裡面有hw_device_t這個成員,並且它是在最前面的一個成員,這個是非常重要的,我們將在下面說明為什麼它需要放在最前面,除瞭hw_device_t就是一些hal層需要提供給jni調用的函數指針。
再回到open函數中,現在我們就能看懂這個open函數所做的工作瞭,它首先註冊瞭一個structlcd_reflect_device_t *dev; lcd_reflect_device_t變量,然後填充common,也就是hw_device_t這個結構,這裡需要註意有幾個成員:

tag:必須指定為HARDWARE_DEVICE_TAG

    還需要實現一個close函數,接著*device= &dev->common;,即讓jni的hw_device_t與hal中的lcd_reflect_device_t聯系在一起瞭,由於common這個成員在lcd_reflect_device_t的最前面定義的,那麼也就是lcd_reflect_device_t的地址和common的地址是相同的。隻要知道common的地址就可以知道lcd_reflect_device_t的地址,這樣lcd_reflect_device_t結構就可以傳送到jni層使用瞭,隻需要將common的地址強制轉換一下即可。最後把hal層需要提供給jni的API實現就可以瞭。

這樣一個簡單的hal層代碼框架就有啦。

2.調用HAL層

     在jni層,我們通過hw_get_module函數得到hw_module_t結構,如下:

hw_get_module(LCD_REFLECT_HARDWARE_MODULE_ID,(hw_module_t const**)&module);

通過指定LCD_REFLECT_HARDWARE_MODULE_ID來區別module,接著還需要得到lcd_reflect_device_t*device;這個結構,我們可以通過下面這個函數實現:

[cpp]
<span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""> 
static lcd_reflect_device_t * 
 
get_device(hw_module_t *module, char const *name) 
 

 
    int err; 
 
    hw_device_t *device; 
 
 
 
    err = module->methods->open(module, name, &device); 
 
    if (err == 0) { 
 
        return (lcd_reflect_device_t *)device; 
 
    } else { 
 
        return NULL; 
 
    } 
 
}</span></span></span></span></span> 
    函數返回的是lcd_reflect_device_t結構的地址,在函數中首先定義hw_device_t*device;接著將其通過module->methods->open(module,name, &device);得到hw_device_t這個結構的地址,接著將這個地址返回,返回前需要將地址類型強制轉換一下,(lcd_reflect_device_t*)device,這樣就得到lcd_reflect_device_t這個結構的地址啦。原因我們在上面講過,是因為hw_device_t和lcd_reflect_device_t兩個結構的首地址是相同的。
     有瞭lcd_reflect_device_t我們就可以調用hal層中實現的API啦,通過這些API操作硬件。

 

摘自 android_huber的專欄

發佈留言