Ubuntu16.04編譯android6.0原始碼
因為最近經常編譯android,每次都要去網上搜索教程,這裡把自己編譯的步驟記錄下來,方便以後查詢。
原始碼下載
安裝git
安裝好了後配置下使用者名稱和郵箱地址。
1 2 3 |
$ sudo apt-get install git $ git config --global user.name "Your Name" $ git config --global user.email "[email protected]" |
安裝curl
1
|
$ sudo apt-get install curl
|
下載repo
repo是google為方便管理android原始碼編寫的一系列python指令碼。
1 2 |
$ mkdir ~/bin $ PATH=~/bin:$PATH |
1 2 |
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo $ chmod a+x ~/bin/repo |
同步程式碼
建立原始碼目錄:
1 2 |
$ mkdir android-6.0.1_r46 cd android-6.0.1_r46 |
1
|
$ repo init -u https://android.googlesource.com/platform/manifest -b android-6.0.1_r1 |
這裡使用google的映象伺服器上同步程式碼,如果你沒有翻牆工具或者下載很慢的話可以使用國內的源,比如清華的,像下面這樣修改~/bin/repo中的REPO_URL。
1
|
REPO_URL = 'https://gerrit-google.tuna.tsinghua.edu.cn/git-repo'
|
然後同樣使用repo init來執行同步的版本。
1
|
$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-6.0.1_r46
|
然後使用下面的命令下載原始碼。因為原始碼比較大,所以下載時間會很長,android6.0.1的程式碼大概有46G左右。repo支援斷線重連,所以直接掛在哪裡就可以了。
1
|
$ repo sync
|
編譯原始碼
安裝openjdk
我們這裡編譯的是android6.0.1,需要先安裝openjdk。
1 2 3 |
$ sudo add-apt-repository ppa:openjdk-r/ppa $ sudo apt-get update $ sudo apt-get install openjdk-7-jdk |
但是在日常使用中,我們更經常使用oracle-jdk,所以如果電腦上安裝了其他版本的jdk的話,可以使用下面的命令來切換當前使用的jdk版本。
1 2 |
$ sudo update-alternatives --config java $ sudo update-alternatives --config javac |
安裝依賴
但是這個網址上只有14.04需要的依賴,經過實驗發現在16.04上不成功。下面是我在網上找到的16.04所需的依賴:
1 2 3 4 5 6 7 8 9 10 |
$ sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386 $ sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib $ 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 lib32z-dev ccache $ sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4 |
修改原始碼
我在編譯原始碼的過程中,編譯到libartd.so時出現瞭如下錯誤:
1
|
clang: error: linker command failed with exit code
|
後來經過搜尋,發現修改art/build/Android.common_build.mk檔案中的:
1
|
ifneq ($(WITHOUT_HOST_CLANG),true)
|
為
1
|
ifeq ($(WITHOUT_HOST_CLANG),false)
|
然後重新編譯即可。
開始編譯
為了提高編譯效率,設定編譯器快取記憶體。
1 2 |
$ echo export USE_CCACHE=1 >> ~/.bashrc $ prebuilts/misc/linux-x86/ccache/ccache -M 50G |
匯入編譯Android原始碼需要的環境變數和其他引數:
1
|
$ source build/envsetup.sh
|
使用lunch命令選擇需要編譯的目標:
1
|
$ lunch
|
我這裡選擇的是1。然後使用make命令開始編譯。可以使用make -j 來設定參與編譯的執行緒數量,一般來說設定為cpu核心數的兩倍。可以使用如下命令檢視當前電腦的cpu核心數量:
1
|
$ cat /proc/cpuinfo
|
大概幾個小時後,就可以編譯成功了。使用emulator命令就可以啟動編譯好的模擬器。
1
|
$ emulator
|
如圖:
啟動模擬器
因為我們匯入的環境變數在關閉shell後就失效了,所以我們不能直接用emulator命令來啟動模擬器。每次啟動模擬器前要先匯入環境變數。
1 2 3 |
$ source build/envsetup $ lunch #這裡選擇編譯時選擇的版本 $ emulator |
執行android模擬器時,
emulator -avd test -no-skin -no-audio -no-window
-
‘-no-skin’表示移除模擬按鈕
-
‘-no-audio’ 表示禁用音訊
-
‘-no-window’ 表示禁用圖形視窗
模組編譯
除了通過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模組,執行指令:
1
|
mmm packages/apps/Launcher2/
|
稍等一會之後,如果提示:
1
|
### make completed success fully ###
|
即表示編譯完成,此時在out/target/product/gereric/system/app就可以看到編譯的Launcher2.apk檔案了.
重新打包系統映象
編譯好指定模組後,如果我們想要將該模組對應的apk整合到系統映象中,需要藉助make snod指令重新打包系統映象,這樣我們新生成的system.img中就包含了剛才編譯的Launcher2模組了.重啟模擬器之後生效.
一些模組位置:
- Android系統自帶的apk檔案都在out/target/product/generic/system/apk目錄下;
- 一些可執行檔案(比如C編譯的執行),放在out/target/product/generic/system/bin目錄下;
- 動態連結庫放在out/target/product/generic/system/lib目錄下;
- 硬體抽象層檔案都放在out/targer/product/generic/system/lib/hw目錄下.
編譯SDK
有時候我們需要自己編譯一個sdk,比如有時候需要使用系統隱藏的api,可以將原始碼目錄中隱藏api的@hide註解去掉,然後使用下面的命令編譯。
1
|
make sdk
|
編譯Nexus裝置的映象
更多的時候我們需要的不是使用模擬器,而是使用真機除錯。這個時候我們可以在lunch命令中選擇適用於Nexus裝置的映象。比如我這裡選擇的是使用於nexus5的aosp-hammerhead-userdebug, 這樣直接編譯出來的映象刷入手機是無法成功使用的,因為沒有驅動。所以我們需要到官網上下載對應的驅動。你可以在這裡選擇對應原始碼映象版本的驅動:
https://developers.google.com/android/nexus/drivers
下載3個壓縮包拷貝到原始碼目錄,然後分別解壓獲得3個sh指令碼,分別執行這3個指令碼檔案,在原始碼目錄會出現一個vendor的資料夾,裡面就包含了nexus5的驅動檔案。
重新編譯原始碼,如果你之前已經編譯過一次,那麼這次會很快完成。編譯完成後,我們就可以刷入裝置了。首先手機進入fastboot模式,可以使用音量上下鍵+電源鍵或者在連線到adb時使用”adb reboot bootloader”進入。然後電腦端進入到/out/host/linux-x86/bin目錄,執行
1
|
$ ./fastboot -w flashall
|
就可以刷入了。刷入完成後手機會自動重啟。這裡的命令表示清空使用者資料然後全部刷入,當然也可以只刷入一部分。
編譯核心
比如我要編譯的是nexus5的核心映象。通過第一個網址我們可以知道它對應的核心版本為’kernel/msm’。在原始碼目錄新建kernel目錄,然後git clone。
1 2 |
$ mkdir kernel $ git clone https://android.googlesource.com/kernel/msm.git #這一步需要代理 |
核心原始碼大小大概有1個多G。clone完後進入msm目錄,可以發現裡面什麼都沒有,因為我們還沒有選擇分支。使用
1
|
$ git branch -a
|
來檢視所有分支。如下圖:
這裡因為我們編譯nexus5 6.0.1的核心,所以使用如下命令:
1
|
git checkout -b android-msm-hammerhead-3.4-marshmallow-mr2 remotes/origin/android-msm-hammerhead-3.4-marshmallow-mr2
|
然後配置一些環境變數:
1 2 3 4 |
$ export ARCH=arm $ export SUBARCH=arm $ export CROSS_COMPILE=arm-eabi- $ make hammerhead_defconfig |
然後使用
1
|
$ make
|
編譯。編譯成功後會在arch/arm/boot目錄下生成一個zImage檔案。將這個檔案替換掉device/lge/hammerhead-kernel中的zImage。或者匯出環境變數
1
|
$ export TARGET_PREBUILT_KERNEL="zImage檔案路徑"
|
然後使用
1
|
$make bootimage
|
重新編譯boot.img。再刷入手機就可以了。