1. 程式人生 > >Ubuntu 14.04編譯AOSP for Nexus/Pixel

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包下載:

OpenJDK 8 on github
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

釋放手機驅動
將上述下載的幾個驅動檔案解壓到原始碼根目錄,解壓後也就是幾個指令碼檔案,依次執行,以釋放驅動,畫風大概如下
釋放shamu驅動

釋放shamu驅動

釋放shamu驅動

共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
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等等,就可以愉快的刷機了。
build-aosp-successful

下面是生成的各種映象檔案和其他。
out-dir-files

編譯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個辦法:

  1. 增加機器記憶體
  2. 增加swap分割槽
  3. 修改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….