作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!
學習安卓的架構,是從操作系統的角度理解安卓。安卓使用Linux內核,但安卓的架構又與常見的Linux系統有很大的區別。我們先來回顧一下傳統的Linux架構,再來看安卓的變化。
Linux系統架構
先來看常見的Linux系統架構,你可以參考Linux的架構
內核是系統的底層。Linux開機后,內核即啟動,并存活于屬于自己的內存空間,即內核空間(kernel space)。內核的一大功能是和硬件通信。內核中包含各種驅動程序,這些驅動程序既能實現底層的硬件讀寫操作,又包含硬件使用邏輯。比如一臺打印機的驅動,會把打印指令放在內存中的A位置,把打印數據放在內存中的B位置。打印機讀取指令后,會從B位置取得數據打印。在內核上層,驅動程序的功能被抽象為函數調用,比如printx(data)。這個函數調用隱藏了許多細節,比如如何執行讀寫,以及A和B的具體位置。
除了抽象硬件外,內核還維護著Linux的許多重要運行機制,比如虛擬內存、調度器、信號以及進程間通信(IPC)。內核的功能接口是系統調用(system call)函數。
用戶使用C或者C++編寫的程序,將編譯成機器碼,運行成為一個進程(process)。每個進程都會有一個自己的進程空間。進程空間存活于內核空間之外的用戶空間(user space)。進程空間中包含程序的代碼和數據。不同進程的進程空間相互獨立。進程間如果想要相互交流,需要借用特殊的進程間通信(IPC)機制。進程空間中有棧(stack)和堆(heap)。當執行到新的函數調用時,棧頂會增加一幀(stack frame),用于記錄該函數的數據和返回地址。當函數執行完成時,該幀會彈出,并根據返回地址接著執行母程序的指令。堆中的空間由程序自由分配。你可以進一步參考Linux從程序到進程。
一個進程空間
Linux的程序大多是C和C++編寫。代碼被編譯為機器碼,以便計算機理解。常用的代碼被編譯成庫(library)。程序員可以從自己的程序中調用庫函數,來重復利用已有代碼。程序中調用庫函數時,庫中包含的機器代碼會加載入程序對應的進程空間。
Android架構
我們現在來看看安卓的架構。Android的底層使用的是Linux內核。在用戶空間中,每個應用也會運行為一個進程。但安卓細節方面和傳統Linux差別很大。
HAL
安卓驅動硬件的方式與Linux不盡相同。傳統Linux的驅動完全存活于內核空間。Android則在內核外部增加了硬件抽象層(HAL, Hardware Abstraction Layer),把一部分驅動功能放到HAL層中。你或許會奇怪,安卓為什么費盡麻煩增加一個HAL呢?為了保護源代碼。Linux內核采用了GPL協議,所以硬件生產商想要支持Linux系統,必須遵照GPL協議公開硬件驅動的源代碼。但這些源代碼中包含有許多硬件的設計信息,牽涉到硬件生產商的核心利益。而增加了HAL層之后,硬件廠商就不需要開放所有的驅動代碼了。
我們來看看HAL的具體工作方式。安卓的HAL存活在用戶空間,它與內核驅動通信。但HAL是個“空殼”,安卓會根據需要,加載不同的動態庫,比如調用計算機時,載入libprinter.so。這個動態庫是由硬件廠商提供的。比如上面的打印機,硬件廠商可以把讀寫功能做成驅動。而“指令寫入位置A、數據寫入位置B”這樣的高層邏輯,則編譯成庫文件(.so)。當我們使用打印機打印時,我們將打印需求和數據發送給HAL。HAL加載對應的動態庫,通過內核驅動的讀寫功能,將指令寫入打印機的內存位置A,數據寫入位置B。打印機預裝的程序從位置A讀到打印指令,就會從位置B讀取數據,實現打印。這樣,HAL實際上把部分驅動功能放入到動態庫中,內核中的驅動只保留最基本的讀寫操作功能。部分驅動功能從內核空間轉移到了用戶空間。由于高層邏輯是編譯好的.so文件,打印機廠商不用擔心如指令位置A、數據位置B這樣的信息泄露。
左為Linux,右為安卓HAL
安卓的HAL模塊是從Linux內核導出的,所以源代碼公開。HAL是Apache協議,并不要求它的配套程序,如硬件驅動的源碼公開。由于這些庫函數沒有直接調用內核,所以不需要釋放源代碼。通過HAL層,安卓保護了硬件廠商的商業利益,鼓勵了硬件廠商對安卓系統的支持。
當然,Linux開發小組對此很不高興,把安卓的開發分支從Linux內核中刪除。
Dalvik虛擬機
安卓的應用是由Java編寫的,而包括HAL在內的Linux的庫都是由C/C++編寫的,這個落差由Dalvik虛擬機銜接的。當一個應用運行時,進程空間內將包含一個Dalvik虛擬機。Java程序編譯為字節碼文件,運行在Dalvik虛擬機中。根據Java代碼中的要求,Dalvik通過JNI(Java Native Interface)調用底層的C/C++編寫的功能。JNI是從Java中調用C/C++模塊的接口。由于上層接口的標準化,字節碼可以暢通無阻的跨平臺運行。
Dalvik VM
Dalvik虛擬機內部是一個“虛擬”進程空間,有自己的棧和堆,管理代碼的運行流程。如果這以“虛擬”進程空間不足,Dalvik內建的垃圾回收(garbage collection)機制會自動清空堆上不再使用的對象。自動的垃圾回收簡化了程序員的工作,但速度較慢。手動內存管理效率高,但需要更多的編程,且容易犯錯。垃圾回收的具體原理可參考Java內存管理與垃圾回收。
當然,Oracle不高興,認為Dalvik是對JVM赤裸裸的抄襲。
Core Library和Android Framework
Android程序員的主要工作是編寫Dalvik上運行的Java程序。Google提供了核心類庫(Java core library),它包括Java的常用類庫,如:
- java.lang
- java.util
- java.math
- java.net
- ...
這些類庫的API,與Oracle的官方API相同,所以你可以按照同樣的方法調用。
核心類庫中還包括Dalvik虛擬機的調用接口:
- dalvik.annotation
- dalvik.bytecode
- dalvik.system
安卓程序員還可以調用一些針對安卓的類庫,即安卓框架(Android Framework)。這些類庫對應安卓的特定功能。通過它們,我們可以操縱安卓上的各個功能模塊,從觸屏到GPS,從視圖元素到數據庫。如:
- android.database
- android.bluetooth
- android.gesture
- ...
核心類庫和安卓框架是安卓程序員的左膀右臂。再加上Java語言本身的邏輯,這就是安卓程序員戰斗著的世界了。我會在以后的文章中,繼續深入這個戰場。
多謝微博 @文藝復興記 指導我Dalvik的相關內容。下面資料也幫助了我理解:
http://sujaiantony.wordpress.com/2012/06/25/an-android-101-hardware-and-hal/
總結
HAL
Dalvik
Core Library
Android Framework
歡迎繼續閱讀“Java快速教程”系列文章
文章列表
留言列表