本文簡述如何自行修改Android kernel,開啟特定的功能,再重新編譯檔案,將其刷入手機。
不同廠牌手機的作法不一樣,本文以小米當例子,從原始碼樹外(out of source tree)編譯kernel。
先從簡單的開始: 刷入自己修改過的kernel後,會在手機設定→關於→核心版本顯示自己的名字。
如果成功了,那麼就能更進一步去調kernel的功能,例如把docker要求的功能全部打開,就能 在Android手機跑docker。
1. 硬體需求#
要刷kernel,手機必定已經解鎖bootloader。刷kernel不會重置手機資料,所以刷之前只要備份boot分區,避免卡開機。
本文使用的手機是紅米Note 5 (whyred),系統為LineageOS 18。
編譯kernel需要一台x86-64位元的Linux電腦。我的電腦規格: Intel Core 2 Q9550 + 4GB DDR2 RAM。作業系統為Lubuntu 20.04。
2. 步驟概述#
編譯kernel包含除錯可能會花至少一天的時間,修改程式需要對C語言有深入了解。由於每支手機kernel的編譯器和需要的patch不盡相同,在此只講最基礎的方法。
首先下載kernel原始碼 → 設定交叉編譯器(在x86上編譯ARM) → 簡單加上名字後第一次編譯 → 刷入手機看功能正不正常 → 修改kernel功能 → 再次編譯 → 刷入到手機
我們會在Linux電腦桌面建立一個叫做customkernel
的目錄當作工作目錄。在第5步開始編譯前裡面大概長這樣:
接著安裝以下套件
sudo apt update
sudo apt 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 libgl1-mesa-dev \
libxml2-utils xsltproc unzip bc
3. 取得kernel原始碼#
原廠的kernel或第三方kernel都可以,通常會把原始碼放在Github。
這裡我以有很多額外功能的”RAD Kernel”專案做示範,這個專案程式碼問題比較少。
到他們的Github,clone原始碼。
git clone https://github.com/radcolor/android_kernel_xiaomi_whyred.git
為了方便識別,將clone下來的目錄重新命名為”src”。
4. 設定交叉編譯器#
再次提醒:不同廠牌手機kernel使用的編譯器不見得相同,有些甚至要用舊版GCC才編譯的過。
在Google改用Clang後,XDA仍有開發者持續提供最新版的GCC編譯器,也就是本文使用的"EVA GCC"。
到 XDA下載ARM與ARM64的版本(點選direct download下載)
將下載的arm版本解壓縮,命名為"tc32"。再將aarch64版本解壓縮,命名為"tc"。
將這二個目錄移動到"customkernel",到目前為止目錄長這樣,src是kerenl原始碼的目錄,tc和tc32則是剛剛下載的交叉編譯器。
5. 第一次測試編譯#
- 進入src目錄,在這裡開啟終端機。先export環境變數,指向編譯器的所在位置:
#以下分別對應tc和tc32所在的目錄,以及檔案名稱前綴
export CROSS_COMPILE=/home/ivon/Desktop/customkernel/tc/bin/aarch64-elf-
export CROSS_COMPILE_ARM32=/home/ivon/Desktop/customkernel/tc32/bin/arm-eabi-
export ARCH=arm64
- 清理kernel原始碼目錄
make clean
make mrproper
- 按照
機型_config
檔案產生kernel設定檔,該檔案通常在arch/arm64/configs
。
make whyred_defconfig
#輸出: configuration written to .config
開啟src目錄的
MakeFile
,在EXTRAVERSION
後面加入自己名字的字串:接著開始編譯kernel。
-j
後面加的數字通常是CPU核心數的二倍。
make -j8
4核心的Intel Q9550編譯至少要20分鐘,若遇到error編譯器就會停下來,要去改程式碼、上網找patch,再重新
make
,編譯器會從上個中止的地方繼續。編譯好的檔案位於
arch/arm64/boot/
,應該會有一個Image.gz-dtb
的檔案。接著要重新打包boot.img,把原廠的boot.img解開之後把我們做的kernel塞進去。先到 XDA下載Linux版Android Image Kitchen (點選文中的
AIK-Linux-v3.8-ALL.tar.gz
附件),解壓縮。手機進入TWRP → Advanced → Terminal,使用
dd
指令從手機提取原廠的boot.img。
dd if=/dev/block/bootdevice/by-name/boot of=/sdcard/stockboot.img
把這個原廠的stockboot.img檔案傳輸到電腦,放到AIK的工作目錄,並將剛剛編譯的
Image.gz-dtb
也放到這個目錄。在AIK目錄開啟終端機,使用指令解開stockboot.img(需要sudo)
./unpackimg.sh stockboot.img
進入目錄
split_img
,把stockboot.img-kernel
檔案替換成我們編譯好的Image.gz-dtb,檔名也改成stockboot.img-kernel
。回到AIK目錄,重新打包:
./repackimg.sh
- 應該會得到一個
image-new.img
的檔案。
6. 刷入到手機#
將新的image-new.img傳輸到手機,用TWRP點選Install Image,刷入到boot分區。
接著就是看看能不能開機了…若卡開機,還原TWRP的boot分區備份,繼續在電腦上debug吧…
7. menuconfig開關kernel功能#
如果前六個步驟成功完成,那就來真正修改kernel吧。
- 在src目錄開啟終端機,輸入指令開啟kconfig選單,用於開關kernel的功能。
make menuconfig
使用鍵盤上下和Enter進入子選項。找到要開啟的項目按下y,然後用鍵盤左右鍵移動到Save儲存設定值。
改好後切換到Exit退出,寫入變更,再次開始編譯kernel:
make -j8
- 接著重複第5步的步驟,編譯成功後把kernel打包,刷到手機測試。
8. 參考資料#
感謝fossfrog的影片清楚地解釋如何製作kernel: Build Your Own Android Custom Kernel | fossfrog
這篇文章有講解LineageOS編譯kernel的注意事項: Building LineageOS kernel trees from source