一次纠结的小米 3 TD 内核编译经历

10 年前的电脑可以装最新的 Windows 11,10 年前的安卓机却装不聊最新的 Android 发行版。虽然安卓开放,但上游硬件厂商提供的驱动和文档确大都闭源甚至收费的。再加上对各种商业因素的考量,一款安卓手机发布 2 到 3 年后,厂商就愉快地结束升级支持并转身投入到新机器的系统适配和维护中去了。这台用着英伟达 SoC 的手机在服务周期内虽然从 MIUI5 升级到 MIUI9 ,但 Android 版本一直停留在 4.4.4,升级内容基本是换皮。被英伟达坑了的小米坑了一众相信 MIUI 的米粉。

这个机器的内核开源了后,民间的第三方 ROM 才有活跃了起来。这次试下用源码编译内核并且刷进机器上。源码全部 clone 下来有 n 个多 G,Github 下载速度很慢,所有在 Gitee 上找了一个备份的仓库。按照小米官方内核编译WIKI下载下来还要安装一大堆开发环境包:

1
sudo apt install -y bc bison build-essential ccache curl flex g++-multilib gcc-multilib git gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5-dev libsdl1.2-dev libssl-dev libwxgtk3.0-gtk3-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev unzip openjdk-8-jdk language-pack-zh-hans abootimg

在源码的这个位置 搜 gcc 发现返回这三个结果:

1
2
3
compiler-gcc.h
compiler-gcc3.h
compiler-gcc4.h

所以要找的跨平台编译链工具的版本号大概是 4 左右。在 GNU Arm Embedded Toolchain 的官网可以查到最后一个 4.9 的版本是 4.9-2015-q3-update。下载下来解压并配置好环境变量:

1
2
3
export ARCH=arm
export SUBARCH=arm
export CROSS_COMPILE=/home/user/gcc-arm-none-eabi-4_9-2015q3/bin/arm-none-eabi-

在这个仓库里用 git log 可以看到:

The Patch based on NVIDIA release TAG tegra-17r18-android-4.2

The kernel config file used is tegra11_pisces_user_defconfig

接下来先建一个输出文件夹,然后开始编译:

1
2
3
mkdir out
make O=out tegra11_pisces_user_defconfig
make -j32 O=out

中间遇到错误停下来编译终止,查看报错的是 /drivers/media/video/tegra/ad5823.c 这里出现 error: iteration 6u invokes undefined behavio, 按照搜到的方法在下面的代码中:

1
2
3
4
5
6
for (i = 0; i <= ARRAY_SIZE(ad5823_gpios); i++) {
if (info->gpio[i].flag && info->gpio[i].own) {
gpio_free(info->gpio[i].gpio);
info->gpio[i].own = false;
}
}

把 <= 改成< 后就好了。改完后重新开始编译,若编译成功最后的 log 里会出现 zImage is ready 的字样。在 ./out/arch/arm/boot 下面的 zImage 文件就是编译好的内核文件。

现在要把 zImage 打包成 img 文件刷进手机。把官方的线刷文件的 boot.img 文件拿过来,然后用 abootimg 将 zImage 刷进去:

1
abootimg -u boot.img -k zImage

再将处理好的 boot.img 文件放回到原来的刷机包里正常线刷就行了。刷机成功后打开手机查看参数可以看到内核版本的参数已经改变了:

就是不知道最后为啥加了一个 dirty 的后缀…

dirty 后缀的原因找到了, 在 /scrpit/setlocalversion 里第 60 - 63 行, 如果有未提交的更改机会在内核后面加 dirty 的后缀:

1
2
3
4
# Check for uncommitted changes
if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then
printf '%s' -dirty
fi

上面的 if 判断注释掉就就不会有 dirty 后缀了。

开机后发现有些第三方的预装 APP。这些 APP 在刷机包里对应的文件在 userdata.img 里。可以用 simg2img 将 img 文件转成 ext4 文件再用 mount 挂载编辑,然后打包回来,这样很麻烦。搜了下发现可以直接用蘑菇 ROM 助手来在图形界面下编辑预装 APP 然后打包,非常方便。将精简好的 userdata.img 文件放回到刷机包,刷机完成后系统会非常干净。

这篇文章参考了:

How to compile kernel standalone

编译小米3td内核记录

求大佬发编译教程