1. 程式人生 > >Android 驅動(3)---Android驅動開發知識儲備

Android 驅動(3)---Android驅動開發知識儲備

Android驅動開發知識儲備

Android軟體層次結構
(1)作業系統層
顯示驅動(Frame Buffer),Flash記憶體驅動,照相機驅動,音訊驅動,WiFi驅動,鍵盤驅動,藍芽驅動,Binder IPC驅動,Power Management  ,這些都包括在Linux核心裡。

(2)各種庫和Android執行環境
C庫、多媒體框架、SGL(2D影象引擎),SSL(安全),OpenGL ES(3D),介面管理工具,SQLite,WebKit,FreeType。
JVM是基於棧的虛擬機器,DVM是基於暫存器的虛擬機器
(3)應用程式框架
(4)應用程式


 

Android移植定義

       在硬體系統的基礎上構建Android軟體系統。
(1)Linux中的相關裝置驅動程式
驅動程式是硬體和上層軟體的介面,在Android手機系統中,需要基本的螢幕、觸控式螢幕、鍵盤等驅動程式,以及音訊、攝像頭、電話、WiFi、藍芽等裝置驅動程式。
(2)Android本地框架中的硬體抽象層
在Android中,硬體抽象層工作在使用者空間,介於驅動程式和Android系統之間。Android系統對硬體抽象層通常都有標準的介面定義,在開發過程中,實現這些介面也就給Android系統提供了硬體抽象層。

Android移植型別
(1)基礎圖形使用者介面部分:包括顯示部分、使用者輸入部分和硬體相關的加速部分,還包括媒體編解碼和OpenGL等。
(2)音視訊輸入輸出部分:包括音訊、視訊輸出和攝像頭等。
(3)連線部分:包括無線局網、藍芽、GPS等。
(4)電話部分
(5)附屬部分:包括感測器、背光、震動器等。

Android的核心驅動
(1)Binder:程序間通訊IPC
(2)電源管理(PM)
(3)低記憶體管理器(Low Memory Killer):根據需要殺死程序來釋放需要的記憶體
(4)匿名共享記憶體(ashmem)
(5)PMEM:用於向用戶空間提供連續的實體記憶體區域。
(6)Logger
(7)Alarm:提供了一個定時器用於把裝置從睡眠狀態喚醒。
(8)USB Gadget驅動
(9)Android Ram Console:這是為了提供除錯功能而推出的,Android允許將除錯日誌資訊寫入一個被稱為RAM Console的裝置裡,是一個基於RAM的Buffer。
(10)Android timed device:提供了對裝置進行定時控制功能。
(11)Yaffs2檔案系統:作為MTD nand flash檔案系統



在linux系統中,主要有3類裝置驅動,分別是字元裝置驅動、塊裝置驅動和網路介面驅動。
字元裝置是指在I/O傳輸過程中以字元為單位進行傳輸的裝置,例如鍵盤、印表機等。
塊裝置只能以塊為單位接收輸入返回輸出,而字元裝置則以Byte為單位。大多數裝置是字元裝置,它們不需要緩衝並且不以固定塊大小進行操作。
網路裝置驅動程式,分別是網路裝置媒介層、網路裝置驅動層、網路裝置介面層以及網路協議介面層。




Binder的工作流程
(1)客戶端首先獲得伺服器端的代理物件。所謂的代理物件實際上就是在客戶端建立一個服務端的”引用“,該代理物件具有服務端的功能,使其在客戶端訪問服務端的方法就想訪問本地方法一樣。
(2)客戶端通過呼叫伺服器代理物件的方式向伺服器端傳送請求。
(3)代理物件將使用者請求通過BInder驅動傳送到伺服器程序。
(4)伺服器程序處理使用者請求,並通過BInder驅動返回處理結果給客戶端的伺服器代理物件。

(5)客戶端收到伺服器端的返回結果。

Android HAL概述

在Android的4層構架中,在C++庫層的最底部,有一個子層--硬體抽象層(Hardware Abstract Layer,HAL)。該層實現Android上層對Linux中驅動程式的呼叫,向Android上層提供訪問底層裝置的介面,以便Android系統的其他部分訪問這些硬體。

Android驅動與一般Linux驅動的最大區別就是把對硬體的支援分為了兩層:一層放在了使用者空間,我們稱之為硬體抽象層;另一層則放到了核心空間,我們稱之為核心驅動層。其中,一般核心驅動層只提供簡單的訪問硬體的邏輯,例如提供讀寫硬體暫存器方法,而具體讀寫什麼值到硬體的邏輯,則放到硬體抽象層中。

通過這種分層的方式,硬體廠商不用再提供其HAL層的原始碼,進而有利於保護這些硬體廠商的智慧財產權。另外通過這種分層的方式,有利於遮蔽底層驅動的差異性,為同一類裝置向上提供統一的介面。

Bootloader

Bootloader負責Android機器的啟動、Image的燒寫、關機充電等,這些都是與核心要實現。BootLoader是作業系統執行之前執行的一段程式,他最主要的工作就是將機器的軟硬體環境帶到一個適當的狀態,為作業系統的執行做好準備。具體講,BootLoader要完成的子任務很多。但這些任務的目的總體說就是要努力把OS拉出來,在機器的CPU等硬體組成的環境上執行。ARM處理器系列的Bootloader則大多數以U-Boot為基礎。

U-Boot的啟動過程可分成兩個階段:第一階段,常稱彙編程式碼階段,在這個階段用於要考慮儲存空間受限和啟動速度的要儘量快,所以其程式碼編寫才用效率更高的組合語言;第二階段,C程式碼階段,到此階段亦可以開始與使用者互動,而且機器的硬體大多已啟用,所以一般採用C語言編寫。

OS基本概念

現在的PC和常用手機等,都有一組基本的程式--OS(作業系統)。在這組程式中最重要的叫核心,人們常將OS與核心等同。

OS必須完成兩個主要目標:

與硬體互動。為在計算機系統上執行的應用程式提供可執行的環境。

一些OS允許使用者程式直接與硬體元件互動(如MS-DOS)。相反,Linux OS會遮蔽掉所有與物理硬體相關的東西。當應用程式要用到硬體資源時,它就必須向OS發出請求,而OS則會根據情況許可上層應用使用該硬體資源。

為了加強這種機制,現代的OS將依賴於特定硬體的特性來禁止使用者程式直接與底層的硬體元件互動,或直接地隨意訪問記憶體的地址。繼而,該硬體引入了兩個不同的CPU執行模式:非特權模式給上層使用者程式用;特權模式則給核心用。

多使用者系統

LinuxOS是源於UNIX系統的。通過分時共享等策略,讓多個使用者可以同時使用一臺計算機,卻讓各使用者感受不到自己是在與其他使用者共用這臺機器。該分享策略,使得機器即便只有一個使用者,也可以同時執行多個任務,響應多個程序。

認證機制,以驗證使用者ID。保護機制1,以對抗bug,不讓這些壞程式堵塞了其他使用者程式。保護機制2,以對抗惡意的程式,以防它去監聽其他使用者的活動。審計機制,以限制分派給每個使用者的資源。

使用者和組

Linux OS作為多使用者系統,每個使用者在機器上都有一個私有空間;特別是,他會擁有配額的磁碟空間,以儲存檔案、接收私有的mail訊息等。OS必須確保這個部分私有空間只對它的擁有者是可見的。所有使用者都是通過唯一的使用者ID來識別的,簡稱UID。當用戶想用機器,會被要求輸入使用者名稱和密碼,這樣使用者的私密權就得到了保證。

如果要選擇與其他使用者共享材料,共享的每個使用者就應是一個或多個組的成員,這個組由組ID(GID)來識別。每個檔案都可與一個確切的組相關聯。例如:作為檔案擁有者的使用者擁有對該檔案的讀寫許可權,而組中其他使用者則只擁有讀許可權,系統中非組中的使用者則沒有任何訪問權。

Linux OS中,有一個特殊的使用者:root。系統管理員應以root的身份登入機器,以管理其他使用者賬號,完成維護任務(如系統的備份和程式的升級等)。root使用者幾乎可以做任何事情,因為OS並沒有對它採取一般的防護機制。另外,root使用者可以訪問系統上的每一個檔案,可以管理每一個正執行著的使用者程式。

程序

程序是動態的實體,其在系統中的生命是有限的。程序的建立、銷燬和同步在核心中體現為一組執行緒。Linux核心是以執行緒為排程的單位。

對於支援多使用者的OS都有一個基本的抽象:程序。程序是一個執行的例項,是程式執行的上下文。在初始的OS中,一個程序是在一個地址空間中,執行單個順序的指令集。現代的OS中,則允許程序中有多個執行流,也就是在同樣的地址空間裡有多個同步執行著的順序執行指令集。作為Linux OS,它就允許程序中多個執行流可以併發執行。這些執行流在Linux OS中被稱為執行緒或輕量級程序。

對於單處理器,程序、執行緒或中斷處理執行流的併發,是分時的併發,是邏輯上的併發。對於多處理器系統,這些併發執行是真真切切同時在執行的。多使用者系統,必須保證有一個這些的併發執行環境:執行幾個程序同時執行,他們將對系統的資源共享,且通過競爭來獲得使用。這些允許多個活動程序的OS,也被稱作多程式或多程序系統。Linux OS就是支援多使用者、多程序、多處理器的一款作業系統。

程式與程序是有區別的。程式是靜止的,由程式碼、庫或資源組成的集合體;而程序則是程式在計算機系統裡執行,是程式的動態體現。

Linux單核架構

OS的核心架構主要分為兩種:一種是單核心的;另一種是微核心的。Linux核心是單核:每個核心層被整合為一個整體的核心程式,並執行在當前程序的核心模式中。相反,微核心OS則只有上述核心的最核心功能,一般包括:一些同步用的原語、排程器、與程序間通訊的機制;而幾個系統程序會執行在上述微核心之上,來完成OS其他系統層的功能,如記憶體分配、裝置驅動,以及系統呼叫處理例程(Handlers)。

微核心OS速度上較單核的架構要慢,微核心強制系統程式設計師才用模組化的方法,因為每個OS層是一個相對獨立的程式,它要通過已定義好的、簡潔的軟體介面與其它層互動。

Linux引入了模組的概念。一個模組包含一個object檔案,該Object程式碼由一組功能組成;歸屬於某一檔案系統、底層裝置功能驅動,以及其他屬於核心上層的特性。這個模組又不同於微核心OS的外部層,他不是執行在專門的程序中,而是執行在當前程序的核心模式中。

linux OS使用模組機制的好處:模組化的方法。保持平臺的獨立性。節儉的主記憶體使用。沒有任何效能上的損失。

Linux核心概述

Linux核心必須實現一組服務和相應的介面,應用程式則可以用這些介面,間接與硬體打交道。主要由五個子系統組成:程序排程、記憶體管理、虛擬檔案系統、程序間通訊以及裝置驅動。

Linux核心是通過裝置驅動與I/O裝置互動的。裝置驅動被包含在linux核心中。


linux核心分為兩部分
(1)體系相關部分:這部分核心為體系結構和硬體所持有。
(2)體系無關部分:這部分核心是可移植的。體系無關部分通常會定義與體系相關部分的介面,這樣,核心向新的體系結構移植的過程就變成確認這些介面的特性並將他們加以實現的過程。

系統呼叫介面

為了與使用者應用程式進行互動,核心提供了一組系統呼叫介面,通過這組介面,應用程式可以訪問系統硬體和各種硬體系統資源。系統呼叫介面層在使用者應用程式和核心之間添加了一箇中間層

在Linux OS程序/核心模型中,每個程序就是執行在機器上的唯一的映象,他們對系統服務的訪問具有排他性。當程序需要訪問系統服務時,他會發出系統呼叫(就是對核心的請求),硬體則會將權利模式由使用者模式改為核心模式。此時,該程序就開始執行某核心的過程,這個過程是有嚴格限制的。通過這種方法,OS(確切的講應該是核心程式碼)執行在該程序的上下文(context)中,卻又保證其請求是安全的。該核心過程在合適時機會通過硬體強制返回使用者模式,此時該程序將繼續執行程式中緊接著系統呼叫的下一條指令。

當一個程式執行在使用者模式下,他就不能直接的訪問核心資料結構或核心的程式。當程式處於核心模式時,這些限制就不再存在了。現在CPU一般提供了特定的指令在使用者模式與核心模式之間切換。通常,在使用者模式下執行的程式向核心發出服務請求時,就會切換到核心模式。當核心已響應程式的請求時,就會設定程式退回使用者模式。

核心不是程序,而是程序的管理者。

除了使用者程序,Linux系統包括一些特權執行緒,這些核心執行緒有以下特點:他們執行在核心模式,用的是核心地址空間。他們不與使用者直接互動。他們通常在系統啟動時被建立,並一直存活到系統關閉。

裝置驅動簡述

Linux核心是通過裝置驅動與I/O裝置互動的。裝置驅動被包含在Linux核心中,由控制元件一個或多個裝置的資料結構與功能函式構成,如硬碟、鍵盤等。每個驅動會通過一個特定的介面,與核心的其他部分(甚至是其他驅動)互動。

這個方法有以下好處:特定於裝置的程式碼,可以被封裝在特定的模組中。廠商可以在不知道核心原始碼的情況下,增加新的裝置,只要知道特定的介面即可。核心會用統一的方法來處理所有裝置,並通過同樣的介面來訪問這些裝置。可以以模組的方式來寫驅動,並可以動態地載入這些模組,也可動態地解除安裝他們。

一些使用者程式會想要操作硬體裝置,它們會向核心發出請求,請求訪問/dev目錄下的檔案。事實上,裝置檔案就是使用者可見的裝置驅動的介面。每個裝置檔案都會引用到特定的裝置驅動,他會被核心呼叫,以完成對相應硬體元件的操作。

Linux核心原始碼目錄結構

arch:該目錄包含與CPU硬體系統結構相關的程式碼。每個CPU系列都獨自佔有一個目錄,如ARM、MIPS、AVR32、x86、ia64等。

block:該目錄包含塊裝置驅動程式中程序I/O排程的功能程式碼。

crypto:該目錄包含加密/解密演算法,以及壓縮和校驗等功能程式碼。

documentation:該部分是一些文件,在該文件中對核心的各個部分進行了一般性的闡述。

drivers:該目錄包含各裝置程式的功能程式碼。每種型別的裝置驅動常佔有一個獨立的子目錄,如char、block、net、input、power等。

fs:該目錄包含Linux核心所支援的各種檔案系統,如ext、jffs2、yaffs2、fat、ntfs等。

include:該目錄包含一些標頭檔案,其中與Linux系統相關的標頭檔案就放置在該目錄下的linux子目錄中。

init:該目錄包含Linux核心的初始化功能程式碼。

ipc:該目錄包含程序間通訊的功能程式碼。

kernel:該目錄包含程序排程、定時器等功能程式碼。

lib:該目錄包含庫或用於生產庫的程式碼。

mm:該目錄包含記憶體管理功能程式碼。

net:該目錄包含網路相關的功能程式碼,其實現了各種常見的網路協議。

scripts:該目錄包含了一些指令碼檔案,用於配置核心。

security:該目錄包含Linux安全管理方面的程式碼,如賬號等。

sound:該目錄包含ALSA、OSS音訊子系統的核心程式碼,以及一些常用的音訊驅動。

usr:該目錄包含實現cpio工具的功能程式碼。

Linux核心模組基礎與骨架

模組特點:模組本身不被編譯入核心映像,從而控制了核心的大小。模組一旦被載入,他就與核心中的其他部分完全一樣。

例子程式碼:

  1. #include <linux/init.h>

  2. #include <linux/module.h>

  3. MODULE_LICENSE("Dual BSD/GPL");

  4. static int hello_init(void)

  5. {

  6. printk(KERN_ALERT " Hello World enter\n");

  7. return 0;

  8. }

  9. static void hello_exit(void)

  10. {

  11. printk(KERN_ALERT " Hello World exit\n ");

  12. }

  13. module_init(hello_init);

  14. module_exit(hello_exit);

  15. MODULE_AUTHOR("Tony Liu");

  16. MODULE_DESCRIPTION("A simple Hello World Module");

  17. MODULE_ALIAS("a module skeleton");

編譯上面的程式碼生成hello.o的核心模組檔案。

將該模組載入進Linux核心:

#insmod ./hello.o

將該模組從Linux核心解除安裝

#rmmod hello

Linux核心模組主要由以下6個部分組成:

1.模組載入函式:這部分是必需的;一般用於完成模組的初始化工作。2.模組解除安裝函式:這部分是必需的;一般用於解除安裝模組所佔用的相關係統資源。3.模組許可宣告:必需;用於描述該模組的許可許可權;Linux核心中常用的許可是GPL。4.模組引數:可選;用於在模組載入時,向模組傳遞引數;這些引數對應著模組內的全域性變數。5.模組匯出符號:可選;用於匯出可供核心其他模組使用。6.模組作者、描述、別名。

Linux模組的載入與解除安裝

Linux核心初始化函式,一般會加上_ _init,比如

static int _ _init hello_init(void)

模組解除安裝函式,一般會加上_ _exit標識宣告,比如

static void _ _exit hello_exit(void)

若模組載入函式註冊了XXX,則模組解除安裝函式應該登出XXX。若模組載入函式動態申請了記憶體,則模組解除安裝函式應釋放該記憶體。若模組載入函式申請了硬體資源的佔用,則模組解除安裝函式應釋放這些硬體資源。若模組載入函式開啟了硬體,則模組解除安裝函式一般要關閉硬體。

LInux模組的引數與匯出符號

我們可以用“module_param(引數名,引數型別,引數讀寫許可權)”為模組定義一個引數,例如:

  1. static char *my_name = "Tony";

  2. static int num = 5000;

  3. module_param(num, int, S_IRUGO);

  4. module_param(my_name, charp, S_IRUGO);

在裝載核心模組時,使用者可以向模組傳遞引數,形式為“insmode 模組名 引數名 = 引數值”,如果不傳遞,引數將使用模組內定義的預設值。執行insmod命令時,應使用逗號分隔輸入的陣列元素。

帶引數的模組程式碼:

  1. #include <linux/init.h>

  2. #include <linux/module.h>

  3. MODULE_LICENSE("Dual BSD/GPL");

  4. static char *my_name = "Tony";

  5. static int num = 5000;

  6. static int person_init(void)

  7. {

  8. printk(KERN_INFO " person name:%s\n", book_name);

  9. printk(KERN_INFO " person num:%s\n", num);

  10. return 0;

  11. }

  12. static void person_exit(void)

  13. {

  14. printk(KERN_ALERT " person module exit\n ");

  15. }

  16. module_init(person_init);

  17. module_exit(person_exit);

  18. module_param(num, int, S_IRUGO);

  19. module_param(my_name, charp, S_IRUGO);

  20. MODULE_AUTHOR("Yang Liu");

  21. MODULE_DESCRIPTION("A simple Module for testing module params");

  22. MODULE_VERSION("V1.0");

模組可以使用如下巨集匯出符號到核心符號表:
EXPORT_SYMBOL(符號名);
EXPORT_SYMBOL_GPL(符號名);
匯出的符號將可以被其他模組使用,使用前宣告一下即可。EXPORT_SYMBOL_GPL()只適用於包含GPL許可權的模組。在Linux2.6版本中,“/proc/kallsyms"檔案對應著核心符號表,他記錄了符號以及符號所在的記憶體地址。
 

模組的符號匯出

  1. #include <linux/init.h>

  2. #include <linux/module.h>

  3. MODULE_LICENSE("Dual BSD/GPL");

  4. int add_integer(int a, int b)

  5. {

  6. return a+b;

  7. }

  8. int sub_integer(int a, int b)

  9. {

  10. return a-b;

  11. }

  12. EXPORT_SYMBOL(add_integer);

  13. EXPORT_SYMBOL(sub_integer);

如果上面的程式碼在某核心模組順利執行,我們可以從”/proc/kallsyms"檔案中找出add_integer,sub_integer相關訊息。

Linux檔案系統的目錄結構

這裡講的目錄結構則是一個處於執行態Linux系統自身所擁有的目錄結構。
1./dev
裝置檔案儲存目錄,應用程式通過對這些檔案的讀寫和控制就可以訪問實際的裝置。
2./etc
系統配置檔案的所在地,一些伺服器的配置檔案也在這裡,如使用者賬號及密碼配置檔案。
3./lib
庫檔案存放目錄
4./mnt
這個目錄一般是用於存放儲存類裝置的掛載目錄,這些掛載目錄代表了這些儲存裝置的掛載點,如/mnt/sdcard等目錄。有時我們可以讓系統開機自動掛載某檔案系統,也可以把代表該檔案系統的掛載目錄放置在/mnt下。
5./proc
作業系統在執行時,程序及核心資訊(比如CPU、硬碟分割槽、記憶體資訊等)存放在這裡。/proc目錄為偽檔案系統proc的掛載目錄,proc並不是真正的檔案系統,它存在於記憶體之中。
6./sbin
存放可執行檔案,大多是涉及系統管理的命令,是超級許可權使用者root的可執行命令存放地,普通使用者無許可權執行這個目錄下的命令。
7./tmp
有時使用者執行程式的時候會產生臨時檔案,/tmp用來存放臨時檔案。
8./var
var表示的是變化的意思,這個目錄的內容經常變動。
9./sys
Linux2.6核心所支援的sysfs檔案系統被對映在此目錄。Linux裝置驅動模型中的匯流排、驅動和裝置都可以在sysfs檔案系統中找到對應的節點。當核心檢測到在系統中出現了新裝置後,核心會在sysfs檔案系統中為該新裝置生成一項新的記錄。
10./initrd
若在啟動過程中使用了initrd映像作為臨時根檔案系統,則在執行完其上的/linuxrc掛接真正的根檔案系統後,原來的初始RAM檔案系統被對映到/initrd目錄。

裝置驅動與Linux檔案系統的關聯

Linux系統其實是一個以檔案為中心的系統。在Linux檔案系統中最大的一個特色就是實現了一個虛擬檔案系統VFS。虛擬檔案系統下面可以掛在各種檔案系統,包括對應裝置驅動的裝置檔案系統。
應用程式和VFS之間的介面是系統呼叫,而VFS與磁碟檔案系統以及普通裝置之間的介面是file_operations結構體成員函式,這個結構體包含對檔案進行開啟、關閉、讀寫、控制的一系列成員函式。
由於字元裝置的上層沒有磁碟檔案系統,所以字元裝置的file_operations成員函式就直接由裝置驅動提供了,file_operations正是字元裝置驅動的核心。

而對於塊儲存裝置而言,ext2、fat、jffs2等檔案系統中會實現針對VFS的file_operations成員函式,裝置驅動層將看不到file_operations的存在。磁碟檔案系統和裝置驅動將對磁碟上檔案的訪問最終轉換成對磁碟上柱面和扇區的訪問