Android FrameWork學習(一)Android 7.0系統源碼下載\編譯

最近計劃著研究下 Android 7.0 的系統源碼,之前也沒做過什么記錄,這次正好將學習的內容記錄下來,方便以后復習鞏固。

既然要學習我們的系統源碼,那我們第一步要做的就是下載源碼并進行編譯了。


硬件環境要求

1. 編譯環境

按照官方的說法,編譯 Android 2.3.x 及以上版本的系統源碼需要 64 位的系統運行環境來支持,而編譯 2.3.x 以下的版本則需要 32 位的系統運行環境。

2. 硬盤空間

官方建議最好預留 100G 的磁盤空間來下載源碼,150G 的磁盤空間用來編譯源碼,如果使用了 ccache(一個高速編譯緩存工具,可以大幅加快 gcc 的編譯速度),那么則需要更大的空間來支持。

所以盡可能地保證自己的磁盤空間夠大吧,之前就因為磁盤空間預留不夠導致源碼編譯過程中空間不足,狠狠地把自己坑了一把。

3. 內存空間

如果你是在虛擬機上跑 linux,官方建議至少需要 16G 的內存空間,我的機器只有 8G 的內存空間跑虛擬機,目前跑起來也沒太大問題,就是編譯源碼的過程非常漫長,不知道是否跟內存大小有關。


軟件環境要求

1. 操作系統

Android 系統的源碼的編譯支持 Linux 跟 Mac OS 兩種操作系統,一般情況下,Android 系統源碼都是在 Linux Ubuntu 系統上進行開發與測試的,所以如果你準備使用 Linux 系統來進行源碼編譯,那一般推薦安裝 Ubuntu 版本的 Linux。

下面列出了各 Android 版本與編譯系統版本的對應關系

Linux:

Android 版本 GNU/Linux
Android 6.0 (Marshmallow) - Android最新版本 Ubuntu 14.04 (Trusty)
Android 2.3.x (Gingerbread) - Android 5.x (Lollipop) Ubuntu 12.04 (Precise)
Android 1.5 (Cupcake) - Android 2.2.x (Froyo) Ubuntu 10.04 (Lucid)

Mac OS

Android 版本 Mac OS (Intel/x86)
Android 6.0 (Marshmallow) - Android最新版本 Mac OS v10.10 (Yosemite) or later with Xcode 4.5.2 and Command Line Tools
Android 5.x (Lollipop) Mac OS v10.8 (Mountain Lion) with Xcode 4.5.2 and Command Line Tools
Android 4.1.x-4.3.x (Jelly Bean) - Android 4.4.x (KitKat) Mac OS v10.6 (Snow Leopard) or Mac OS X v10.7 (Lion) and Xcode 4.2 (Apple's Developer Tools)
Android 1.5 (Cupcake) - Android 4.0.x (Ice Cream Sandwich) Mac OS v10.5 (Leopard) or Mac OS X v10.6 (Snow Leopard) and the Mac OS X v10.5 SDK

2.JDK 版本要求

不同的Android版本編譯也需要對應的 JDK 環境,這里列出了各版本之間的對應關系

|Android 版本|JDK 版本(Ubuntu)|JDK 版本(Mac OS)|
|---|---|
|Android 目前最新版本| OpenJDK 8| jdk 8u45 or newer|
|Android 5.x (Lollipop) - Android 6.0 (Marshmallow)|OpenJDK 7|jdk-7u71-macosx-x64.dmg|
|Android 2.3.x (Gingerbread) - Android 4.4.x (KitKat)|Java JDK 6|Java JDK 6|
|Android 1.5 (Cupcake) - Android 2.2.x (Froyo)|Java JDK 5| |


搭建編譯環境

根據上面列出的軟硬件要求,我們可以根據自己要編譯的 Android 版本以及自己的設備來選擇合適的系統及JDK,接下來我們就來說說如何搭建編譯環境。

這里我們主要針對Android 7.0的需要的編譯環境分別對 Linux 和 Mac OS 進行配置:

設置 Linux 系統編譯環境

1.安裝 JDK

Android 7.0目前需要 openJDK 8的 JDK 環境

Ubuntu 15.04+

如果你的系統是 Ubuntu 15.04 及以上版本的話,直接運行如下指令即可直接安裝:

$ sudo apt-get update
$ sudo apt-get install openjdk-8-jdk
Ubuntu 14.04

如果你使用的是 Ubuntu 14.04 版本,現在并沒有專門針對14.0.4可用的 open jdk8 的包,

但是 Ubuntu 15.04 OpenJDK 8 的包可以在 14.0.4 上成功地運行,所以我們下載 Ubuntu 15.04 OpenJDK 8 的安裝包來手動安裝:

  1. archive.ubuntu.com上依次下載下面列出的64位的 open JDK 8 的.deb安裝包
    openjdk-8-jre-headless_8u45-b14-1_amd64.deb
    openjdk-8-jre_8u45-b14-1_amd64.deb
    openjdk-8-jdk_8u45-b14-1_amd64.deb

  2. 安裝 .deb 包
    先運行 apt-get 指令更新軟件列表

sudo apt-get update

接著依次對上面下載的三個 deb 文件運行如下指令進行安裝:

sudo dpkg -i 下載的文件地址

最后運行 apt-get -f 指令修復安裝依賴的包

sudo apt-get -f install
  1. 更新系統默認使用的 JDK 版本
    如果你的系統安裝了多個版本的 JDK,可以通過下面的指令執行切換,會彈出可選的 JDK 版本,根據你的需要選擇對應的版本就可以了:
sudo update-alternatives --config java
sudo update-alternatives --config javac

2.安裝所需要的工具包

Ubuntu 14.04

我們編譯過程中會用到下面的依賴包,執行如下指令統一安裝:

sudo apt-get install git-core gnupg flex bison gperf build-essential \
  zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
  lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \
  libgl1-mesa-dev libxml2-utils xsltproc unzip

3.設置源碼編譯輸出路徑

默認情況下,編譯好的系統源碼會在源碼所在目錄的out文件夾下,
如果你希望調整輸出目錄的路徑,可以執行下面的指令指定輸出目錄:

export OUT_DIR_COMMON_BASE=<path-to-your-out-directory>

4.設置 USB 接口訪問設備

在linux下,默認情況是不允許普通用戶直接通過 USB 接口來訪問設備的.

推薦方法是以根用戶身份在 /etc/udev/rules.d/51-android.rules 路徑創建文件。

我們可以通過如下指令來實現(注意用你的系統username替換指令中的<username>):

wget -S -O - http://source.android.com/source/51-android.rules | sed "s/<username>/$USER/" | sudo tee >/dev/null /etc/udev/rules.d/51-android.rules; sudo udevadm control --reload-rules

設置 Mac OS 系統編譯環境

Mac OS 的文件系統默認情況下保留了大小寫實際上卻又不區分大小寫。
目前的git指令無法支持這樣的文件系統,會導致一些莫名其妙的錯誤,所以在 Mac OS 上編譯 Android 系統源碼,我們必須先創建一塊區分大小寫的磁盤鏡像。

創建一塊區分大小寫的磁盤鏡像

這里我們直接通過命令行來創建:

hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 40g ~/android.dmg

該指令會在系統根目錄下生成一個 android.dmg 或是 android.dmg.sparseimage 文件,一旦掛載,將被作為支持 Android 開發所需格式的驅動鏡像分區。

如果之后你需要更大的空間,你可以通過下面的指令進行空間調整:

hdiutil resize -size <new-size-you-want>g ~/android.dmg.sparseimage

你還可以在 ~/.bash_profile 文件中,添加幫助函數來掛載跟取消掛載:

# mount the android file image
function mountAndroid { hdiutil attach ~/android.dmg -mountpoint /Volumes/android; }

#如果創建dmg文件時生成的是android.dmg.sparseimage文件,則使用
function mountAndroid { hdiutil attach ~/android.dmg.sparseimage -mountpoint /Volumes/android; }
# unmount the android file image
function umountAndroid() { hdiutil detach /Volumes/android; }

之后我們就可以通過執行 mountAndroid 指令來執行掛載鏡像,通過 umountAndroid 指令來取消掛載。

安裝 JDK

安裝工具依賴包
1. 安裝 xcode 命令行工具
$ xcode-select --install

對于老版本的 Mac OS 系統(10.8或者10.8之前的),我們需要到蘋果開發者站點進行下載安裝.
如果你還沒有注冊成為蘋果開發者,你需要先注冊一個蘋果賬號來進行下載.

2. 到 macports.org 上下載對應Mac OS版本的 macports (類似于Linux下的 apt-get,用來幫助你安裝其他應用程序)

注意:確保 /opt/local/bin 在路徑 /usr/bin 前,如果沒有,在 ~/.bash_profile 文件中進行添加

export PATH=/opt/local/bin:$PATH

注意:如果根目錄下沒有 .bash_profile 文件,那就手動創建一個

3. 通過 macports 安裝 make , git 以及 GPG
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg

如果使用的是 Mac OS X v10.4 版本的系統,還需要安裝 bison :

$ POSIXLY_CORRECT=1 sudo port install bison

注意:如果是編譯 Android 4.0.x 及以下版本的系統,gmake 3.8.2 版本存在一個 bug,需要還原到 gmake 3.8.1


優化編譯環境(可選)

設置 ccache

我們可以自由選擇是否開啟 ccache 編譯工具。

ccache 是一個高速編譯緩存工具,它通過將頭文件高速緩存到源文件之中而改進了構建性能,因而通過減少每一步編譯時添加頭文件所需要的時間而提高了 C\C++ 的構建速度。

從編譯的全過程來看,不使用 ccache 的情況下,編譯過程中會多次解析相同的頭文件,浪費了處理器周期,更重要的是浪費了開發者的時間,因為他們要等待這一過程的完成。在一個團隊中,這一影響可能會更為明顯,因為團隊成員可能會反復編譯解析相同的頭文件。

所以,一般對于專門用來編譯系統的服務器或是大容量的生產環境,這個功能比較有用,它可以加速重新編譯的速度。

注意:如果你只是個人開發者,不是專門的編譯服務器,不需要進行增量構建的話,那么使用 ccache 可能會因為高速緩存缺失而降低你的構建速度。

開啟 ccache

要開啟 ccache,在源碼樹的根路徑下執行下面的指令:

$ export USE_CCACHE=1
$ export CCACHE_DIR=/<path_of_your_choice>/.ccache
$ prebuilts/misc/linux-x86/ccache/ccache -M 50G

緩存的大小一般設置為50G-100G

接著在 .bashrc (或者 etc/profile )中添加下面的指令

export USE_CCACHE=1

默認情況下,緩存會存在home根目錄的 ~/.ccache 中,但是如果你使用的是NFS或者其他的非本地文件系統,那么你同樣需要在 .bashrc 指定緩存目錄地址

在 Mac OS 的系統中,你需要將 linux-x86 替換成 darwin-x86:

prebuilts/misc/darwin-x86/ccache/ccache -M 50G

當編譯的 Android 系統是4.0.x或者更老的版本,ccache 的緩存路徑會有所不同

prebuilt/linux-x86/ccache/ccache -M 50G

這個設置會一直存儲在 CCACHE_DIR 中。

在Linux上,你可以通過以下指令開啟對 ccache 的監聽:

$ watch -n1 -d prebuilts/misc/linux-x86/ccache/ccache -s

下載源碼

編譯環境配置好之后,我們就可以開始下載我們的源碼了

安裝 Repo

Repo 是 google 用 python 寫的一個腳本工具,Android 使用 git 作為代碼管理工具,一個 Android 系統由 N 多個 git 庫構成,如果手動進行一個個下載,那簡直是一件非常痛苦的事,而 repo 就是用來對這些 git 庫進行維護管理跟下載的。

通過 Repo 工具,我們可以輕松地完成 Android 系統源碼的下載。

1.在系統 home 根路徑下創建bin目錄并且添加到 path 路徑中:
#創建bin目錄
$ mkdir ~/bin

#把bin目錄的路徑添加到PATH中
$ PATH=~/bin:$PATH
2.下載 repo 工具并設置其可執行
#curl 是個開源文件傳輸工具,在這里是把遠程的 repo 文件下載到指定的 ~/bin/repo 路徑
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo

#修改 repo 對所有人可執行
$ chmod a+x ~/bin/repo

初始化 Repo 客戶端

1.創建一個空目錄用來存放我們的 Android 系統源碼,名字自己隨便定
#創建名為 WORKING_DIRECTORY 的目錄
$ mkdir WORKING_DIRECTORY

#進入到創建的目錄中
$ cd WORKING_DIRECTORY
2.初始化 repo 倉庫

從主干 master 下載源碼,目前最新版本

$ repo init -u https://android.googlesource.com/platform/manifest

如果需要下載某個特定版本系統的分支,可以在上述命令后加 -b 版本分支號,這里我指定 Android 7.0 的版本分支

$ repo init -u https://android.googlesource.com/platform/manifest -b android-7.1.0_r7

具體的版本分支號可以到這個地址查看(需要翻墻):
Android系統個版本分支號

3.同步源碼到本地

這時執行 sync 指令便可以自動下載源碼到本地了

$ repo sync

使用國內鏡像下載源碼

由于國內網絡的問題,上述操作的源碼下載需要翻墻才能進行,速度會受到很大影響,幾十G的系統源碼可能需要花上上周的時間才能下完,

因此我們可以選擇國內的鏡像進行源碼下載:

清華大學的鏡像站
參照頁面上的描述對上面的指令稍作調整便可以了,站點上寫得比較詳細,這里我們就不作贅述了。

根據網速的不同,一般一天之內能夠下載完畢。

對于下載下來的源碼,我們并不能直接刷到我們的目標設備上或者是使用模擬器運行,我們必須對源碼進行編譯生成對應的 image 二進制鏡像文件,
當然你也可以直接從官網下載對應系統版本的鏡像文件(需翻墻):
Google's Nexus driver page
Binaries Preview for Nexus Devices

這里我們還是自己來編譯下源碼,熟悉下整個編譯過程。


源碼編譯

首先我們通過命令行進入到源碼目錄中,我這里目錄的名稱是aosp

cd aosp

清空輸出目錄

為了確保我們編譯生成的文件不受之前 build 構建的文件影響,我們在源碼目錄中執行下面的指令,該指令會清空 out 輸出目錄中的所有文件

$ make clobber

設置編譯環境

首先我們通過源碼 build 目錄中的 envsetup.sh 腳本文件初始化我們的編譯環境,執行

$ source build/envsetup.sh

$ . build/envsetup.sh

這兩個指令的效果是一樣的,會初始化一些有用的命令工具

Paste_Image.png

我們后面執行的一些指令必須在初始化 envsetup之后才能執行

選擇編譯目標

接著我們通過 lunch 指令來選擇我們需要編譯的目標
執行lunch指令

$ lunch

會彈出可選目標項:

Paste_Image.png

所有的構建目標由 BUILD-BUILDTYPE 的形式組成:
BUILD 對應 codename

這是官方提供的一份對照表:

|Device| Code name| Build configuration
|---|---|
|Pixel XL |marlin |aosp_marlin-userdebug|
|Pixel|sailfish |aosp_sailfish-userdebug|
|HiKey| hikey| hikey-userdebug|
|Nexus 6P| angler |aosp_angler-userdebug|
|Nexus 5X |bullhead |aosp_bullhead-userdebug|
|Nexus 6 |shamu |aosp_shamu-userdebug|
|Nexus Player |fugu| aosp_fugu-userdebug|
|Nexus 9 |volantis (flounder) |aosp_flounder-userdebug|
|Nexus 5 (GSM/LTE) |hammerhead |aosp_hammerhead-userdebug|
|Nexus 7 (Wi-Fi) |razor (flo) |aosp_flo-userdebug|
|Nexus 7 (Mobile) |razorg (deb) |aosp_deb-userdebug|
|Nexus 10 |mantaray (manta) |full_manta-userdebug|
|Nexus 4 |occam (mako) |full_mako-userdebug|
|Nexus 7 (Wi-Fi) |nakasi (grouper)| full_grouper-userdebug|
|Nexus 7 (Mobile)| nakasig (tilapia)| full_tilapia-userdebug|
|Galaxy Nexus (GSM/HSPA+)| yakju (maguro)| full_maguro-userdebug|
|Galaxy Nexus (Verizon) |mysid (toro) |aosp_toro-userdebug|
|Galaxy Nexus (Experimental) |mysidspr (toroplus) |aosp_toroplus-userdebug|
|Motorola Xoom (U.S. Wi-Fi) |wingray |full_wingray-userdebug|
|Nexus S| soju (crespo)| full_crespo-userdebug|
|Nexus S 4G |sojus (crespo4g) |full_crespo4g-userdebug|

BUILD_TYPE 對照表:

構建類型 用途
user 有限的訪問權限,主要用于發布正式產品,沒有 root 跟調試權限
userdebug 跟 user 類型差不多,但是多了 root 跟 debug 調試權限
eng 擁有各種調試工具的開發版設置,擁有 root 跟 debug 權限

如果作為開發使用的話,那我們一般都是選 -eng,

這里我自己是準備在模擬器上運行編譯的 image 鏡像,并且我電腦的 cpu 是 intel x86 的,所以我選擇了 6. aosp_x86-eng

我們可以根據自己的需要選擇對應的 cpu 類型。

注意:我們知道,Android 官方的模擬器速度很慢,
Intel 特意提供了一個叫 HAXM 的虛擬硬件加速技術,全稱為:Intel Hardware Accelerated Execution Manager.

只要你的 CPU 是 intel 的產品并且支持 VT(virtualization Technology)就可以使用 HAXM 技術將你的模擬器的速度提升至真機的水平。

目前 Intel 只提供了 windows 版和 MAC 版,Linux 系統只有通過安裝 KVM 來達到這個效果。

安裝 KVM

首先我們檢測下自己的 cpu 是否支持 hardware virtualization(硬件虛擬化)

egrep -c '(vmx|svm)' /proc/cpuinfo
Paste_Image.png

輸出的值如果是大于 0 的,則表明你的 cpu 支持

如果你使用的是 vmware 虛擬機安裝的 linux,注意要設置下虛擬機的 cpu 來支持硬件虛擬化,先關閉虛擬機,然后右鍵虛擬機=》設置,選中 cpu,勾選虛擬化 Intel VT 項,這樣就能支持 KVM 了。

Paste_Image.png

對于 Ubuntu 10.0.4 以上的版本,我們通過下面的指令安裝 KVM 即可

sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils

如果在安裝 KVM 的過程中有什么疑問的話,可以訪問下面這個網址查找方法:https://help.ubuntu.com/community/KVM/Installation

這樣,在編譯完目標 intel cpu 的鏡像文件后,我們運行模擬器就會自動進行加速了。

編譯源碼

好了,一切就緒,我們可以開始編譯我們的源碼了,
我們在源碼路徑下通過 make -jN 指令來進行源碼編譯,這里的 N 一般建議設置為 cpu 核心線程數的 1-2 倍。

$ make -j4

一般情況下,我們等待源碼編譯完成就可以了,不過從 Android 7.0 N 開始,make 指令默認會開啟 Jack 編譯工具鏈來進行 Java 代碼的編譯,這個過程中可能會出現一些問題。

什么是 Jack 編譯工具鏈 (The Jack toolchain)?

我們知道,我們平時編譯 Android 代碼的時候會先將 Java 代碼編譯成 .class 文件,最終再轉換成 .dex 文件,如圖:

Paste_Image.png

而 Jack 編譯工具鏈則跳過了編譯成 .class 文件這一過程,直接將 Java 代碼編譯成 .dex文件

Paste_Image.png

它的優勢:

  • 完全開放源碼
    源碼均在 AOSP 中,合作伙伴可貢獻源碼
  • 加快編譯源碼
    Jack 提供特殊的配置,減少編譯時間:pre-dexing ,增量編譯和Jack編譯服務器.
  • 支持代碼壓縮,混淆,重打包和 multidex
  • 不在使用額外單獨的包,例如 ProGuard。

如果想進一步了解 Jack,可以訪問Compiling with Jack(需翻墻),這里就不作太多解釋了。

按照官方的說法 Jack 可以加快編譯速度

但實際編譯過程中,在我的設備上 Jack 會占用大量內存,并且拖慢編譯速度,還會報錯,而且官方文檔上寫的配置方式對 Jack 并不起作用。

Jack編譯過程中遇到的問題
編譯過程中報 Out of memory error 并中斷編譯

在執行 make 指令后,當第一次編譯 Java 代碼的時候,Jack 會被啟用,這個時候經常會卡住,并且一段時間后報錯 Out of memory error

按照官方的說法, Jack 并行編譯的時候占用的資源太大導致內存溢出了

可以通過在 $HOME/.jack 文件中減小 SERVER_NB_COMPILE 的值來減小并行編譯數量, SERVER_NB_COMPILE 的值默認為4

但實際情況是 Jack 沒有在根路徑下生成 .jack 文件,并且手動創建設置 SERVER_NB_COMPILE 后重啟 Jack 服務也沒有效果。

經測試發現 make 編譯過程中當 Jack 第一次被啟用時會在 home 根路徑下生成 .jack-server 目錄

Paste_Image.png

可以通過修改該目錄中 config.properties 文件里的.jack.server.max-service值來設置并發線程數。

Paste_Image.png

同時,你也可以設置增加 Jack 的內存容量來解決這個問題,指令如下

export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4096m"

然后進入到輸出路徑的 bin 目錄下:

cd /home/cjpx00008/aosp/out/host/linux-x86/bin

執行下面的指令重啟 Jack 服務

./jack-admin stop-server

./jack-admin start-server

我改了 service 大小,同時增加了內存,后來編譯的過程中沒有發生其他問題。

有辦法關閉 Jack 編譯嗎?

既然Jack有問題,那我們可以關閉 Jack 編譯嗎?

目前來說我還沒有找到如何在 Android 7.0 編譯的時候關閉 Jack,如果有知道的小伙伴歡迎留言告訴我哈,感激不盡??!

運行編譯出的 image 鏡像

經過漫長的等待,我們的源碼終于編譯結束了,是時候來運行編譯出的 image 鏡像了。

這時我們只要在源碼目錄下執行 emulator 指令即可運行模擬器

$ emulator

第一次啟動時間可能會有點長,耐心等待即可


Paste_Image.png

運行成功了,是不是有點小激動呢!

注意:如果你的命令行窗口關閉重開了,那 emulator 指令可能會提示找不到命令,我們可以在源碼根目錄環境下,通過 envsetup.sh 重新初始化命令,運行 lunch 指令選擇編譯目標,這個時候你再運行 emulator 就不會提示找不到指令了(每次關閉命令行窗口都需要重新運行如下指令才能執行 emulator)

也可以通過配置環境變量來設置 emulator 指令,不過我沒有成功,哈哈

$ source build/envsetup.sh
$ lunch
$ emulator

好啦,到此,我們的源碼就編譯完畢啦,下一篇我們來聊聊如何使用 Android Studio 導入 Android 系統源碼,并通過 AS 進行 Java 源碼調試,以及使用 GDB 來調試系統 Native C\C++ 源碼。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容