1. 程式人生 > >Ubuntu16.04編譯android6.0原始碼

Ubuntu16.04編譯android6.0原始碼

2016-08-25

因為最近經常編譯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

如圖:
Screenshot from 2016-08-25 15-05-34.png

啟動模擬器

因為我們匯入的環境變數在關閉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

來檢視所有分支。如下圖:
Screenshot from 2016-08-28 16-38-10.png

這裡因為我們編譯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。再刷入手機就可以了。