HAL

一、概述

本文希望通過分析臺灣的Jollen的mokoid 工程代碼,和在s5pc100平臺上實現過程種遇到的問題,解析Andorid HAL的開發方法。

二、HAL介紹

現有HAL架構由Patrick Brady (Google) 在2008 Google I/O演講中提出的,如下圖。

Android的HAL是爲了保護一些硬件提供商的知識產權而提出的,是爲了避開linux的GPL束縛。思路是把控制硬件的動作都放到了Android HAL中,而linux driver僅僅完成一些簡單的數據交互作用,甚至把硬件寄存器空間直接映射到user space。而Android是基於Aparch的license,因此硬件廠商可以只提供二進制代碼,所以說Android只是一個開放的平臺,並不是一個開源的平臺。也許也正是因爲Android不遵從GPL,所以Greg Kroah-Hartman纔在2.6.33內核將Andorid驅動從linux中刪除。GPL和硬件廠商目前還是有着無法彌合的裂痕。Android想要把這個問題處理好也是不容易的。

總結下來,Android HAL存在的原因主要有:

1. 並不是所有的硬件設備都有標準的linux kernel的接口
2. KERNEL DRIVER涉及到GPL的版權。某些設備製造商並不原因公開硬件驅動,所以纔去用HAL方 式繞過GPL。
3. 針對某些硬件,An有一些特殊的需求。

三、HAL內容

1、HAL 主要的儲存於以下目錄:

(注意:HAL在其它目錄下也可以正常編譯)
● libhardware_legacy/ - 舊的架構、採取鏈接庫模塊的觀念進行
● libhardware/ - 新架構、調整爲 HAL stub 的觀念
● ril/ - Radio Interface Layer
● msm7k QUAL平臺相關

主要包含以下一些模塊:Gps、Vibrator、Wifi、Copybit、Audio、Camera、Lights、Ril、Overlay等。

2、兩種 HAL 架構比較

目前存在兩種HAL架構,位於libhardware_legacy目錄下的“舊HAL架構”和位於libhardware目錄下的“新HAL架構”。兩種框架如下圖所示。

圖3.1 舊HAL架構 圖3.2 新HAL架構

libhardware_legacy 是將 *.so 文件當作shared library來使用,在runtime(JNI 部份)以 direct function call 使用 HAL module。通過直接函數調用的方式,來操作驅動程序。當然,應用程序也可以不需要通過 JNI 的方式進行,直接加載 *.so (dlopen)的做法調用*.so 裏的符號(symbol)也是一種方式。總而言之是沒有經過封裝,上層可以直接操作硬件。

現在的 libhardware 架構,就有stub的味道了。HAL stub 是一種代理人(proxy)的概念,stub 雖然仍是以 *.so檔的形式存在,但HAL已經將 *.so 檔隱藏起來了。Stub 向 HAL提供操作函數(operations),而 runtime 則是向 HAL 取得特定模塊(stub)的 operations,再 callback 這些操作函數。這種以 indirect function call 的架構,讓HAL stub 變成是一種包含關係,即 HAL 裏包含了許許多多的 stub(代理人)。Runtime 只要說明類型,即 module ID,就可以取得操作函數。對於目前的HAL,可以認爲Android定義了HAL層結構框架,通過幾個接口訪問硬件從而統一了調用方式。

下面結合實例來分析HAL編程方法。

四、mokoid 工程代碼下載與結構分析

1、mokid項目概述

modkoid工程提供了一個LedTest示例程序,是臺灣的Jollen用於培訓的。對於理解android層次結構、Hal編程方法都非常有意義。

2、下載方法

#svn checkout http://mokoid.googlecode.com/svn/trunk/mokoid-read-only

3、結構分析



Android的HAL的實現需要通過JNI(Java Native Interface),JNI簡單來說就是java程序可以調用C/C++寫的動態鏈接庫,這樣的話,HAL可以使用C/C++語言編寫,效率更高。在Android下訪問HAL大致有以下兩種方式:

(1)Android的app可以直接通過service調用.so格式的jni

(2)經過Manager調用service

上面兩種方法應該說是各有優缺點,第一種方法簡單高效,但不正規。第二種方法實現起來比較複雜,但更符合目前的Android框架。第二種方法中,LegManager和LedService(java)在兩個進程中,需要通過進程通訊的方式來通訊。

mokoid工程中實現了上述兩種方法。下面將詳細介紹這兩種方法的實現原理。

4、第一種方法:直接調用service方法的實現過程

下面分析第一種方法中,各層的關鍵代碼。

(1)HAL層

一般來說HAL moudle需要涉及的是三個關鍵結構體:
struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;

下面結合代碼說明這3個結構的用法。部分代碼經過修改,後面的章節會給出修改的原因。

文件:mokoid-read-only/hardware/modules/include/mokoid/led.h
/***************************************************************************/
struct led_module_t {
struct hw_module_t common;
};
//HAL 規定不能直接使用hw_module_t結構,因此需要做這麼一個繼承。
struct led_control_device_t {
//自定義的一個針對Led控制的結構,包含hw_device_t和支持的API操作
struct hw_device_t common;
/* attributes */
int fd; //可用於具體的設備描述符
/* supporting control APIs go here */
int (*set_on)(struct led_control_device_t *dev, int32_t led);
int (*set_off)(struct led_control_device_t *dev, int32_t led);
};
#define LED_HARDWARE_MODULE_ID "led"
//定義一個MODULE_ID,HAL層可以根據這個ID找到我們這個HAL stub

文件:mokoid-read-only/hardware/modules/led/led.c



(2)JNI層

文件:mokoid-read-only/frameworks/base/service/jni/com_mokoid_server_LedService.cpp





 

(3)service (屬於Framework層)

(4)APP 測試程序 (屬於APP層)

文件:apps/LedClient/src/com/mokoid/LedClient/LedClient.java

5、第二種方法:經過Manager調用service

HAL、JNI兩層和第一種方法一樣,所以後面只分析其他的層次。

(1)Manager (屬於Framework層)

APP通過這個Manager和service通訊。

文件:mokoid-read-only /frameworks/base/core/java/mokoid/hardware/LedManager.java
 


因爲LedService和LedManager在不同的進程,所以要考慮到進程通訊的問題。Manager通過增加一個aidl文件來描述通訊接口

文件:mokoid-read-only/frameworks/base/core/java/mokoid/hardware/ILedService.aidl

(2)SystemServer (屬於APP層)

文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedSystemServer.java

(3)APP 測試程序(屬於APP層)

文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java


五、實驗中需要注意的問題

將下載後的源碼放到你的android源碼目錄下,然後編譯系統。本實驗用的android版本爲2.1。實驗的過程中大致出現過以下幾個問題:

1、目標系統中沒有生成LedClient.apk或LedTest.apk應用程序

編譯完成後,沒有在目標系統的system/app/目錄下找到LedClient.apk或LedTest應用程序。只有通過單獨編譯LedClient或LedTest才能在目標目錄中生成。方法如下:

#mmm mokoid-read-only/apps/LedTest/

檢查原因後發現mokoid-read-only/apps/LedTest/Android.mk

LOCAL_MODULES_TAGS :=user

而我們的s5pc100系統在配置時tapas時選擇的是eng,所以沒有裝載到目標系統。

所以修改LedTest和LedClient的Android.mk

LOCAL_MODULES_TAGS :=user eng

再次編譯即可自動裝載到目標系統/system/app/目錄下。

2、啓動後沒有圖標,找不到應用程序

目標系統啓動後找不到兩個應用程序的圖標。仔細閱讀logcat輸出的信息發現:

E/PackageManager( 2717): Package com.mokoid.LedClient requires unavailable shared library com.mokoid.server; failing!

原因是找不到 com.mokoid.server。檢查mokoid-read-only/frameworks/base/Android.mk發現系統將LedManager和LedService編譯成 mokoid.jar庫文件。爲了讓應用程序可以訪問到這個庫,需要通過com.mokoid.server.xml 來設定其對應關係。解決方法:拷貝com.mokoid.server.xml到目標系統的system/etc/permissions/目錄下。

此時兩個應用的程序的圖標都正常出現了。

3、提示找不到 JNI_OnLoad

按照以前的實驗加入下列代碼:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章