安卓第二夜 有趣的架構

Vamei發表於2014-06-05

作者: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快速教程”系列文章

相關文章