Ubuntu 14.04編譯AOSP for Nexus/Pixel
前言
雖說幾年前博主在一家公司做機頂盒的時候總是需要編譯Android原始碼,但是那時還沒有手中的愛機:Nexus 6,又名shamu。今天我要為它刷入一個自己編譯的Rom。拿起鍵盤就是幹。
筆者注:AOSP:Android Open Source Project,安卓開源專案
準備
- Ubuntu 14.04+
- OpenJDK/JDK
- Nexus/Pixel手機一部
假設你已經有了一個較新的Ubuntu系統和一部谷歌親兒子手機,下文將從安裝jdk開始。
AOSP編譯環境搭建
安裝OpenJDK
警告:不要使用oracle jdk來編譯較新(API 21+/Android 5.0及以上)的AOSP,會在準備編譯工作make
clobber時出現錯誤提示.
Checking build tools versions... ************************************************************* You asked for an OpenJDK based build but your version is java version "1.8.0_121" Java(TM) SE Runtime Environment(build 1.8.0_121-b13)Java HotSpot (TM)64 bit Server VM(build 25.121-b13), mixed mode). ************************************************************* build/core/main.mk:230: *** stop.
關於JDK版本的選擇:根據你想編譯的Android版本來決定
- AOSP最新原始碼: OpenJDK 8
- Android 5.x (Lollipop) - Android 6.0 (Marshmallow):OpenJDK 7
- Android 2.3.x (Gingerbread) - Android 4.4.x(KitKat):Java JDK 6
- Android 1.5 (Cupcake) - Android 2.2.x (Froyo): Java JDK 5
博主想要編譯的是Android 7.0,所以需要使用是OpenJDK 8。
博主是用的Ubuntu 14.04 LTS,可採取安裝deb包或者新增ppa兩種方式安裝OpenOJDK 8:
1. OpenJDK deb包下載:
2. 新增ppa方式安裝OpenJDK
$ sudo add-apt-repository ppa:openjdk-r/ppa
$ sudo apt-get update
$ sudo apt-get install openjdk-8-jdk
$ sudo update-alternatives --config java
$ sudo update-alternatives --config javac
假如你Ubuntu是15.04或者更新的系統,可直接執行下列命令進行OpenJDK 8安裝
$ sudo apt-get update
$ sudo apt-get install openjdk-8-jdk
Linux使用下列命令檢視機器中所有jdk版本
$ [email protected]-ThinkPad:~/AOSP_NBD91Z$ update-java-alternatives -l
// 打印出下面已安裝的jdk版本
java-1.8.0-openjdk-amd64 1069 /usr/lib/jvm/java-1.8.0-openjdk-amd64
Linux設定預設JDK命令
// 設定預設為openjdk8,此處必須選用OpenJDK8
$ sudo update-java-alternatives -s java-1.8.0-openjdk-amd64
// 設定預設為oracle jdk8
$ sudo update-java-alternatives -s java-8-oracle
// 設定預設為oracle jdk7
$ sudo update-java-alternatives -s java-7-oracle
Ubuntu 14.04設定預設OpenJDK 8時出現一處警告提示:
update-java-alternatives: plugin alternative does not exist: /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/IcedTeaPlugin.so
該提示無需理會,可直接忽略。
檢視Java版本,出現以下提示,說明jdk環境已經ok。
$ java -version
openjdk version "1.8.0_111"
OpenJDK Runtime Environment (build 1.8.0_111-8u111-b14-3~14.04.1-b14)
OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)
如果實在切換不了預設jdk,就像博主一樣,卸了oracle jdk吧。
安裝必要軟體
在你的Ubuntu 14(x64)上執行以下命令
$ 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
會有些已經安裝,有些無法安裝,或者安裝失敗,無需理會,繼續往下。其他系統版本系統請直接參考:Establishing a build environment
配置USB訪問許可權
ps:不知道這個幹啥的,但是官方是這麼建議的,為了讓普通使用者可訪問usb裝置。
$ 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
安裝repo
安裝repo以下載AOSP原始碼。repo是Google根據git開發來專門管理Android原始碼用的,具有斷點續傳的特性。其主要命令可參考:git/repo常用命令一覽。依次執行下面命令。
$ cd ~
$ mkdir bin
$ PATH=~/bin:$PATH
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo # 給repo新增執行許可權
配置git
由於需要下載Android原始碼,你需要事先準備好一個google的gmail郵箱。執行以下命令配置git使用者名稱和gmail郵箱。
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
下載AOSP原始碼
建立一個目錄以存放Android原始碼
$ mkdir ~/AOSP_NBD91Z # 目錄名請自行定義,本文以AOSP_NBD91ZNBD91Z為例
$ cd AOSP_NBD91Z
AOSP原始碼編譯預設是不適配驅動的,只適合模擬器執行,由於博主想要為Nexus 6編譯,所以需要考慮驅動問題,根據上文第二個連結找到shamu的最新驅動,目前(20170307)最新的驅動支援到build NBD91Z,將驅動下載下來,留著備用。
在第一個連結中找到對應的branch name(android-7.0.0_r29)。
在AOSP本地目錄初始化repo分支
$ cd ~/AOSP_NBD91Z
$ repo init -u https://android.googlesource.com/platform/manifest -b android-7.0.0_r29
下載/續傳AOSP原始碼
無論是第一次開始下載,還是中途斷掉後接著續傳下載,都是執行以下命令。
$ repo sync
之後就是漫長的等待了,該分支(android-7.0.0_r29)程式碼總共約80G(含版本管理檔案.repo目錄46G)。
這裡提醒下各位,分割槽的時候一定記得至少至少至少給到120G啊,80G還不是最新分支的大小呢。編譯後更加大得多:該分支編譯出的out目錄共30G左右。
不過下載完成後,如果沒什麼版本控制的需要 .repo目錄倒是可以刪除掉,節省點硬碟空間。
編譯AOSP預備工作
設定編譯快取(可選操作)
可加速後續第二次編譯,如需要,可在原始碼目錄執行以下命令
$ export USE_CCACHE=1
$ export CCACHE_DIR=~/AOSP_NBD91Z/.ccache # 目錄自定義
$ prebuilts/misc/linux-x86/ccache/ccache -M 50G # 官方推薦50-100G
更新環境變數
$ vim ~/.bashrc
# 新增以下這行
export USE_CCACHE=1
$ source ~/.bashrc
釋放手機驅動
將上述下載的幾個驅動檔案解壓到原始碼根目錄
,解壓後也就是幾個指令碼檔案,依次執行,以釋放驅動,畫風大概如下
共8大條款,幾十個小條款,一行行回車按過去,心累啊。
劃重點:在執行驅動指令碼後,會讓你看一大長串協議,最後你需要輸入:I ACCEPT 來同意驅動的協議,方可釋放驅動檔案。按回車按快了則提示你沒有同意,驅動未釋放成功。成功之後會多出一個vendor目錄。
清理編譯檔案
驅動釋放完畢,先執行make clobber
清理下編譯後文件的目錄,第一次編譯其實博主覺得這個命令無所謂。
相似命令:
make clean
它清理out/target/product/[product_name]目錄。
編譯AOSP
準備好編譯平臺
$ cd AOSP_NBD91Z
$ source build/envsetup.sh
# or 或者,上面的命令和下面的命令等價
$ . build/envsetup.sh
選擇編譯平臺
執行上述命令後方可執行這條命令lunch
由於筆者手中是Nexus 6(shamu),所以果斷選擇了21
關於幾種模式的區別
- user 正常模式,給普通使用者用的
- userdebug 具備root許可權和更多除錯功能,其他和user模式無異
- eng 開發者的最佳選項,具有許多額外的除錯工具
正式編譯AOSP原始碼
執行make
進行編譯,也可以使用-j選項指定並行編譯執行緒數量
# 利用6個執行緒進行編譯。官方建議的最快並行執行緒數量為:j16-j32之間。
$ make -j6
# 請各位根據自身CPU效能量力而行。博主曾經使用-j16導致GUI介面和終端統統卡死,只能強制關機,心疼我的ssd硬碟30s。
又是一次漫長的等待啊,如果不出什麼問題,那麼在out/target/product/[product_name]/
目錄下將會多出諸如system.img,recovery.img等等,就可以愉快的刷機了。
下面是生成的各種映象檔案和其他。
編譯AOSP遇到的問題
許可權遭拒
由於部落格使用了外部硬碟作為out編譯輸出,make
時提示Permission is denied。這時換成sudo make
即可。
使用外部磁碟做out輸出:export OUT_DIR_COMMON_BASE=/media/username/外部磁碟路徑/out
記憶體不足
由於筆者的記憶體只有4G,並且最開始沒有分出swap分割槽,導致多次記憶體不足編譯失敗,有多種日誌形式都表明記憶體不足:
第1種錯誤:
[ 34% 12287/35393] Building with Jack: out/target/common/obj/JAVA_LIBRARIES/core-all_intermediates/with-local/classes.dex
FAILED: /bin/bash out/target/common/obj/JAVA_LIBRARIES/core-all_intermediates/with-local/classes.dex.rsp
Communication error with Jack server (52). Try 'jack-diagnose'
ninja: build stopped: subcommand failed.
make: *** [ninja_wrapper] Error 1
第2種錯誤:
[ 82% 30024/36285] Aligning zip: out/target/product/shamu/obj/SHARED_LIBRARIES/libdlext_test_runpath_zip_zipaligned_intermediates/libdlext_test_runpath_zip_zipaligned.zip
[ 82% 30025/36285] Import includes file: out/target/product/shamu/obj/STATIC_LIBRARIES/libverifier_intermediates/import_includes
[ 82% 30026/36285] target thumb C++: libverifier <= bootable/recovery/asn1_decoder.cpp
[ 82% 30027/36285] target thumb C++: libverifier <= bootable/recovery/verifier.cpp
[ 82% 30028/36285] Export includes file: -- out/target/product/shamu/obj/STATIC_LIBRARIES/libverifier_intermediates/export_includes
[ 82% 30029/36285] target thumb C++: libverifier <= bootable/recovery/ui.cpp
ninja: fatal: fork: Cannot allocate memory
make: *** [ninja_wrapper] Error 1
第3種錯誤:
FAILED: /bin/bash out/target/common/obj/JAVA_LIBRARIES/core-all_intermediates/with-local/classes.dex.rsp
Out of memory error (version 1.2-rc4 'Carnac' (298900 f95d7bdecfceb327f9d201a1348397ed8a843843 by [email protected])).
GC overhead limit exceeded.
Try increasing heap size with java option '-Xmx<size>'.
Warning: This may have produced partial or corrupted output.
[ 31% 11494/36285] host C++: libartd-compiler <= art/compiler/optimizing/graph_visualizer.cc
[ 31% 11494/36285] Building with Jack: out/target/common/obj/JAVA_LIBRARIES/libprotobuf-java-nano_intermediates/classes.jack
[ 31% 11494/36285] build out/target/common/obj/JAVA_LIBRARIES/sdk_v21_intermediates/classes.jack
ninja: build stopped: subcommand failed.
第4種錯誤:
[ 6% 2375/35393] target Java: icu4j (out/target/common/obj/JAVA_LIBRARIES/icu4j_intermediates/classes)
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: external/icu/icu4j/main/classes/core/src/com/ibm/icu/impl/Relation.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
[ 6% 2394/35393] host C++: libLLVMMC_32 <= external/llvm/lib/MC/MCDwarf.cppninja: fatal: fork: Cannot allocate memory
make: *** [ninja_wrapper] Error 1
第5種錯誤:
[ 5% 1883/35393] Docs droiddoc: out/target/common/docs/api-stubs
FAILED: /bin/bash out/target/common/docs/api-stubs-timestamp.rsp
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000bdb80000, 72876032, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 72876032 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /home/michaelx/AOSP_NBD91Z/hs_err_pid508.log
[ 5% 1883/35393] Docs droiddoc: out/target/common/docs/system-api-stubs
DroidDoc took 27 sec. to write docs to out/target/common/docs/system-api-stubs
ninja: build stopped: subcommand failed.
make: *** [ninja_wrapper] Error 1
解決記憶體不足的3個辦法:
- 增加機器記憶體
- 增加swap分割槽
- 修改prebuild/sdk/tools/jack-admin檔案
# 備份jack-admin
$ cp prebuild/sdk/tools/jack-admin ~/Docments/jack-admin.original
# 修改jack-admin檔案
$ vim prebuild/sdk/tools/jack-admin
# start-server方法,筆者的jack-admin在443行,修改該方法中的一句話:
# JACK_SERVER_COMMAND="java -Djava.io.tmpdir=$TMPDIR $JACK_SERVER_VM_ARGUMENTS -cp $LAUNCHER_JAR $LAUNCHER_NAME"
# 改成下面這行,增加java堆大小。
JACK_SERVER_COMMAND="java -Djava.io.tmpdir=$TMPDIR $JACK_SERVER_VM_ARGUMENTS -Xmx8000M -cp $LAUNCHER_JAR $LAUNCHER_NAME"
以上增加的-Xmx8000M,表示允許java在執行時java堆使用最大不超過8000M記憶體,這個數值是筆者經歷了多次測試得到的結果,2048M,4096M,依舊沒通過編譯,改成8000M後編譯通過,可能跟筆者自身硬體限制有很大關係
另一種修改方式:修改jack-admin第29行的變數:JACK_SERVER_VM_ARGUMENTS="${JACK_SERVER_VM_ARGUMENTS:=-Dfile.encoding-UTF-8 -XX:+TieredCompilation}"
改成:
JACK_SERVER_VM_ARGUMENTS="${JACK_SERVER_VM_ARGUMENTS:=-Dfile.encoding-UTF-8 -XX:+TieredCompilation -Xmx8000M}"
但是這種修改方式仍然不好使,編譯失敗了。
筆者是嘗試了第二,三種方式解決。
jack-server無法執行
錯誤日誌如下:
[ 37% 13421/35393] Ensure Jack server is installed and started
FAILED: /bin/bash -c "(prebuilts/sdk/tools/jack-admin install-server prebuilts/sdk/tools/jack-launcher.jar prebuilts/sdk/tools/jack-server-4.8.ALPHA.jar 2>&1 || (exit 0) ) && (JACK_SERVER_VM_ARGUMENTS=\"-Dfile.encoding=UTF-8 -XX:+TieredCompilation\" prebuilts/sdk/tools/jack-admin start-server 2>&1 || exit 0 ) && (prebuilts/sdk/tools/jack-admin update server prebuilts/sdk/tools/jack-server-4.8.ALPHA.jar 4.8.ALPHA 2>&1 || exit 0 ) && (prebuilts/sdk/tools/jack-admin update jack prebuilts/sdk/tools/jacks/jack-2.28.RELEASE.jar 2.28.RELEASE || exit 47; prebuilts/sdk/tools/jack-admin update jack prebuilts/sdk/tools/jacks/jack-3.36.CANDIDATE.jar 3.36.CANDIDATE || exit 47; prebuilts/sdk/tools/jack-admin update jack prebuilts/sdk/tools/jacks/jack-4.7.BETA.jar 4.7.BETA || exit 47 )"
Jack server already installed in "/home/michaelx/.jack-server"
Launching Jack server java -XX:MaxJavaStackTraceDepth=0 -Djava.io.tmpdir=/tmp -Dfile.encoding=UTF-8 -XX:+TieredCompilation -cp /home/michaelx/.jack-server/launcher.jar com.android.jack.launcher.ServerLauncher
Jack server failed to (re)start, try 'jack-diagnose' or see Jack server log
No Jack server running. Try 'jack-admin start-server'
No Jack server running. Try 'jack-admin start-server'
[ 37% 13421/35393] target thumb C++: libicui18n <= external/icu/icu4c/source/i18n/coptccal.cpp
[ 37% 13421/35393] target thumb C++: libicui18n <= external/icu/icu4c/source/i18n/compactdecimalformat.cpp
[ 37% 13421/35393] target thumb C++: libicui18n <= external/icu/icu4c/source/i18n/cpdtrans.cpp
ninja: build stopped: subcommand failed.
解決Jack server failed to (re)start辦法:
$ cd /prebuild/sdk/tools/
$ jack-admin stop-server
$ jack-admin start-server
和各路編譯錯誤大戰了7天7夜(真的是7天7夜呀,碰到的無數問題我都沒寫完呢),終於修成正果。
總結
到了這裡,相信大家都能輕鬆搞機了,如果有需要Nexus的刷機教程,請留言評論,下次出一篇Nexus的刷機過程。放2張Nexus 6刷機後的高清截圖
參考連結
etc….