如何編譯AOSP內核Kernel並整合進AOSP (Android P/Pixel 2)

本文指引Android平台開發者如何取得Android官方 (AOSP)釋出的Kernel進行編譯(Build)並且刷入實機驗證。

接下來我們要完成以下項目:
  • 取得Android官方釋出的Pixel 2 (Walleye) Kernel。(Android 9.0/Pie)
  • 編譯核心Linux Kernel
  • 刷入Pixel 2實機 (以下步驟對於其他Google Pixel系列手機也適用。)
  • 整合AOSP及內核代碼庫

編譯AOSP

編譯AOSP的完整引導可以參考:完整指引如何編譯AOSP (Android P),整合GMS及刷機

最新的Android官方內核編譯已不需要先把AOSP編譯完成(甚至不用刷機)就可以編譯內核並且由新編譯的內核利用fastboot boot的命令直接用來開機。

取得AOSP Kernel


目前(2019/4/15)Android官方內核Kernel的原始碼釋出方式有了重大改變,看起來是為了支持更多的內核組態。Kernel的原始碼釋出不再只是使用一個Git Project做管理,而是以一個Android Repo來進行多個Project管理。所以取得AOSP Kernel有點類似取得整個AOSP的流程。

Android官網的說明:https://source.android.com/setup/build/building-kernels#id-version


在Android官網中,說明Pixel2的對映版本為android-msm-wahoo-4.4-pie-qpr2
從官網可以看出,我們要拿的內核Repo branch版本為android-msm-wahoo-4.4-pie-qpr2

首先取得AOSP Kernel for Pixel 2

repo init -u https://android.googlesource.com/kernel/manifest -b android-msm-wahoo-4.4-pie-qpr2
repo sync

取得原始碼後,在此原始碼根目錄下可以列出以下目錄及一個連結檔:

  • build => 編譯命令及環境設定腳本
  • build.config => 編譯設定組態檔
  • kernel => 內核測試工具
  • prebuilts => 內核編譯工具 (Cross Compiler/GCC)
  • prebuilts-master => 內核編譯工具 (Clang)
  • private => 內核原始碼
  • .repo => repo管理目錄

所以以前的AOSP內核編譯需要先把AOSP環境架設好,然後內核的編譯才能「依附」其下。現在的內核編譯採用了「自給自足」模式。

編譯AOSP內核


再來進行編譯AOSP內核 (build AOSP Kernel),取得後在原始碼目錄下,直接執行以下命令

sh build/envsetup.sh
build/build.sh

最後會將Kernel編譯完成,編譯過程中輸出的編譯訊息文字:

make: Leaving directory `./out/android-msm-wahoo-4.4/private/msm-google'
 Copying kernel UAPI headers to ./out/android-msm-wahoo-4.4/dist/kernel-uapi-headers.tar.gz
========================================================
 Copying kernel headers to /home/jeremychen/develop/aosp/walleyes-kernel/out/android-msm-wahoo-4.4/dist/kernel-headers.tar.gz
========================================================
 Files copied to ./out/android-msm-wahoo-4.4/dist

最後一行Files copied to ~,就是輸出核心映像(Kernel Image)的位置,到該目錄下,列出檔案:

AOSP Kernel核心編譯完成的輸出檔案

測試AOSP Kernel內核


Android提供「不刷機測試核心」的功能,好處就是如果改壞Kernel了,重開機後(一般是長按Power Key 15秒),就能回復原有的Kernel核心,這也降低了把手機刷壞的機率(理論上目前的手機要刷壞到無法重刷那也不容易)。不刷機直接從新編譯的核心開機命令如下,先將目錄轉換至核心輸出目錄,out/android-msm-wahoo-4.4/dist,執行:

fastboot boot Image.lz4-dtb

之後手機就直接由新編譯的核心開機,為了確認這件事,開機後用adb檢視開機的核心Log:

adb shell dmesg
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Initializing cgroup subsys schedtune
[    0.000000] Linux version 4.4.155-g0a25236 (jeremychen@ubuntu) (Android clang version 5.0.300080 (based on LLVM 5.0.300080)) #1 SMP PREEMPT Mon Apr 15 11:55:46 CST 2019
[    0.000000] Boot CPU: AArch64 Processor [51af8014]
[    0.000000] Machine: Qualcomm Technologies, Inc. MSM8998 v2.1
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.

可以從以上Log的時間 (Apr 15 11:55:46 CST 2019) 看出,內核是由新編譯出來。

整合進AOSP

整合的意思即是將內核編譯後,納入AOSP編譯,編譯AOSP完成後,其內核映像檔(boot.img)即是自行編譯的內核。

選擇1:簡易整合


如果你要將內核及AOSP分別管理,在編譯完成內核後,從內核輸出目錄,將以下檔案複製到AOSP原始碼Codebase下(編譯AOSP的完整引導可以參考:完整指引如何編譯AOSP (Android P),整合GMS及刷機),再進行AOSP編譯即可。

例如你的內核編譯完成,輸出在/aosp-kernel/out/android-msm-wahoo-4.4/dist,而AOSP目錄在/aosp下,則執行複製命令:

cd /aosp-kernel/out/android-msm-wahoo-4.4/dist #切換至內核輸出目錄
cp Image.lz4-dtb /aosp/device/google/wahoo-kernel #device/google/wahoo-kernel是pixel2預載內核目錄
cp ftm4.ko /aosp/device/google/wahoo-kernel
cp htc_battery.ko /aosp/device/google/wahoo-kernel
cp lge_battery.ko /aosp/device/google/wahoo-kernel
cp sw49408.ko /aosp/device/google/wahoo-kernel
cp synaptics_dsx_core_htc.ko /aosp/device/google/wahoo-kernel
cp synaptics_dsx_fw_update_htc.ko /aosp/device/google/wahoo-kernel
cp synaptics_dsx_rmi_dev_htc.ko /aosp/device/google/wahoo-kernel
cp touch_core_base.ko /aosp/device/google/wahoo-kernel
cp wlan.ko /aosp/device/google/wahoo-kernel

再進入AOSP的目錄下,執行envsetup.sh及lunch後,再make,就能完整編譯出可刷機的自製AOSP + Kernel版本。

選擇2:完整原始碼Codebase整合


如果要管理自身內核的更動,包含原始碼審視(Code Review),就必須將內核專案納入Gerrit Server/AOSP。若你已經建立一個Gerrit Server可以管理AOSP代碼庫,則你可以將內核也一併整合進該代碼庫。(若是還沒有自有的AOSP Gerrit Server,請參考 架設AOSP Gerrit Server

以下是快速命令來建立Kernel內核專案納入本地的Gerrit Server進行管理。以下命令假設你的環境為:
  • Gerrit Server IP: 10.50.100.56,
  • 使用者:jeremychen,
  • 管理者群組:android-admin
  • 父專案:AOSP,
  • 自有AOSP Branch分枝為:my_android-9
如果對以上的變數不熟悉,也對自有的AOSP Gerrit Server建立並不熟悉,可以參考「架設本地AOSP Gerrit Server完整指引」的系列文:

步驟一:取得內核Git鏡射 (git mirror)

#取得內核Mirror,重點在最後--mirror
repo init -u https://android.googlesource.com/kernel/manifest -b android-msm-wahoo-4.4-pie-qpr2 --mirror
#同步代碼庫
repo sync

步驟二:將內核代碼庫推入(push)Gerrit Server

Android官方內核代碼庫包含了七個專案,我們只需其中兩個:kernel/buildkernel/msm
因為其他五個不是必要,有些和AOSP代碼庫的專案是重複的,所以排除。

#在Gerrit Server建立kernel/build專案
ssh -p 29418 jeremychen@10.50.100.56 gerrit create-project --owner android-admin kernel/build
#設定kernel/build父專案為AOSP
ssh -p 29418 jeremychen@10.50.100.56 gerrit set-project-parent --parent AOSP kernel/build
#在Gerrit Server建立kernel/msm專案
ssh -p 29418 jeremychen@10.50.100.56 gerrit create-project --owner android-admin kernel/msm
#設定kernel/msm父專案為AOSP
ssh -p 29418 jeremychen@10.50.100.56 gerrit set-project-parent --parent AOSP kernel/msm
#進入kernel/build鏡射目錄
cd ./kernel/build.git
#將kernel/build所有分枝及Tags推入Gerrit Server
git push ssh://jeremychen@10.50.100.56:29418/kernel/build +refs/heads/* +refs/tags/*
#基於master,建立my_android-9分枝
ssh -p 29418 jeremychen@10.50.100.56 gerrit create-branch kernel/build my_android-9 master
#進入kernel/msm鏡射目錄
cd ../kernel/msm.git
#將kernel/msm所有分枝及Tags推入Gerrit Server (需一段時間)
git push ssh://jeremychen@10.50.100.56:29418/kernel/msm +refs/heads/*
git push ssh://jeremychen@10.50.100.56:29418/kernel/msm +refs/heads/* +refs/tags/*
#基於android-msm-wahoo-4.4-pie-qpr2,建立my_android-9分枝
ssh -p 29418 jeremychen@10.50.100.56 gerrit create-branch kernel/build my_android-9 android-msm-wahoo-4.4-pie-qpr2

步驟三:把內核專案加入AOSP代碼庫

目前只是把內核代碼庫加入Gerrit Server,所以還必須在AOSP代碼庫中加入內核專案。
首先在AOSP的.repo/manifests/default.xml加入內核專案。

  <project path="kernel/private/msm" name="kernel/msm" groups="vendor">
      <linkfile src="build.config" dest="kernel/build.config" />
  </project>
  <project path="kernel/build" name="kernel/build" groups="vendor"/>

然後在.repo/manifests目錄下,更新default.xml推上Gerrit Server。

git push ssh://jeremychen@10.50.100.56:29418/platform/manifest HEAD:refs/for/my_android-9

步驟四:修改內核編譯環境

配合整個AOSP編譯環境,我們把內核原始碼放在kernel/private/msm,把內核編譯命令放在kernel/build。
接下來改變以下kernel/build/private/msm/build.config來符合AOSP的編譯環境:


diff --git a/build.config b/build.config
index 471f62b..3226602 100644
--- a/build.config
+++ b/build.config
@@ -1,19 +1,20 @@
 ARCH=arm64
-BRANCH=android-msm-wahoo-4.4
+BRANCH=my_android-9
+DIST_DIR=../device/google/wahoo-kernel
 CC=clang
 CLANG_TRIPLE=aarch64-linux-gnu-
 CROSS_COMPILE=aarch64-linux-android-
 CROSS_COMPILE_ARM32=arm-linux-androideabi-
 DEFCONFIG=wahoo_defconfig
 EXTRA_CMDS=''
-KERNEL_DIR=private/msm-google
+KERNEL_DIR=private/msm
 POST_DEFCONFIG_CMDS='check_defconfig'
-CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-4053586/bin/
-LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
-LINUX_GCC_CROSS_COMPILE_ARM32_PREBUILTS_BIN=prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin
-LZ4_PREBUILTS_BIN=prebuilts-master/misc/linux-x86/lz4
-DTC_PREBUILTS_BIN=prebuilts-master/misc/linux-x86/dtc
-LIBUFDT_PREBUILTS_BIN=prebuilts-master/misc/linux-x86/libufdt
+CLANG_PREBUILT_BIN=../prebuilts/clang/host/linux-x86/clang-4053586/bin/
+LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=../prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
+LINUX_GCC_CROSS_COMPILE_ARM32_PREBUILTS_BIN=../prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin
+LZ4_PREBUILTS_BIN=../prebuilts/misc/linux-x86/lz4
+DTC_PREBUILTS_BIN=../prebuilts/misc/linux-x86/dtc
+LIBUFDT_PREBUILTS_BIN=../prebuilts/misc/linux-x86/libufdt
 FILES="
 arch/arm64/boot/dtbo.img
 arch/arm64/boot/Image.lz4-dtb

第8,9行的改變是改變分枝名稱。第10行加入DIST_DIR把原本AOSP的預載內核覆蓋成自行編譯的內核。第17,18行是指向內核原始碼,第20~31行是把編譯工具指向AOSP的編譯工具(GCC及Clang等等)。

步驟五:編譯內核及編譯完整AOSP

最後重新進行編譯,我們分為兩部份,所編譯內核,再編譯AOSP
進入kernel目錄,編譯內核
#進入Kernel Build根目錄
sh build/envsetup.sh
sh build/build.sh

完成後,新的內核映像檔及其他內核模組會自動產生在device/google/wahoo-kernel下, 再回到AOSP根目錄,重新編譯AOSP,完成後利用fastboot flashall刷機。
#進入AOSP Codebase根目錄
sh build/envsetup.sh
lunch aosp_walleye-userdebug
make
adb reboot bootloader
fastboot flashall

完成後就可以把內核的原始碼也納入Gerrit Server管理,並且和AOSP整成一包完整的代碼庫,包含AOSP,GMS及Kernel。

修改Kernel Config(內核組態)

修改Kernel Config要先找到內核的Config檔案位置。在kernel/build/private/msm/build.config中,定義了變數DEFCONFIG=wahoo_defconfig,這就是Kernel Config的檔案名稱。而實際的位置目錄根據Linux Kernel的規則是放在Kernel根目錄下的arch/<ARCH>/configs。Kernel根目錄我們放在kernel/private/msm而Pixel2的架構為ARM64,所以其組態位置在

kernel/private/msm/arch/arm64/configs/wahoo_defconfig


找到後編輯加入一個SYSVPIC設定

CONFIG_SYSVIPC=y

儲存後重新編輯內核會發生錯誤,這是AOSP內核編輯系統的設定,主要是不讓你因變更預設的內核組態而造成Android系統的問題。AOSP官方有規定必須加入的CONFIG及不可加入的CONFIG。這些可以從kernel/config/README.md仔細去看,這裏我們先省略檢查相容性的部份,可以將kernel/private/msm/build.config中的POST_DEFCONFIG_CMDS='check_defconfig'改為空字串

POST_DEFCONFIG_CMDS=

如此即可跳過相容性檢查,再重新執行一次Kernel Build就能成功編譯。但使用到不相容的CONFIG是有風險的,以SYSVIPC來說其風險在以下官方連結有詳細說明。

https://android.googlesource.com/platform/ndk/+/4e159d95ebf23b5f72bb707b0cb1518ef96b3d03/docs/system/libc/SYSV-IPC.TXT


留言

  1. 謝謝分享整個程序。不過我有兩個問題請教,第一是下載完後編譯,你會先下"sh build/envsetup.sh",然而程式會顯示此方法已經不再使用,只需要進行"build/build.sh" 即可。第二個問題是我在驗證 android-msm-marlin-3.18-pie-qpr2,編譯無法成功,卡在 build_config 裡的一個命令:python build/buildinfo/buildinfo.py,因為檔案 buildinfo/buildinfo.py 並不存在,所以就編譯失敗,因為 Google 上找不到類似的問題與解決方式,想請教你這邊是否有經驗。Thanks.

    回覆刪除
  2. 你好,我按照文章内步驟編譯並成功flash了内核,發現觸屏功能失效。。。不知道什麽原因導致的

    回覆刪除
    回覆
    1. 我也碰到触屏失效的问题,请问你解决了吗?

      刪除
    2. 作者已經移除這則留言。

      刪除
    3. 我也遇到相同的問題解決了。可以用滑鼠點進去系統看,是因為核心版本跟原本不一致所導致的。重抓核心版本一致的用就行了!

      刪除

張貼留言

這個網誌中的熱門文章

完整指引如何編譯AOSP (Build Android P),整合GMS及刷機 (Pixel 2)

架設Gerrit Server : 架設本地AOSP Gerrit Server完整指引 PART1

將AOSP加入Gerrit Server : 架設本地AOSP Gerrit Server完整指引 PART2