1. 程式人生 > >Android系統(114)---Android 系統移植驅動篇

Android系統(114)---Android 系統移植驅動篇

【導語】在Android系統移植中,有很重要的一個部分工作,就是為新平臺上的硬體裝置移植驅動程式。因為Android系統是基於Linux kernel核心構建,所以這裡說的移植驅動程式,其實就是基於Android系統平臺開發適應移動裝置的Linux核心驅動程式。

一. Android系統中Linux核心與裝置驅動

Android系統中使用了Linux核心作為自己的作業系統,除了linux的通用程式碼之外,主要還包含三個方面的東西:

  • 體系結構和處理器 
    體系結構處理器和標準的裝置驅動程式這兩個方面是和硬體相關的,但是對於同一種硬體,在Android系統和標準的Linux系統中基本上是一樣的。

  • Android專用的驅動程式 
    Android的專用驅動程式,通常是和硬體無關的驅動程式,僅僅在Android系統中使用。

  • 標準的linux裝置驅動程式

Android系統中Linux核心與裝置驅動的結構如下圖示:

這裡寫圖片描述

Android系統通常用於移動裝置和其他的嵌入式裝置,因此都基於ARM體系結構,在ARM體系結構具有多種處理器。因此,對於不同對的處理器,基於相同的外圍裝置,驅動程式也可能不一樣。

需要說明的是上圖中的Goldfish:

Android模擬器通過執行一個Goldfish的虛擬CPU ,Goldfish用來執行arm926t指令集(arm926t屬於armv5構架),並且模擬了輸入/輸出,比如鍵盤輸入和LCD 輸出。這個模擬器其實是在qemu之上開發的,輸入/輸出是基於libSDL的。既然Goldfish是被模擬器執行的虛擬CPU,那麼當Android在真實的硬體裝置上執行時,我們就需要去掉它。

二. Android系統上的裝置驅動

  • 基本圖形使用者介面(GUI)部分:包括顯示部分、使用者輸入部分和硬體相關的加速部分,還包括媒體編解碼和OpenGL等。
  • 音視訊輸入輸出部分:包括音訊、視訊輸出和攝像頭等。
  • 連線部分:包括無線區域網、藍芽、GPS等。
  • 電話部分:包括通話、GSM等。
  • 附屬部件:包括感測器、背光、振動器等。

具體來說是有以下:

  • [x] Display顯示部分:包括FrameBuffer驅動和Gralloc模組。
  • [x] Input使用者輸入部分:包括Event驅動和EventHub。
  • [x] Codec多媒體編解碼:包括硬體Codec驅動和Codec外掛,例如OpenMax。
  • [x] 3DAccelerator(3D加速器)部分:包括硬體OpenGL驅動和OpenGL外掛。
  • [x] Audio音訊部分:包括Audio驅動和Audio硬體抽象層。
  • [x] VideoOut視訊輸出部分:包括視訊顯示驅動和Overlay硬體抽象層。
  • [x] Camera攝像頭部分:包括Camera驅動(通常是v4l2)和Camera硬體抽象層。
  • [x] Phone電話部分:包括Modem驅動程式和RIL庫。
  • [x] GPS全球定位系統部分:包括GPS驅動(例如串列埠)和GPS硬體抽象層。
  • [x] Wi-Fi無線區域網部分:包括Wlan驅動和協議和Wi-Fi的適配層。
  • [x] BlueTooth藍芽部分:包括BT驅動和協議及BT的適配層。
  • [x] Sensor感測器部分:包括Sensor驅動和Sensor硬體抽象層。
  • [x] Vibrator振動器部分:包括Vibrator驅動和Vibrator硬體抽象層。
  • [x] Light背光部分:包括Light驅動和Light硬體抽象層。
  • [x] Alarm警告器部分:包括Alarm驅動和RTC系統和使用者空間呼叫。
  • [x] Battery電池部分:包括電池部分驅動和電池的硬體抽象層。

在實際應用中,通過下面的圖,感受下一個量產的平板中用到了哪些硬體,體會下其中涉及到的驅動: 
全志A33平板PCBA,如有侵權,請及時告知

三.Android系統專用驅動

看一下Google為基於Linux kernel而定製的Android系統專用驅動程式:

(1)Android Binder

Android Binder是基於OpenBinder框架的一個驅動,用於Android平臺的程序間通訊(InterProcess 
Communication,IPC)。原來的Linux系統上層應用的程序間通訊主要是D-bus(Desktop bus),採用訊息匯流排的方式來進行IPC。 
原始碼位於drivers/staging/android/binder.c。

(2)Android電源管理

Android電源管理是基於標準Linux電源管理系統的輕量級Android電源管理驅動,針對嵌入式裝置做 
了很多優化。利用鎖和定時器來切換系統狀態,控制裝置在不同狀態下的功耗,已達到節能的目的。 
原始碼位於: 
- [ ] kernel/power/earlysuspend.c 
- [ ] kernel/power/consoleearlysuspend.c 
- [ ] kernel/power/fbearlysuspend.c 
- [ ] kernel/power/wakelock.c 
- [ ] kernel/power/userwakelock.c

Android5.0版本引用JobSchedule排程程式,以便增加裝置續航時間。

(3)低記憶體管理器(Low Memory Killer)

比Linux的標準的OOM(Out Of Memory)機制更加靈活,它可以根據需要 
殺死程序以釋放需要的記憶體。原始碼位於 drivers/staging/ android/lowmemorykiller.c。

(4)匿名共享記憶體(Ashmem)

為程序間提供大塊共享記憶體,同時為核心提供回收和管理這個記憶體的機制。原始碼位於 
mm/ashmem.c。

(5)Android PMEM(Physical)

PMEM用於向用戶空間提供連續的實體記憶體區域,DSP和某些裝置只能工作在連續的物 
理記憶體上。 
原始碼位於drivers/misc/pmem.c。

(6)Android Logger

一個輕量級的日誌裝置,用於抓取Android系統的各種日誌,是Linux所沒有的。 
原始碼位於drivers/staging/android/logger.c。

(7)Android Alarm

提供了一個定時器,用於把裝置從睡眠狀態喚醒,同時它還提供了一個即使在裝置睡眠時也會 
執行的時鐘基準。原始碼位於drivers/rtc/alarm.c。

(8)USB Gadget驅動

一個基於標準 Linux USB gadget驅動框架的裝置驅動,Android的USB驅動是基於gaeget框架的。 
原始碼位於 
- [ ] drivers/usb/gadget/android.c 
- [ ] drivers/usb/gadget/f_adb.c 
- [ ] drivers/usb/gadget/f_mass_storage.c

(9)Android Ram Console

為了提供除錯功能,Android允許將除錯日誌資訊寫入一個被稱為RAM Console的裝置 
裡,它是一個基於RAM的Buffer。原始碼位於drivers/staging/android / ram_console.c。

(10)Android timed device

提供了對裝置進行定時控制的功能,目前支援vibrator和LED裝置。原始碼位於 
drivers/staging/android /timed_output.c(timed_gpio.c)。

(11)Yaffs2 檔案系統

Android採用Yaffs2作為MTD nand flash檔案系統,原始碼位於fs/yaffs2/目錄下。 
Yaffs2是一個快速穩定的應用於NAND和NOR Flash的跨平臺的嵌入式裝置檔案系統,同其他Flash檔案系統相比, 
Yaffs2能使用更小的記憶體來儲存其執行狀態,因此它佔用記憶體小。Yaffs2的垃圾回收非常簡單而且快速,因此能表 
現出更好的效能。Yaffs2在大容量的NAND Flash上的效能表現尤為突出,非常適合大容量的Flash儲存。

四.Android驅動開發主要工作

Linux系統將裝置驅動分為以下三類:

  • (1)字元裝置

    指只能一個位元組一個位元組讀寫的裝置,不能隨機讀取裝置記憶體中的某一資料,讀取資料需要按照先後資料。字元裝置是面向流的裝置,常見的字元裝置有滑鼠、鍵盤、串列埠、控制檯和LED裝置等。

  • (2)塊裝置

    指可以從裝置的任意位置讀取一定長度資料的裝置。塊裝置包括硬碟、磁碟、U盤和SD卡等。

  • (3)網路裝置

    為支援通過檔案介面處理網路連線,Linux使用了源於BSD的套接字抽象,套接字keil看作應用程式、檔案介面、核心的網路之間的代理。

驅動程式是介於系統和硬體之間的橋樑,實現硬體和系統之間的互動是我們底層開發的主要任務。在Android系統中,我們一般需要編寫核心級和使用者級的程式來完成具體的任務。

4.1 實現系統和硬體之間互動的幾種方式

  • (1).編寫自己的系統呼叫 
    系統呼叫是使用者級程式訪問核心最基本的方法,Linux提供了很多標準的系統呼叫(參見核心程式碼樹中的include/asm-i386/unistd.h和arch/i386/kernel/entry.S檔案),並且允許我們新增自己的系統呼叫來實現和核心的資訊交換;

  • (2).編寫驅動程式 
    Linux有一個重要的理念就是“一切皆檔案”(everything is a file)。

    使用者空間的應用程式通過系統提供的統一互動介面 open() —— read() —— write() —— ioctl() —— close()方法,訪問檔案系統中/dev/目錄下的一個檔案來訪問運行於核心空間的驅動程式,並通過驅動程式中實現的功能達到對硬體的訪問。

  • (3). 使用proc 檔案系統

    proc是Linux提供的一種特殊的檔案系統,推出它的目的就是提供一種便捷的使用者和核心間的互動方式。proc 檔案系統相對是比較簡單的,不過proc檔案的讀寫並不統一,讀資料的buf指標直接指向的就是使用者態的地址,可以用sprintf進行寫入;而寫方法卻是核心態的地址,需要用get_user或者 copy_from_user之類的方法。

  • (4).使用虛擬檔案系統

    有些核心開發者認為利用ioctl()系統呼叫往往會似的系統呼叫意義不明確,而且難控制。而將資訊放入到proc檔案系統中會使資訊組織混亂,因此也不贊成過多使用。他們建議實現一種孤立的虛擬檔案系統來代替ioctl()和/proc,因為檔案系統介面清楚,而且便於使用者空間訪問,同時利用虛擬檔案系統使得利用指令碼執行系統管理任務更家方便、有效。

  • (5).使用記憶體映像

    Linux通過記憶體映像機制來提供使用者程式對記憶體直接訪問的能力。記憶體映像的意思是把核心中特定部分的記憶體空間對映到使用者級程式的記憶體空間去。也就是說,使用者空間和核心空間共享一塊相同的記憶體。

4.2 核心空間和使用者空間的互動

上面講了系統與硬體互動的幾種方式提到了,在具體的互動中,驅動程式驅動具體的硬體模組工作時涉及到一個核心空間和使用者空間互動的概念。

現代的計算機體系結構中儲存管理通常都包含保護機制。提供保護的目的,是要避免系統中的一個任務訪問屬於另外的或屬於作業系統的儲存區域。如在IntelX86體系中,就提供了特權級這種保護機制,通過特權級別的區別來限制對儲存區域的訪問。

基於這種構架,Linux作業系統對自身進行了劃分:一部分核心軟體獨立於普通應用程式,執行在較高的特權級別上,(Linux使用Intel體系的特權級3來執行核心。)它們駐留在被保護的記憶體空間上,擁有訪問硬體裝置的所有許可權,Linux將此稱為核心空間 。

相對的,其它部分被作為應用程式在使用者空間 執行。它們只能看到允許它們使用的部分系統資源,並且不能使用某些特定的系統功能,不能直接訪問硬體,不能直接訪問核心空間,當然還有其他一些具體的使用限制。(Linux使用Intel體系的特權級0來執行使用者程式。)

通過下面的圖,看一下核心空間與使用者空間的互動關係: 
這裡寫圖片描述