理解 Android Build 系統
Android Build 系統是 Android 原始碼的一部分。關於如何獲取 Android 原始碼,請參照 Android Source 官方網站:
Android Build 系統用來編譯 Android 系統,Android SDK 以及相關文件。該系統主要由 Make 檔案,Shell 指令碼以及 Python 指令碼組成,其中最主要的是 Make 檔案。
眾所周知,Android 是一個開源的作業系統。Android 的原始碼中包含了大量的開源專案以及許多的模組。不同產商的不同裝置對於 Android 系統的定製都是不一樣的。
如何將這些專案和模組的編譯統一管理起來,如何能夠在不同的作業系統上進行編譯,如何在編譯時能夠支援面向不同的硬體裝置,不同的編譯型別,且還要提供面向各個產商的定製擴充套件,是非常有難度的。
但 Android Build 系統很好的解決了這些問題,這裡面有很多值得我們開發人員學習的地方。
對於 Android 平臺開發人員來說,本文可以幫助你熟悉你每天接觸到的構建環境。
對於其他開發人員來說,本文可以作為一個 GNU Make 的使用案例,學習這些成功案例,可以提升我們的開發經驗。
概述
Build 系統中最主要的處理邏輯都在 Make 檔案中,而其他的指令碼檔案只是起到一些輔助作用,由於篇幅所限,本文只探討 Make 檔案中的內容。
整個 Build 系統中的 Make 檔案可以分為三類:
第一類是 Build 系統核心檔案,此類檔案定義了整個 Build 系統的框架,而其他所有 Make 檔案都是在這個框架的基礎上編寫出來的。
圖 1 是 Android 原始碼樹的目錄結構,Build 系統核心檔案全部位於 /build/core(本文所提到的所有路徑都是以 Android 原始碼樹作為背景的,“/”指的是原始碼樹的根目錄,與檔案系統無關)目錄下。
圖 1. Android 原始碼樹的目錄結構
第二類是針對某個產品(一個產品可能是某個型號的手機或者平板電腦)的 Make 檔案,這些檔案通常位於 device 目錄下,該目錄下又以公司名以及產品名分為兩級目錄,圖 2 是 device 目錄下子目錄的結構。對於一個產品的定義通常需要一組檔案,這些檔案共同構成了對於這個產品的定義。例如,/device/sony/it26 目錄下的檔案共同構成了對於 Sony LT26 型號手機的定義。
圖 2. device 目錄下子目錄的結構
第三類是針對某個模組(關於模組後文會詳細討論)的 Make 檔案。整個系統中,包含了大量的模組,每個模組都有一個專門的 Make 檔案,這類檔案的名稱統一為“Android.mk”,該檔案中定義瞭如何編譯當前模組。Build 系統會在整個原始碼樹中掃描名稱為“Android.mk”的檔案並根據其中的內容執行模組的編譯。
編譯 Android 系統
執行編譯
在完成編譯環境的準備工作以及獲取到完整的 Android 原始碼之後,想要編譯出整個 Android 系統非常的容易:
開啟控制檯之後轉到 Android 原始碼的根目錄,然後執行如清單 1 所示的三條命令即可("$"
是命令提示符,不是命令的一部分。):
完整的編譯時間依賴於編譯主機的配置,在筆者的 Macbook Pro(OS X 10.8.2, i7 2G CPU,8G RAM, 120G SSD)上使用 8 個 Job 同時編譯共需要一個半小時左右的時間。
清單 1. 編譯 Android 系統
$ source build/envsetup.sh $ lunch full-eng $ make -j8
這三行命令的說明如下:
第一行命令“source build/envsetup.sh”引入了 build/envsetup.sh
指令碼。該指令碼的作用是初始化編譯環境,並引入一些輔助的
Shell 函式,這其中就包括第二步使用 lunch 函式。
除此之外,該檔案中還定義了其他一些常用的函式,它們如表 1 所示:
表 1. build/envsetup.sh 中定義的常用函式
名稱 | 說明 |
---|---|
croot | 切換到原始碼樹的根目錄 |
m | 在原始碼樹的根目錄執行 make |
mm | Build 當前目錄下的模組 |
mmm | Build 指定目錄下的模組 |
cgrep | 在所有 C/C++ 檔案上執行 grep |
jgrep | 在所有 Java 檔案上執行 grep |
resgrep | 在所有 res/*.xml 檔案上執行 grep |
godir | 轉到包含某個檔案的目錄路徑 |
printconfig | 顯示當前 Build 的配置資訊 |
add_lunch_combo | 在 lunch 函式的選單中新增一個條目 |
第二行命令“lunch full-eng”是呼叫 lunch 函式,並指定引數為“full-eng”。lunch 函式的引數用來指定此次編譯的目標裝置以及編譯型別。在這裡,這兩個值分別是“full”和“eng”。“full”是 Android 原始碼中已經定義好的一種產品,是為模擬器而設定的。而編譯型別會影響最終系統中包含的模組,關於編譯型別將在表 7 中詳細講解。
如果呼叫 lunch 函式的時候沒有指定引數,那麼該函式將輸出列表以供選擇,該列表類似圖 3 中的內容(列表的內容會根據當前 Build 系統中包含的產品配置而不同,具體參見後文“新增新的產品”),此時可以通過輸入編號或者名稱進行選擇。
圖 3. lunch 函式的輸出
第三行命令“make -j8”才真正開始執行編譯。make 的引數“-j”指定了同時編譯的 Job 數量,這是個整數,該值通常是編譯主機 CPU 支援的併發執行緒總數的 1 倍或 2 倍(例如:在一個 4 核,每個核支援兩個執行緒的 CPU 上,可以使用 make -j8 或 make -j16)。在呼叫 make 命令時,如果沒有指定任何目標,則將使用預設的名稱為“droid”目標,該目標會編譯出完整的 Android 系統映象。
Build 結果的目錄結構
所有的編譯產物都將位於 /out 目錄下,該目錄下主要有以下幾個子目錄:
- /out/host/:該目錄下包含了針對主機的 Android 開發工具的產物。即 SDK 中的各種工具,例如:emulator,adb,aapt 等。
- /out/target/common/:該目錄下包含了針對裝置的共通的編譯產物,主要是 Java 應用程式碼和 Java 庫。
- /out/target/product/<product_name>/:包含了針對特定裝置的編譯結果以及平臺相關的 C/C++ 庫和二進位制檔案。其中,<product_name>是具體目標裝置的名稱。
-
/out/dist/:包含了為多種分發而準備的包,通過“
make dist
target”將檔案拷貝到該目錄,預設的編譯目標不會產生該目錄。
Build 生成的映象檔案
Build 的產物中最重要的是三個映象檔案,它們都位於 /out/target/product/<product_name>/ 目錄下。
這三個檔案是:
- system.img:包含了 Android OS 的系統檔案,庫,可執行檔案以及預置的應用程式,將被掛載為根分割槽。
- ramdisk.img:在啟動時將被 Linux 核心掛載為只讀分割槽,它包含了 /init 檔案和一些配置檔案。它用來掛載其他系統映象並啟動 init 程序。
- userdata.img:將被掛載為 /data,包含了應用程式相關的資料以及和使用者相關的資料。
Make 檔案說明
整個 Build 系統的入口檔案是原始碼樹根目錄下名稱為“Makefile”的檔案,當在原始碼根目錄上呼叫 make 命令時,make 命令首先將讀取該檔案。
Makefile 檔案的內容只有一行:“include
build/core/main.mk
”。該行程式碼的作用很明顯:包含 build/core/main.mk 檔案。在 main.mk 檔案中又會包含其他的檔案,其他檔案中又會包含更多的檔案,這樣就引入了整個 Build 系統。
這些 Make 檔案間的包含關係是相當複雜的,圖 3 描述了這種關係,該圖中黃色標記的檔案(且除了 $
開頭的檔案)都位於
build/core/ 目錄下。
圖 4. 主要的 Make 檔案及其包含關係
表 2 總結了圖 4 中提到的這些檔案的作用:
表 2. 主要的 Make 檔案的說明
檔名 | 說明 |
---|---|
main.mk | 最主要的 Make 檔案,該檔案中首先將對編譯環境進行檢查,同時引入其他的 Make 檔案。另外,該檔案中還定義了幾個最主要的 Make 目標,例如 droid,sdk,等(參見後文“Make 目標說明”)。 |
help.mk | 包含了名稱為 help 的 Make 目標的定義,該目標將列出主要的 Make 目標及其說明。 |
pathmap.mk |
將許多標頭檔案的路徑通過名值對的方式定義為對映表,並提供 include-path-for 函式來獲取。例如,通過$(call
include-path-for, frameworks-native) 便可以獲取到 framework 原生代碼需要的標頭檔案路徑。 |
envsetup.mk |
配置 Build 系統需要的環境變數,例如:TARGET_PRODUCT,TARGET_BUILD_VARIANT,HOST_OS,HOST_ARCH 等。 當前編譯的主機平臺資訊(例如作業系統,CPU 型別等資訊)就是在這個檔案中確定的。 另外,該檔案中還指定了各種編譯結果的輸出路徑。 |
combo/select.mk | 根據當前編譯器的平臺選擇平臺相關的 Make 檔案。 |
dumpvar.mk | 在 Build 開始之前,顯示此次 Build 的配置資訊。 |
config.mk |
整個 Build 系統的配置檔案,最重要的 Make 檔案之一。該檔案中主要包含以下內容:
|
definitions.mk | 最重要的 Make 檔案之一,在其中定義了大量的函式。這些函式都是 Build 系統的其他檔案將用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package 等,關於這些函式的說明請參見每個函式的程式碼註釋。 |
distdir.mk | 針對 dist 目標的定義。dist 目標用來拷貝檔案到指定路徑。 |
dex_preopt.mk | 針對啟動 jar 包的預先優化。 |
pdk_config.mk | 顧名思義,針對 pdk(Platform Developement Kit)的配置檔案。 |
${ONE_SHOT_MAKEFILE} |
ONE_SHOT_MAKEFILE 是一個變數,當使用“mm”編譯某個目錄下的模組時,此變數的值即為當前指定路徑下的 Make 檔案的路徑。 |
${subdir_makefiles} |
各個模組的 Android.mk 檔案的集合,這個集合是通過 Python 指令碼掃描得到的。 |
post_clean.mk | 在前一次 Build 的基礎上檢查當前 Build 的配置,並執行必要清理工作。 |
legacy_prebuilts.mk | 該檔案中只定義了 GRANDFATHERED_ALL_PREBUILT 變數。 |
Makefile | 被 main.mk 包含,該檔案中的內容是輔助 main.mk 的一些額外內容。 |
Android 原始碼中包含了許多的模組,模組的型別有很多種,例如:Java 庫,C/C++ 庫,APK 應用,以及可執行檔案等 。並且,Java 或者 C/C++ 庫還可以分為靜態的或者動態的,庫或可執行檔案既可能是針對裝置(本文的“裝置”指的是 Android 系統將被安裝的裝置,例如某個型號的手機或平板)的也可能是針對主機(本文的“主機”指的是開發 Android 系統的機器,例如裝有 Ubuntu 作業系統的 PC 機或裝有 MacOS 的 iMac 或 Macbook)的。不同型別的模組的編譯步驟和方法是不一樣,為了能夠一致且方便的執行各種型別模組的編譯,在 config.mk 中定義了許多的常量,這其中的每個常量描述了一種型別模組的編譯方式,這些常量有:
- BUILD_HOST_STATIC_LIBRARY
- BUILD_HOST_SHARED_LIBRARY
- BUILD_STATIC_LIBRARY
- BUILD_SHARED_LIBRARY
- BUILD_EXECUTABLE
- BUILD_HOST_EXECUTABLE
- BUILD_PACKAGE
- BUILD_PREBUILT
- BUILD_MULTI_PREBUILT
- BUILD_HOST_PREBUILT
- BUILD_JAVA_LIBRARY
- BUILD_STATIC_JAVA_LIBRARY
- BUILD_HOST_JAVA_LIBRARY
通過名稱大概就可以猜出每個變數所對應的模組型別。(在模組的 Android.mk 檔案中,只要包含進這裡對應的常量便可以執行相應型別模組的編譯。對於 Android.mk 檔案的編寫請參見後文:“新增新的模組”。)
這些常量的值都是另外一個 Make 檔案的路徑,詳細的編譯方式都是在對應的 Make 檔案中定義的。這些常量和 Make 檔案的是一一對應的,對應規則也很簡單:常量的名稱是 Make 檔案的檔名除去後綴全部改為大寫然後加上“BUILD_”作為字首。例如常量 BUILD_HOST_PREBUILT 的值對應的檔案就是 host_prebuilt.mk。
這些 Make 檔案的說明如表 3 所示:
表 3. 各種模組的編譯方式的定義檔案
檔名 | 說明 |
---|---|
host_static_library.mk | 定義瞭如何編譯主機上的靜態庫。 |
host_shared_library.mk | 定義瞭如何編譯主機上的共享庫。 |
static_library.mk | 定義瞭如何編譯裝置上的靜態庫。 |
shared_library.mk | 定義瞭如何編譯裝置上的共享庫。 |
executable.mk | 定義瞭如何編譯裝置上的可執行檔案。 |
host_executable.mk | 定義瞭如何編譯主機上的可執行檔案。 |
package.mk | 定義瞭如何編譯 APK 檔案。 |
prebuilt.mk | 定義瞭如何處理一個已經編譯好的檔案 ( 例如 Jar 包 )。 |
multi_prebuilt.mk | 定義瞭如何處理一個或多個已編譯檔案,該檔案的實現依賴 prebuilt.mk。 |
host_prebuilt.mk | 處理一個或多個主機上使用的已編譯檔案,該檔案的實現依賴 multi_prebuilt.mk。 |
java_library.mk | 定義瞭如何編譯裝置上的共享 Java 庫。 |
static_java_library.mk | 定義瞭如何編譯裝置上的靜態 Java 庫。 |
相關推薦深入理解Android Build系統概述 Android Build 系統是用來編譯 Android 系統、Android SDK 以及相關文件的一套框架。在Android系統中,Android 的原始碼中包含了許許多多的模組。 不同產商的不同裝置對於 Android 系統的定製都是不一樣的。如 理解 Android Build 系統Android Build 系統是 Android 原始碼的一部分。關於如何獲取 Android 原始碼,請參照 Android Source 官方網站: Android Build 系統用來編譯 Android 系統,Android SDK 以及相關文件。 《深入理解Android 卷III》第五章 深入理解Android輸入系統《深入理解Android 卷III》即將釋出,作者是張大偉。此書填補了深入理解Android Framework卷中的一個主要空白,即Android Framework中和UI相關的部分。在一個特別講究顏值的時代,本書分析了Android 4.2中WindowManagerS Android build系統中常用LOCAL_變數以下內容節選自本書 編寫模組的編譯檔案,實際就是定義一系列以“LOCAL_”開頭的編譯變數,因此我們有必要弄明白這些變數的具體含義。下面是一些經常使用的LOCAL_編譯變數的說明: 變數名 說明 LOCAL_ASSET_FILES 編譯APK檔案時用於指定資源列表,通常寫成 LOCAL_ android soong build 系統Android soong build系統介紹https://www.jianshu.com/p/80013a768a45android blueprint介紹https://www.jianshu.com/p/32c9d2b04a7bAndroid blueprint 程式 Android編譯系統詳解(一)——build/envsetup.shhttp://www.cloudchou.com/android/post-134.html 準備好編譯環境後,編譯Rom的第一步是 source build/envsetup.sh,該步驟把envsetup.sh裡的函式宣告為當前會話終端可用的命令。這些命令能讓我們 深入理解 Android 系統升級前言 2013年7月至2015年6月在長虹擔任Android系統研發工程師,主要負責長虹智慧電視升級(OTA升級),研發平臺是MST 628 和 MTK 5327等。 摘要 隨著Android系統的快速發展,越來越多的智慧終端裝置搭載Android平臺 Android開發之深入理解Android 7.0系統許可權更改相關文件摘要: Android 6.0之後的版本增加了執行時許可權,應用程式在執行每個需要系統許可權的功能時,需要新增許可權請求程式碼(預設許可權禁止),否則應用程式無法響應;Android 7.0在Android 6.0的基礎上,對系統許可權進一步更改,這次的許可權更改包括三個方 Android build system:構建系統的組成及其原理Android build system 組成部分 Android build system 的組成部分:Gradle + Android plugin for Gradle android app打包流程(即構建流程): Gra 深入理解Android訊息處理系統——Looper、Handler、Thread熟悉Windows程式設計的朋友可能知道Windows程式是訊息驅動的,並且有全域性的訊息迴圈系統。而Android應用程式也是訊息驅動的,按道理來說也應該提供訊息迴圈機制。實際上谷歌參考了Windows的訊息迴圈機制,也在Android系統中實現了訊息迴圈機制。Android通過Looper、Handl android編譯系統分析(一)source build/envsetup.sh與lunch雖然已經有很多人分析過Android的編譯系統的程式碼了,我也看過他們的部落格,也學到了不少知識,但單純的看別人分析,終究還是理解的不深入,所以,我還是要自己再認真的分析一遍。 想想我們編譯android系統的過程: 首先:source build/envsetup 轉:輕松理解 Android Binder,只需要讀這一篇native 線程同步 ntp 並不是 crud 響應 抽象 過程 開源 轉自http://www.jianshu.com/p/bdef9e3178c9 在 Android 系統中,Binder 起著非常重要的作用,它是整個系統 IPC 的基石。網上已經有很多文章講述 理解Android進程創建流程(轉)object c mman appdata sel failed scrip sca emp 不足 /frameworks/base/core/java/com/android/internal/os/ - ZygoteInit.java - Zygote 理解Android線程創建流程(轉)ttr cal 創建失敗 指向 ear long readn nbsp bar /android/libcore/libart/src/main/java/java/lang/Thread.java /art/runtime/native/java_lang_Thread com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: android/support/annotation/ColorRes.class導致 .class div src jar 技術 cnblogs 沖突 信息 保存信息如上: 我在添加一個支持庫的時候遇的問題,這個庫com.yanzhenjie:album:1.0.5 這是由於v4包重復導致的,在網上我也找過多種解決方案 用了這種,方式 confi 打造一個全命令行的Android構建系統命令 匹配 pda 符號鏈接 創建 ack https vim ott IDE都是給小白程序猿的,大牛級別的程序猿一定是命令行控,終端控,你看大牛都是使用vim,emacs 就一切搞定” 這話說的盡管有些絕對。可是也不無道理。做開發這行要想效率高,自己主動化還真是 Android常用系統廣播參考 -s locale pro ebo heads use man 重啟 查看詳情://關閉或打開飛行模式時的廣播Intent.ACTION_AIRPLANE_M;//充電狀態,或者電池的電量發生變化;//電池的充電狀態、電荷級別改變,不能通過組建聲;Intent.ACT Android View系統解析(下)target 過程 getc ets 解包 有時 消息隊列 nbsp 實現 轉載請註明出處:http://blog.csdn.net/singwhatiwanna/article/details/38426471(來自singwhatiwanna的csdn博客)Andr Android面試題3之描寫敘述下Android的系統架構都是 csdn 進行 功能 驅動程序 libraries sso 封裝 rar 描寫敘述下Android的系統架構: Android系統從下往上分為Linux內核層(linux kerner),執行庫(runtime library),應用程序框架層, Android sensor 系統框架 (二)port amp cap 錯誤 str 註釋 hardware war cas 連載上一篇http://www.cnblogs.com/hackfun/p/7327320.html (D) 如何加載訪問.so庫 在前一篇博客http://www.cnblogs.co |