**注意:**做爲
Android
開發人員,心裏多少有對源碼的嚮往,研究源碼能夠說是開發人員的榮耀,彰顯了對系統的認知度,本文適用於Ubuntu 16.04
上編譯Android 6.0.*
及以上版本,其餘狀況請酌情處理,自行參考官網,源碼針對系統8.0分析。python
@(源碼系列)linux
##摘要 android源碼編譯的四個流程:android
下文也將按照該流程講述.git
##1.源碼下載 因爲牆的緣由,不少人採用國內的鏡像源進行下載。不過筆者經過設置hosts能夠在官方地址上下載源碼,配置項以下:shell
110.4.24.178 www.googlesource.com 110.4.24.178 android.googlesource.com 110.4.24.178 dl-ssl.google.com 110.4.24.178 gerrit.googlesource.com 110.4.24.178 www.google.com 110.4.24.178 google.com 110.4.24.178 google.com.hk 110.4.24.178 www.google.com.hk 110.4.24.178 chromium.googlesource.com
地址查詢來源,參考google代理hosts查詢,按期更新,用起來很是方便。 在ubuntu下,下載代碼仍是比較簡單的,步驟分爲4步:ubuntu
1.下載repo toolapi
mkdir ~/bin PATH=~/bin:$PATH curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod a+x ~/bin/repo
2.初始化repo下載代碼,須要註冊谷歌帳號,與本身git配置相對應,注意姓名的排序,lastName在前。bash
mkdir WORKING_DIRECTORY cd WORKING_DIRECTORY git config --global user.name "Your Name" git config --global user.email "you@example.com"
3.repo初始化,選擇須要下載的分支markdown
repo init -u https://android.googlesource.com/platform/manifest # 若是不填寫分支默認下載master或經過-b切換至對應的分支 repo init -u https://android.googlesource.com/platform/manifest -b android-6.0.1_r1
4.同步android源碼網絡
repo sync
**提示:**這裏,來簡單的介紹下repo工具,咱們知道AOSP項目由不一樣的子項目組成,爲了方便進行管理,Google採用Git對AOSP項目進行多倉庫管理。AOSP項目當前全部的分支列表參看分支列表。
之後若是須要同步最新的遠程代碼到本地,也只須要執行該命令便可。在同步過程當中,若是由於網絡緣由中斷,使用該命令繼續同步便可。不出意外,5個小時即可以將所有源碼同步到本地。
**提示:**必定要肯定代碼徹底同步了,否則在下面編譯過程出現的錯誤會讓你痛不欲生,不肯定的童鞋能夠多用repo sync同步幾回。
因爲網絡緣由,在使用repo sync
同步代碼的過程當中會屢次出錯,總不能時時刻刻刻盯着,能不能在同步失敗的狀況下,自動重試呢?固然能夠,咱們能夠寫一個簡單的shell腳本:
#!/bin/bash #FileName source_asyn.sh PATH=~/bin:$PATH # 注意修改爲你要編譯的版本,固然也能夠不填 repo init -u https://android.googlesource.com/platform/manifest repo sync while [$? = 1]: do echo "=========download failed,again============" sleep 5 repo sync done
將該文件保存在源碼目錄下,也就是咱們的source目錄,而後執行該腳本便可,如今能夠安心的等待源碼下載完成了。
注意:因爲
.repo
目錄是隱藏目錄,所以在下載完成以前你是不看到啥東西的。
##2.源碼編譯 ###2.1編譯環境 源碼下載完成後,就能夠構建編譯環境了。在開始以前,咱們先來看看一些編譯要求:
硬件
磁盤空間越多越好,至少在100GB以上
軟件
|Android版本| 編譯要求的Ubuntu最低版本| 編譯要求的JDK版本| |--| |Android 6.0至AOSP master| Ubuntu 14.04|OpenJDK 8| |Android 5.x至AOSP 6.0| Ubuntu 12.04|OpenJDK 7| |Android 2.3.x至Android 5.0| Ubuntu 12.04|Oracle JDK 6| |Android 1.5至Android 2.2.x| Ubuntu 10.04|Oracle JDK 5|
更具體的能夠參看:Google源碼編譯要求
我如今在Ubuntu 16.04下編譯AOSP主線代碼,所以須要安裝OpenJDK 8,執行命令以下:
sudo apt-get install openjdk-8-jdk
其它需求
sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386 sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev sudo apt-get install git-core gnupg flex bison gperf build-essential sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib sudo apt-get install libc6-dev-i386 sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4 sudo apt-get install lib32z-dev ccache
###2.2初始化編譯 首先初始化編譯環境,確保上述過程完整完成,接下來咱們須要初始化編譯環境,命令以下:
source build/envsetup.sh
不難發現該命令只是引入了其餘執行腳本,至於這些腳本作什麼,目前不在本文中細說.。該命令執行成功後,咱們會獲得了一些有用的命令,好比最下面要用到的lunch命令。
###2.3編譯源碼 初始化編譯環境以後,就進入源碼編譯階段。這個階段又包括兩個階段:選擇編譯目標和執行編譯。 ####2.3.1選擇編譯目標 經過lunch指令設置編譯目標,所謂的編譯目標就是生成的鏡像要運行在什麼樣的設備上。這裏咱們設置的編譯目標是aosp_arm64-eng,所以執行指令:
lunch aosp_arm64-eng
編譯目標格式說明 編譯目標的格式:BUILD-BUILDTYPE,好比上面的
aosp_arm-eng
的BUILD是aosp_arm
,BUILDTYPE是eng
。
什麼是BUILD
BUILD指的是特定功能的組合的特定名稱,即表示編譯出的鏡像能夠運行在什麼環境。其中aosp(Android Open Source Project)表明Android開源項目;arm表示系統是運行在arm架構的處理器上;arm64則是指64位arm架構;處理器x86則表示x86架構的處理器;此外,還有一些單詞表明瞭特定的Nexus設備,下面是經常使用的設備代碼和編譯目標,更多參考官方文檔。
|受型號| 設備代碼| 編譯目標| |:--| |Nexus 6P| angler| aosp_angler-userdebug| |Nexus 5X| bullhead| aosp_bullhead-userdebug| |Nexus 6| shamu| aosp_shamu-userdebug| |Nexus 5| hammerhead| aosp_hammerhead-userdebug|
提示:若是你沒有Nexus設備,那麼一般選擇arm或者x86便可
什麼是BUILDTYPE
BUILD TYPE則指的是編譯類型,一般有三種:
瞭解編譯目標的組成以後,咱們就能夠根據本身目前的狀況選擇了。那不知道編譯目標怎麼辦?咱們只須要執行不帶參數的lunch
指令,稍後控制檯會列出全部的編譯目標,以下:
接着咱們只須要輸入相應的數字便可。 來舉個例子:你沒有Nexus設備,只想編譯完後運行看看,那麼就能夠選擇aosp_arm-eng
。(我在ubuntu 16.04(64位)中編譯完成後啓動虛擬機時,卡在黑屏,嘗試編譯aosp_arm64-eng
解決。所以這裏我使用了aosp_arm64-eng
)
####2.3.2開始編譯 經過make指令進行代碼編譯,該指令經過-j
參數來設置參與編譯的線程數量,以提升編譯速度。好比這裏咱們設置8個線程同時編譯:
make -j8
須要注意的是,參與編譯的線程並非越多越好,一般是根據你機器cup的核心來肯定:core*2
,即當前cpu的核心的2倍。好比我如今的筆記本是雙核四線程的,所以根據公式,最快速的編譯能夠make -j8
。
經過cat /proc/cpuinfo查看相關cpu信息
若是一切順利的化,在幾個小時以後,即可以編譯完成。看到
### make completed successfully (04:16:38(hh:mm:ss)) ###
表示你編譯成功了。
###2.4運行模擬器 在編譯完成以後,就能夠經過如下命令運行Android虛擬機了,命令以下:
source build/envsetup.sh lunch(選擇剛纔你設置的目標版本,好比這裏了我選擇的是2) emulator
若是你是在編譯完後馬上運行虛擬機,因爲咱們以前已經執行過source及lunch命令了,所以如今你只須要執行命令就能夠運行虛擬機:
emulator
不出意外,在等待一會以後,你會看到運行界面:
**補充:**既然談到了模擬器運行,這裏咱們順便介紹模擬器運行所須要四個文件:
Linux Kernel
、system.img
、userdate.img
、ramdisk.img
若是你在使用 lunch命令時選擇的是aosp_arm-eng,那麼在執行不帶參數的emualtor命令時,Linux Kernel默認使用的是/source/prebuilds/qemu-kernel/arm/kernel-qemu
目錄下的kernel-qemu文件;而android鏡像文件則是默認使用source/out/target/product/generic
目錄下的system.img
,userdata.img
和ramdisk.img
,也就是咱們剛剛編譯出來的鏡像文件。
上面我在使用lunch命令時選擇的是aosp_arm64-eng,所以linux默認使用的/source/prebuilds/qemu-kernel/arm64/kernel-qemu
下的kernel-qemu,而其餘文件則是使用的source/out/target/product/generic64
目錄下的system.img
, userdata.img
和ramdisk.img
。
固然emulator指令容許你經過參數制定使用不一樣的文件,具體用法能夠經過emulator --help
查看。
###2.5模塊編譯 除了經過make命令編譯能夠整個android源碼外,Google也爲咱們提供了相應的命令來支持單獨模塊的編譯。編譯環境初始化(即執行source build/envsetup.sh)以後,咱們能夠獲得一些有用的指令,除了上邊用到的lunch,還有如下:
- croot: Changes directory to the top of the tree. - m: Makes from the top of the tree. - mm: Builds all of the modules in the current directory. - mmm: Builds all of the modules in the supplied directories. - cgrep: Greps on all local C/C++ files. - jgrep: Greps on all local Java files. - resgrep: Greps on all local res/*.xml files. - godir: Go to the directory containing a file.
其中mmm指令就是用來編譯指定目錄。一般來講,每一個目錄只包含一個模塊。好比這裏咱們要編譯Launcher2模塊,執行指令:
mmm packages/apps/Launcher2/
稍等一會以後,若是提示:
### make completed success fully ###
即表示編譯完成,此時在out/target/product/gereric/system/app
就能夠看到編譯的Launcher2.apk文件了。
從新打包系統鏡像
編譯好指定模塊後,若是咱們想要將該模塊對應的apk集成到系統鏡像中,須要藉助make snod
指令從新打包系統鏡像,這樣咱們新生成的system.img
中就包含了剛纔編譯的Launcher2模塊了,重啓模擬器以後生效。
單獨安裝模塊
咱們在不斷的修改某些模塊,總不能每次編譯完成後都要從新打包system.img,而後重啓手機吧?有沒有什麼簡單的方法呢? 在編譯完後,藉助adb install命令直接將生成的apk文件安裝到設備上便可,相比使用make snod,會節省不少事件。
補充:咱們來介紹
out/target/product/generic/system
目錄下的內容: 系統自帶apk文件:out/target/product/generic/system/apk
目錄下; 系統可執行文件:out/target/product/generic/system/bin
目錄下; 動態連接庫:out/target/product/generic/system/lib
目錄下; 硬件抽象層文件:out/targer/product/generic/system/lib/hw
目錄下。
###2.6錯誤合集 1. 提示:error processing archive /var/cache/apt/archives/lib32z1-dev_
在安裝依賴的時候有一個依賴不能順利安裝:
sudo apt-get install lib32z-dev ccache
這裏筆者也是安裝你們推薦的依賴安裝,若是出現任何不能安裝的依賴都會去解決一下,解決辦法爲:
sudo dpkg -i --force-overwrite <filename> # 以下例 sudo dpkg -i --force-overwrite /var/cache/apt/archives/lib32z1-dev_1%3a1.2.8.dfsg-2ubtuntu4_amd64.deb # 而後執行 sudo apt-get -f install
問題順利解決。
##3.源碼調試 咱們已經描述了Android源碼在Ubuntu 16.0.4上下載和編譯的過程,目前咱們已經順利的編譯出android的成果文件:
下載源碼初衷咱們是爲了調試代碼,查看其中的運行機制和關鍵過程,理解其精髓。好比咱們對PMS過程不是很瞭解,如何打個斷點查看一下,亦或是根據本身思想改進一下,都是很是值得嘗試的。下面咱們來講說如何調試源碼,一樣這裏的工做平臺仍是ubuntu 16.04和Android Studio。
**參考:**源碼中developent/tools/idegen/README文檔
###3.1調試準備 在源碼中,存在idegen模塊,該模塊專門用來爲idea工具生成系統源碼的project。在開始調試以前,須要確保當前已經編譯過Android源碼了,若是沒有,跳轉至第二章編譯源碼,時間大概4-5個小時。準備過程分爲以下幾個過程:
android.ipr
,android.iml
android.iml
文件提升as啓動速度1.工程文件生成
檢查out/host/Linux-x86/framework/
目錄下是否存在idegen.jar文件,存在則說明你已經編譯過該模塊,若是沒有編譯過則須要編譯。執行以下命令便可:
source build/envsetup.sh mmm development/tools/idegen/
其中mmm development/tools/idegen/
執行完成後會生成idegen.jar,在已經編譯過idegen模塊後,執行:
sudo ./development/tools/idegen/idegen.sh
會在源碼目錄下生成IEDA工程配置文件:android.ipr
,android.iml
文件,文件什麼做用呢?
android.ipr
:一般是保存工程相關的設置,好比編譯器配置入口相關的libraries等android.iml
:則是主要是描述了modules,好比modules的路徑,依賴關係等2.修改android.iml
android源碼的體量仍是很大的,若是直接使用Android Studio
導入工程,須要漫長的等待時間,看代碼仍是選擇source Insight。這就要求咱們有選擇的導入模塊,選擇須要導入。在導入前修改android.iml
文件,經過添加配置的方式告訴AS不導入某些模塊,好比如今我不想導入art模塊,那麼就在android.iml
文件中添加:
<excludeFloder url="file://$MODULE_DIR$"/abi>
格式爲:<excludeFloder url="file://$MODULE_DIR$"/模塊名>
,這裏只保留了framworks和packages模塊,將其餘模塊所有排除了,所以在android.iml
中添加了如下配置:
<excludeFolder url="file://$MODULE_DIR$/.repo" /> <excludeFolder url="file://$MODULE_DIR$/abi" /> <excludeFolder url="file://$MODULE_DIR$/art" /> <excludeFolder url="file://$MODULE_DIR$/bionic" /> <excludeFolder url="file://$MODULE_DIR$/bootable" /> <excludeFolder url="file://$MODULE_DIR$/build" /> <excludeFolder url="file://$MODULE_DIR$/cts" /> <excludeFolder url="file://$MODULE_DIR$/dalvik" /> <excludeFolder url="file://$MODULE_DIR$/developers" /> <excludeFolder url="file://$MODULE_DIR$/development" /> <excludeFolder url="file://$MODULE_DIR$/device" /> <excludeFolder url="file://$MODULE_DIR$/docs" /> <excludeFolder url="file://$MODULE_DIR$/external" /> <excludeFolder url="file://$MODULE_DIR$/hardware" /> <excludeFolder url="file://$MODULE_DIR$/libcore" /> <excludeFolder url="file://$MODULE_DIR$/libnativehelper" /> <excludeFolder url="file://$MODULE_DIR$/ndk" /> <excludeFolder url="file://$MODULE_DIR$/out" /> <excludeFolder url="file://$MODULE_DIR$/pdk" /> <excludeFolder url="file://$MODULE_DIR$/prebuilt" /> <excludeFolder url="file://$MODULE_DIR$/prebuilts" /> <excludeFolder url="file://$MODULE_DIR$/sdk" /> <excludeFolder url="file://$MODULE_DIR$/system" /> <excludeFolder url="file://$MODULE_DIR$/tools" />
3.設置jdk和sdk,導入源碼
在完成android.iml
文件的修改後,將源碼工程導入至AS,以下圖所示:
圖3.1 源碼工程導入至AS
導入時間會比較長,要耐心等待,若是已經將所有項目導入到AS中,而又想排除一些模塊該怎麼辦呢? 此時能夠在Project Scureture的Mobules中進行排除。 爲了排除android sdudio的Sdk中依賴的干擾,須要改進當前的jdk和sdk,讓代碼跳轉也在源碼的文件中,而不能在依賴於外部的sdk項目,點擊Project Structure進入到項目配置頁面:
圖3.2 設置工程的jdk
選擇新建,新建一個jdk,將其classpath標籤下的內容通通刪除,選擇Android API 25 Platform將當前新建的JDK配置給它。
圖3.3 jdk配置給Android API 25 Platform
###3.2調試源碼 搞定上面以後,如今咱們來看看如何用Android Studio一步一步調試代碼。首先使用emulator命令啓動咱們的虛擬機,啓動完虛擬機後,運行的是咱們源碼編譯的最新的系統。接下來打開android studio,打開源碼工程,選擇Attache debugger to Android process
選項,在彈出的Choose Process框內必須選擇Show all processes,不然看不到相關的進程,能夠看到系統的不少進程。如system_process、com.android.systemui、com.android.settings等不少進程。
**注意:**在虛擬機或設備運行了咱們編譯的系統後,擁有的是root權限,能夠查看全部進程,這與咱們前面說的BUILDTYPE爲eng相關,方便開發和調試
選擇任意一個進程,這裏以com.android.settings進程爲例,並在包名爲com.android.settings的SettingsActivity的onCreate()
函數上打上斷點,打開虛擬機的設置,源碼會在onCreate()
函數上中止,此時能夠對源碼進行斷點調試。
##參考