完整指引如何編譯AOSP (Build Android P),整合GMS及刷機 (Pixel 2)
前言
本文是說明一個Android Framework研發人員,如何利用Google的Pixel手機進行系統程式的客製化。本文的工作如下:- 解鎖Pixel2
- 取得AOSP原始碼
- 編譯AOSP (Build AOSP)
- 將Pixel 2刷機自己編譯的ROM
- 修改Framework後,重編譯,再刷機,完成!
- 安裝GMS
前置工作
解鎖Pixel 2,讓手機允許刷機
首先必須知道,官方釋出的手機的開機載入程序(Bootloader)會阻止你刷入任何客製ROM。所以所謂「解鎖」就是解鎖Bootloader,讓它允許你可以進行刷機動作。其次要注意是在刷機後,所有使用者資料(User data)都會消失。所以刷機前要先備份重要資料。
網路上有很多教解鎖Pixel手機的文章,都可以參考,實際上在Android官網已經有教導你如何解鎖Pixel 2的Bootloader,我個人是比較習慣直接看官網來做:
https://source.android.com/setup/build/running
如果你懶得看一大堆英文,根據官網的描述,以下的命令就可以讓你解鎖Bootloader。
所以解鎖其實只有兩個命令:
1. adb reboot bootloader重開機以進入“開機載入程序”,畫面如下
![]() |
adb reboot bootloader後的實機畫面 |
2. fastboot flashing unlock進行Bootloader解鎖。
![]() |
fastboot flashing unlock後的畫面,按音量上鍵後按電源鍵,確認解鎖 |
之後手機進行資料清除後重開。
很多文章寫了一大堆步驟,主要是為了要取得Root權限。但在本文中這是不必要的,因為等你刷入了自己Build出來的ROM,自然可以取得Root權限。
刷入官網的ROM
先刷一次官網的ROM,目的有兩個:1. 確定解鎖後的Pixel2可以刷機。 2. 刷特定版本的Pixel2 官方ROM,以確保Kernel和之後我們要編譯的系統映像(System Image)是在同一版本。官網的ROM的位置在:
https://developers.google.com/android/images#walleye
Walleye就是Pixel2的代號,這很重要,因為會牽涉到之後取得AOSP原始碼時所要選擇的原始碼分枝 (Branch)。在本文中,下載的版本為:
PQ2A.190205.002
![]() |
選擇PQ2A.190205.002做為官方ROM刷機 |
記得你要刷機的版本,之後一致的版本可以讓你少走一些冤枉路。之後你想要取得更新的版本當然也沒問題,只要確保 官方ROM和AOSP Branch原始碼版本及Binary Driver 的版本一致就可以。
下載後解開tgz,一樣進入Bootloader模式 (adb reboot bootloader),執行fastboot.sh (或在Windows下執行fastboot.bat),則Script開始執行刷機的動作。
順利的話,完成刷機動作,系統重新開機。此時你進入 [系統]->[關於手機] 的畫面
![]() | |
|
你可以看到版本號碼(Build number)為PQ2A.190205.002,這和我們從Android官網取得的官方ROM一致。
取得AOSP原始碼
確認AOSP Branch/Tag
AOSP有很多Branch,那一個Branch才是Android P Pixel2必須先找到。首先根據Android官網指令,把編譯環境設定好,確保你可以編譯Android AOSP:
https://source.android.com/setup/build/initializing
之後要選定AOSP版本及分枝,在以下官方連結中,列出了所有的分枝
https://source.android.com/setup/start/build-numbers.html#source-code-tags-and-builds
記得我們是選定PQ2A.190205.002這個版本來實作,所以可以找到對映的分枝:android-9.0.0_r32
![]() | |
|
下載AOSP Android原始碼 (及私有函式庫)
所以找到的AOSP是android-9.0.0_r32,現在我們就根據官網來下載這個原始碼:
https://source.android.com/setup/build/downloading
順著官網執行設定工作後,最重要就是下載AOSP原始碼了。主要的不同也只有在這一行
下載完成(視網路狀況,資料量約90Gbytes)後,接下來下載Pixel2 Driver。
為什麼還有Driver? 因為AOSP是完成Open Source,但實機上有些原始碼是私有Proprietary的,受版權保護及有安全疑慮而不放開原始碼。例如和無線通訊/圖形加速晶片相關,這些是以Binary形態存在,所以必須也要下載,我們才能完整編譯出一個可以刷入實機的ROM。(否則只能編譯Emulator而已)。
Pixel2 (Walleye) 的Binary Driver在: https://developers.google.com/android/drivers#walleye
同樣我們必須保持版本一致。找到PQ2A.190205.002這個版本
![]() |
PQ2A.190205.002有兩個Binary包,都要下載 |
接下來直接用tar解開,會解出兩個script:
然後執行兩個script,解出Binary:
它會要你看完版權宣告後,輸入 I ACCEPT,才真正解開來,解出的Binary都存在vendor目錄下。
可以看到google_devices目錄中有個vendor.img,這是OEM廠商私有的映像檔,主要包含和硬體相關的程式及函式庫,以及硬體啟動時所需的設定檔。
qcom表示Qualcomm,看起來這些Binary主要是和IMS (IP Multimedia Subsystem)相關的函式庫以及框架層所需的JAR檔。
完全不懂Binary Drivers也無所謂,知道這些檔案是必須的就行了。
至此所需的檔案和原始碼已完全下載完畢。再來接下來就可以開始編譯AOSP了。
進行編譯AOSP
首先建立環境變數,就是告訴AOSP要如何編譯這整包原始碼,你可以把它編輯成模擬器Emulator也可以編譯成Pixel2的ROM。
我們設定為編譯Pixel2 ROM
編譯環境的建立就兩個命令 sh ./build/envsetup.sh建立通用環境變數,而lunch aosp_walleye-userdebug則是指定之後下make編譯時,編譯出符合Pixel2的映像檔(image)。
那如果要編譯Pixel 3呢?你可以到官網:https://source.android.com/setup/build/running#selecting-device-build
![]() |
Google硬體對映Build configuration (編譯組態) |
之後下make就開始編譯了。
所以完整下編譯的命令為:
一切順利後完成編譯,輸出目錄在環境變數$ANDROID_PRODUCT_OUT所指定的位置。你可以直接下cd $ANDROID_PRODUCT_OUT到輸入目錄。
再來檢視你編譯出來的結果:
可以比較一下你編譯出來的映像檔(*.img)是否相同。 完成編譯後,接下來就是刷機了。
用自己編譯的ROM來刷機
最後就是刷機,刷機就簡單了,先下adb reboot bootloader重新將手機進入Bootloader,再執行fastboot flashall刷機完成後會完全清除使用者資料,如果想要保留資料,則之後刷機不加-w參數。
刷機後開機,如果一切順利,你會發現,怎麼和官方ROM的畫面完全不同??官方的ROM是包含GMS,而自己編譯的ROM則沒有GMS,所以自己編譯的ROM看起來就很像開發Android APP的模擬器。
![]() |
Pixel2刷自製ROM後,沒有GMS的主畫面 |
修改AOSP
實作耳機圖示
我們來做簡單的一個小功能(其實只是小改一下),功能為「插入耳機時,在狀態列Status Bar上顯示耳機圖示小Icon」,像這樣:
![]() |
耳機插入小圖示 |
你可以看到在插入耳機後,在Wi-Fi信號左邊一個耳機圖示。這是在耳機插入時才會顯示。在Google的原生AOSP設計中,預設是不顯示這個Icon。
在Android 8.0(Android Oreo)時,你可以下拉Status Bar後,長按設定鍵(齒輸小Icon),進入System Tuner UI,然後手動將耳機Headset圖示開啟。但Android 9.0 (Android Pie)之後,System Tuner的功能預設關掉了,所以我們的工作根本不用開發什麼,就是把它找回來就可以了!!
首先開啟:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
把第三行的Code從false改為true:
再重新下make命令再Build一次,然後重刷一次機。完成後下拉Status Bar,長按右下角的設定鍵會發現小齒輪一直轉動(如下圖指標所示),放開後進入Settings畫面。
![]() |
開啟System UI Tuner,客製圖示顯示設定 |
進入Settings之後,進入System->Advanced->System UI Tunner->Status bar後,開啟Headset。
再找個耳機插入USB Type-C孔,就會看到耳機圖示出現了。
把GSM整合進你的Codebase!
畢竟純AOSP對於一般使用者是不用夠,無法做為日常使用,所以必須有GMS的套件,才算完整。接下來我們就把GSM整合回來!
理論上Google為了要同時保持開放性及服務可靠性,所以算是放水。它讓解鎖後的手機可對Android系統安裝GMS。而重點在「解鎖後」,所以Google不會告你侵權,只要不是預載在市售ROM就可以。於是Open GAPP的計劃就產生了,它讓第三方ROM可以使用GMS及其服務。Open Gapps官網:https://opengapps.org/
一般像是LineageOS這種第三方ROM會教你如何刷GSM進去 (通常是TWRP加上OpenGapps)。不過要整進AOSP有點特別,AOSP預設「沒有」GMS。整個AOSP Codebase並沒有和GMS整合的相關編輯設定。如果直接用TWRP來刷GMS並不是不行,但在Android系統權限和WebView設定等等方面,都會出問題。
OpenGapps也有教你如何把GMS整合進整個原始碼
https://github.com/opengapps/aosp_build (但這說明有些不完整,有幾個Issue我要Submit給作者,請他修正了)
1. 安裝lunzip
首先安裝lunzip,這是Open Gapps在整合AOSP所需的命令工具。
2. 修改manifest.xml
將Open Gapps的專案下載至你的AOSP Codebase。(這些Open Gapps專案很大,約20G,因為他是一個專案支援所有Android版本)
在.repo/manifest.xml的最後,把以下的Open Gapps專案Projects加入
接下來在.repo/mainfests/目前下,執行git commit -a -m "add open gapps",將修改commit進git。
3. 修改aosp_walleye.mk及device.mk
修改檔案:device/google/muskie/aosp_walleye.mk,將:
PRODUCT_RESTRICT_VENDOR_FILES := owner
改為
PRODUCT_RESTRICT_VENDOR_FILES := false
否則在編輯時會發生
error: Error: Product "aosp_walleye" cannot have overlay in vendor tree:...
再修改檔案:device/google/wahoo/device.mk,在檔案最後加入
GAPPS_VARIANT := stock
$(call inherit-product, vendor/opengapps/build/opengapps-packages.mk)
編譯AOSP時,就會呼叫vendor/opengapps/build/opengapps-packages.mk將Open Gapps編入system.img中
4. 修改原始碼
修改frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
把setShelfHeight所需要的權限移除,否則刷入ROM之後Pixel Launcher會因權限不足發生錯誤。
5. 重編譯及刷機
再下make之後,重新刷機,結果如下:
![]() |
刷入最後自行客製ROM,AOSP Android P + Open Gapps |
如此完成了一次,從取得AOSP,編譯,刷機,修改,加入GMS,再編譯,再刷機的完整工作!
最後一哩
有了完整的AOSP + GMS,其實還缺內核原始碼的部份。因為Pixel的內核在AOSP中採取預編內核,在device/google/wahoo-kernel下可以看到預編的內核(prebuilt kernel)。如果是內核開發者必須更動其原始碼,最必須也將內核核心整合進來。詳細方法可以參考:如何編譯AOSP內核Kernel並整合進AOSP (Android P/Pixel 2)
跟下面的整合内核Kernel一起,这个帖子给我示范了一个完整的AOSP 编译与刷机过程。是个好教程。
回覆刪除另外请教有个问题。我现在基于Android Preview(即Android Q的预览版)在写一个东西,但我已经忘记这个Q的源码是如何得到的,更不知道它对应于Walleye的Driver Binary在哪里,所以我现在遇到了一个十分棘手的问题:无法成功将我所编写的软件基于Q来刷Pixel 2的真机。请问,有办法吗?
取得AOSP Q Preview源碼是容易的,如果沒錯,我看了一下,應該是用 "repo init -u https://android.googlesource.com/platform/manifest -b android-q-preview-2.5" 來取得。
刪除但Device Binary就麻煩了,官方還沒釋出,所以只能先刷官方的Android Q Preview之後(https://developer.android.com/preview/download#flash),比較一下AOSP System和官方釋出Binary Image刷機完之後的檔案差別。
把官方Image多出來的檔案抓出來到vendor/qcom/walleye/proprietary下,官方的Binary Image解開後,原本就有vendor.img了,這部份就容易整合了。
這只是理論,有空我會試一下,但這就很花時間,所以對我而言,玩AOSP在工作上沒這麼急迫,所以不如等官方發佈出來再來玩。
Hi, Thanks for your great job!!
回覆刪除现在我有一个疑问的地方. 执行下面这个命令的时候是 cd $ANDROID_PRODUCT_OUT 在这个目录里面吗?
fastboot flashall -w
$ANDROID_PRODUCT_OUT 这个目录里面有很多文件. 当然也有你说的*.img 文件. 执行这个命令的时候会出问题吗?
執行fastboot flashall時,fastboot自然根據$ANDROID_PRODUCT_OUT的環境變數找到該目錄下的image來刷入。所以不一定要先cd $ANDROID_PRODUCT_OUT
回覆刪除写的太详细了,感谢分享~~
回覆刪除非常感谢您细致的说明。将整个过程用在Pixel3上会遇到两个问题:1. 编译内核刷机之后,没有驱动,需要额外添加驱动。这个问题已经解决。2. 最后一步整合GMS的时候,编译没有问题,但是刷机之后停在开机界面。 请问如果是pixel 3 对一GMS这一步的具体修改有哪些呢?我只对应修改了device/google/wahoo/device.mk ——》device/google/crosshatch/device.mk
回覆刪除停在開機界面通常是System Server反覆Exception。所以可能要先看看adb shell能不能進入,並且用adb shell logcat -b crash來看問題出在哪裏?如果adb shell不能用,主要是因為還沒和主機認證,這時用lunch aosp_walleye-eng來Build engineering build,就可以直接進入adb,再找出問題。
刪除有可能是Pixel3有新的Permission Req,必須有Log確認!
刷机完启动,会进入bootloader界面,最下面一行提示:
回覆刪除ERROT: LoadImageAndAuth Failed: Load Error
这个错误有遇到吗?
有過,就是刷壞了。有可能刷到一半usb連結不好時斷線沒刷完整,也可能沒有全刷所有Images, 例如先刷官方image,後來只刷自己build的system image之類的戕況造成的。
刪除我的情况找到原因了:是因为我驱动(google和qcom)版本和AOSP不一致导致的。
刪除android 10 一样吗?有没有教程,thanks
回覆刪除刷玩pixel3后, 开机一直死在fastboot mode界面, 是怎么回事?
回覆刪除把opengapps 在mainfest中添加的内容删除,然后重新repo sync -c,再编再刷
刪除Hello, 謝謝你的教學分享,我在刷opengapps到Pixel 2 Android 10時一直出現
回覆刪除16% 560/3440] Check prebuilt ELF binary: vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so
FAILED: out/target/product/walleye/obj/SHARED_LIBRARIES/libsketchology_native_intermediates/check_elf_files.timestamp
/bin/bash -c "(rm -f out/target/product/walleye/obj/SHARED_LIBRARIES/libsketchology_native_intermediates/check_elf_files.timestamp ) && (build/make/tools/check_elf_file.py --skip-bad-elf-magic --skip-unknown-elf-machine --soname libsketchology_native.so --shared-lib out/target/product/walleye/obj/SHARED_LIBRARIES/libc++_intermediates/libc++.so --shared-lib out/target/product/walleye/obj/SHARED_LIBRARIES/libc_intermediates/libc.so --shared-lib out/target/product/walleye/obj/SHARED_LIBRARIES/libm_intermediates/libm.so --shared-lib out/target/product/walleye/obj/SHARED_LIBRARIES/libdl_intermediates/libdl.so --llvm-readobj=prebuilts/clang/host/darwin-x86/clang-r353983c1/bin/llvm-readobj vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so ) && (touch out/target/product/walleye/obj/SHARED_LIBRARIES/libsketchology_native_intermediates/check_elf_files.timestamp )"
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: error: DT_NEEDED "libEGL.so" is not specified in shared_libs.
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: error: DT_NEEDED "libGLESv2.so" is not specified in shared_libs.
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: error: DT_NEEDED "libandroid.so" is not specified in shared_libs.
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: error: DT_NEEDED "libjnigraphics.so" is not specified in shared_libs.
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: error: DT_NEEDED "liblog.so" is not specified in shared_libs.
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: error: DT_NEEDED "libGLESv1_CM.so" is not specified in shared_libs.
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note:
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note: Fix suggestions:
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note: Android.bp: shared_libs: ["libEGL", "libGLESv1_CM", "libGLESv2", "libandroid", "libc", "libdl", "libjnigraphics", "liblog", "libm"],
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note: Android.mk: LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libGLESv2 libandroid libc libdl libjnigraphics liblog libm
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note:
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note: If the fix above doesn't work, bypass this check with:
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note: Android.bp: check_elf_files: false,
vendor/opengapps/sources/arm64/lib64/29/libsketchology_native.so: note: Android.mk: LOCAL_CHECK_ELF_FILES := false
但找不到應該要修改哪隻Android.bp or Android.mk,不知道你有沒有遇過這個問題? 謝謝
作者已經移除這則留言。
回覆刪除你好,你寫的太好了,我有一些問題還想請教你,能否給個聯系方式或給我發一封郵件,我的邮箱是duanming6699@gmail.com謝謝
刪除