> 设备: Google Pixel 2 (walleye) | Android 10 (QQ3A.200605.001) | Kernel 4.4.223 | KernelSU v0.9.5
>
> 编译环境: Ubuntu 22.04
## 背景
KernelSU 官方从 v1.0 开始不再维护非 GKI (Generic Kernel Image) 设备的支持。Pixel 2 使用的是 4.4 老内核,属于非 GKI 设备,只能通过**手动修改内核源码**的方式集成 KernelSU。
目前社区针对 Pixel 2 的 KernelSU 适配仅有 [AR-Project-Studio/kernel_google_wahoo](075K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6m8f1W2)9J5k6q4m8J5L8$3A6W2j5%4c8Q4x3X3c8e0N6s2g2V1K9h3!0Q4x3V1k6C8k6i4u0F1k6h3I4Q4y4h3k6Y4L8$3!0Y4L8r3g2Q4y4h3k6%4j5h3S2G2L8H3`.`.) 一个仓库,但它**只提供了 Android 14 分支的源码,没有预编译产物**,也没有对应的编译教程。而 Android 10 版本在整个社区中几乎没有可参考的资料。加上内核编译对磁盘空间(~15-20GB)和工具链版本的要求较高,想在 Android 10 上复现 KernelSU 基本只能从零摸索。
本文记录了在 Android 10 上完成这一过程的完整思路、踩坑经验和关键修复。
## 整体思路
```
获取 AOSP 内核源码 (4.4)
|
集成 KernelSU v0.9.5 源码
|
修改内核 fs/ 和 drivers/ 中的 6 个 Hook 点
|
使用 AOSP Clang + GCC 交叉编译
|
从工厂镜像提取 ramdisk + 新内核 → 打包 boot.img
|
fastboot 刷入
```
## 关键信息确认
在动手之前,需要先确认以下信息,任何一个搞错都会导致编不过或刷入后无法启动:
| 项目 | 值 | 确认方式 |
|---|---|---|
| 内核分支 | `android-msm-wahoo-4.4-android10-qpr3` | AOSP 官方文档 legacy kernel 表 |
| 内核版本 | 4.4.223 | 与工厂镜像 build 号 QQ3A.200605.001 对应 |
| KernelSU 版本 | v0.9.5 | 最后一个支持非 GKI 的版本,v1.0+ 明确不支持 |
| defconfig | `wahoo_defconfig` | walleye 和 taimen 共用 wahoo 平台 |
| 编译工具链 | AOSP Clang (clang-r370808) + GCC 4.9 | 需要 64 位和 32 位两套 GCC |
## 编译流程
### Step 1: 安装依赖
```bash
apt update
apt install -y build-essential bc bison flex libssl-dev libelf-dev \
git curl wget python3 python-is-python3 zip unzip cpio mkbootimg \
gcc-aarch64-linux-gnu gcc-arm-linux-gnueabi
```
### Step 2: 下载源码和工具链
```bash
WORK_DIR="$HOME/walleye_kernelsu"
mkdir -p "$WORK_DIR" && cd "$WORK_DIR"
# 内核源码
git clone 1beK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0W2k6$3!0G2k6$3I4W2M7$3!0#2M7X3y4W2i4K6u0W2j5$3!0E0i4K6u0r3K9$3g2J5L8X3g2D9i4K6u0r3L8i4y4E0 \
-b android-msm-wahoo-4.4-android10-qpr3 --depth=1 kernel
# AOSP Clang
git clone 22cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0W2k6$3!0G2k6$3I4W2M7$3!0#2M7X3y4W2i4K6u0W2j5$3!0E0i4K6u0r3M7r3I4S2N6r3k6G2M7X3#2Q4x3V1k6H3M7X3g2T1N6h3W2D9N6s2y4Q4x3V1k6U0L8r3q4F1k6#2)9J5c8X3S2G2M7%4c8Q4x3V1k6D9K9h3&6#2P5q4)9J5k6s2R3^5y4R3`.`. \
--depth=1 -b android10-release clang
# GCC 64位 (注意必须指定 -b android10-release)
git clone af3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0W2k6$3!0G2k6$3I4W2M7$3!0#2M7X3y4W2i4K6u0W2j5$3!0E0i4K6u0r3M7r3I4S2N6r3k6G2M7X3#2Q4x3V1k6H3M7X3g2T1N6h3W2D9N6s2y4Q4x3V1k6Y4j5$3y4Q4x3V1k6D9K9h3&6#2P5q4)9J5k6s2R3^5y4W2)9J5c8X3q4S2M7X3y4Z5y4U0c8Q4x3V1k6S2j5i4u0U0K9o6j5@1i4K6u0V1L8r3W2F1N6i4S2Q4x3X3c8S2L8X3c8J5L8$3W2V1i4K6u0V1y4q4)9J5k6e0V1`. \
--depth=1 -b android10-release gcc-aarch64
# GCC 32位 (vDSO 编译需要,同样需指定分支)
git clone d56K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0W2k6$3!0G2k6$3I4W2M7$3!0#2M7X3y4W2i4K6u0W2j5$3!0E0i4K6u0r3M7r3I4S2N6r3k6G2M7X3#2Q4x3V1k6H3M7X3g2T1N6h3W2D9N6s2y4Q4x3V1k6Y4j5$3y4Q4x3V1k6D9K9h3&6#2P5q4)9J5k6s2R3^5y4W2)9J5c8X3q4J5L8g2)9J5c8X3q4J5L8g2)9J5k6r3I4A6L8Y4g2^5i4K6u0V1j5h3&6V1M7X3!0A6k6r3g2S2j5X3W2Q4x3X3b7@1i4K6u0W2z5b7`.`. \
--depth=1 -b android10-release gcc-arm32
```
### Step 3: 下载工厂镜像,提取原始 boot.img
```bash
cd "$WORK_DIR"
wget -O factory.zip "e01K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8q4)9J5k6h3N6G2L8$3N6D9k6g2)9J5k6h3y4G2L8g2)9J5c8X3c8D9i4K6u0r3j5h3&6V1M7X3!0A6k6q4)9J5c8X3q4G2M7%4m8Q4x3V1k6%4j5h3I4D9k6i4W2W2i4K6u0V1M7i4p5K6j5g2)9J5k6e0t1H3x3o6j5H3y4g2)9J5k6e0l9H3x3g2)9J5k6r3k6S2j5%4c8G2M7Y4W2Q4x3X3b7$3y4X3f1^5k6o6V1@1k6g2)9J5k6i4A6A6M7q4)9J5y4Y4q4#2L8%4c8Q4x3@1t1`.
unzip factory.zip -d factory_extract
unzip factory_extract/walleye-qq3a.200605.001/image-walleye-qq3a.200605.001.zip boot.img -d factory_extract
cp factory_extract/boot.img boot_orig.img
rm -rf factory.zip factory_extract
```
### Step 4: 集成 KernelSU 并修改内核源码
```bash
cd "$WORK_DIR/kernel"
# 拉取 KernelSU v0.9.5
curl -LSs "fddK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6J5j5i4N6Q4x3X3g2Y4K9i4c8Z5N6h3u0#2M7$3g2J5j5$3!0F1N6r3g2F1N6q4)9J5k6h3y4G2L8g2)9J5c8Y4c8A6j5h3&6F1i4K6u0r3d9$3g2J5L8X3g2D9f1#2g2Q4x3V1k6E0j5h3W2F1i4K6u0r3K9$3g2J5L8X3g2D9i4K6u0r3M7$3g2@1N6i4m8Q4x3X3g2K6K9q4)9J5y4Y4q4#2L8%4c8Q4x3@1t1`. | bash -s v0.9.5
# 启用 CONFIG_KSU
echo -e "\n# KernelSU\nCONFIG_KSU=y" >> arch/arm64/configs/wahoo_defconfig
```
然后修改 6 个内核源文件,添加 KernelSU Hook(详见 KernelSU 官方文档"修改内核源码"章节):
| 文件 | Hook 函数 | 4.4 内核注意点 |
|---|---|---|
| `fs/exec.c` | `do_execveat_common` | -- |
| `fs/open.c` | `do_faccessat` | 4.4 可能没有此函数,需改 `SYSCALL_DEFINE3(faccessat,...)` |
| `fs/read_write.c` | `vfs_read` | -- |
| `fs/stat.c` | `vfs_fstatat` | 4.4 没有 `vfs_statx`,必须用 `vfs_fstatat`,且参数名是 `flag` 不是 `flags` |
| `drivers/input/input.c` | `input_handle_event` | 安全模式,音量键救砖 |
| `fs/devpts/inode.c` | `devpts_get_priv` | 修复 pm 命令 |
### Step 5: 编译
```bash
cd "$WORK_DIR/kernel"
export ARCH=arm64
export SUBARCH=arm64
make CC=clang \
CLANG_TRIPLE=aarch64-linux-gnu- \
CROSS_COMPILE=$WORK_DIR/gcc-aarch64/bin/aarch64-linux-android- \
CROSS_COMPILE_ARM32=$WORK_DIR/gcc-arm32/bin/arm-linux-androideabi- \
wahoo_defconfig
make CC=clang \
CLANG_TRIPLE=aarch64-linux-gnu- \
CROSS_COMPILE=$WORK_DIR/gcc-aarch64/bin/aarch64-linux-android- \
CROSS_COMPILE_ARM32=$WORK_DIR/gcc-arm32/bin/arm-linux-androideabi- \
-j12 Image.lz4-dtb
```
### Step 6: 打包 boot.img
```bash
cd "$WORK_DIR"
# 解包原始 boot.img 获取 ramdisk
python3 mkbootimg_tools/unpack_bootimg.py --boot_img boot_orig.img --out boot_unpack
# 使用正确的 cmdline 和 header_version 重新打包
mkbootimg \
--kernel kernel/arch/arm64/boot/Image.lz4-dtb \
--ramdisk boot_unpack/ramdisk \
--cmdline "androidboot.hardware=walleye androidboot.console=ttyMSM0 lpm_levels.sleep_disabled=1 user_debug=31 msm_rtb.filter=0x37 ehci-hcd.park=3 service_locator.enable=1 swiotlb=2048 firmware_class.path=/vendor/firmware loop.max_part=7 raid=noautodetect usbcore.autosuspend=7 androidboot.dtbo_idx=3 buildvariant=user" \
--base 0x00000000 \
--pagesize 4096 \
--os_version 10.0.0 \
--os_patch_level 2020-06 \
--header_version 0 \
-o boot-kernelsu.img
```
### Step 7: 刷入
```bash
adb reboot bootloader
fastboot flash boot boot-kernelsu.img
fastboot reboot
# 救砖(如果无法启动)
# fastboot flash boot boot_orig.img
```
---
## 踩坑记录与原始脚本问题分析
以下是初版编译脚本中的问题,通过 diff 对比和实际编译过程发现并修复。
### 坑 1: AOSP prebuilt 仓库不指定分支会克隆到空内容
**现象**: `git clone ... --depth=1 gcc-aarch64` 后目录内只有一个 `OWNERS` 文件,没有 `bin/` 目录。
**原因**: AOSP prebuilt 仓库的默认分支可能是空的或只有元数据文件。必须指定 `-b android10-release` 才能拉到正确的工具链二进制。
**修复**:
```bash
# 错误写法
git clone $GCC_REPO --depth=1 gcc-aarch64
# 正确写法
git clone $GCC_REPO --depth=1 -b android10-release gcc-aarch64
```
> 64 位和 32 位 GCC 都存在同样的问题。
### 坑 2: Ubuntu 22.04 没有 `python` 命令
**现象**: `make defconfig` 时报 `/usr/bin/env: 'python': No such file or directory`
**原因**: Ubuntu 22.04 默认只有 `python3`,不提供 `python` 软链接。老内核的 Makefile/scripts 中调用的是 `python`。
**修复**: 安装 `python-is-python3` 包。
### 坑 3: 缺少 32 位交叉编译器 (`CROSS_COMPILE_ARM32`)
**现象**: `arch/arm64/Makefile:48: *** CROSS_COMPILE_ARM32 not defined or empty, the compat vDSO will not be built. Stop.`
**原因**: wahoo 内核的 compat vDSO (32位兼容层) 需要一个 ARM 32 位的交叉编译器。初版脚本完全漏掉了这个。
**修复**: 额外克隆 `arm-linux-androideabi-4.9` 并在 make 时传入 `CROSS_COMPILE_ARM32=` 参数。
### 坑 4: GCC 10+ `yylloc` 重复定义
**现象**: `multiple definition of 'yylloc'` 链接错误。
**原因**: GCC 10 开始默认 `-fno-common`,而老内核 dtc 工具的 `dtc-lexer.lex.c` 中 `YYLTYPE yylloc;` 会在多个编译单元中产生重复定义。
**修复**:
```bash
sed -i 's/^YYLTYPE yylloc;/extern YYLTYPE yylloc;/' scripts/dtc/dtc-lexer.lex.c
```
### 坑 5: vDSO 32 位汇编器路径传递失败
**现象**: `/..//bin/as: unrecognized option '-EL'` — 路径中出现 `/..//` 说明变量为空。
**原因**: `CROSS_COMPILE_ARM32` 通过 `export` 设置环境变量,但 vdso32 子 Makefile 没有正确继承。
**修复**: 将 `CROSS_COMPILE_ARM32` 作为 **make 命令行参数** 直接传入,而不是依赖环境变量:
```bash
make CC=clang ... CROSS_COMPILE_ARM32="$GCC32" -j12
```
### 坑 6: make 目标不明确
**初版脚本**: `make -j12`(不指定目标)
**修复版**: `make -j12 Image.lz4-dtb`
显式指定编译目标可以避免编译不必要的模块,加快速度并减少出错概率。
### 坑 7: boot.img cmdline 和 header_version 不正确
**初版脚本**:
```bash
--cmdline "console=ttyMSM0,115200,n8 androidboot.console=ttyMSM0 ..."
--header_version 1
```
**修复版**:
```bash
--cmdline "androidboot.hardware=walleye androidboot.console=ttyMSM0 lpm_levels.sleep_disabled=1 ..."
--header_version 0
```
**原因**:
- cmdline 必须与工厂镜像中的完全一致,否则可能导致启动异常。初版是一个不完整的猜测值。
- Pixel 2 Android 10 使用的是 boot header **version 0**,不是 1。header version 不匹配会导致 bootloader 解析失败。
---
## 资源消耗实测
| 项目 | 实测 |
|---|---|
| 内核源码 (depth=1) | ~3 GB |
| Clang 工具链 | ~5 GB |
| GCC 64 + 32 | ~2 GB |
| 编译产物 | ~1.5 GB |
| 工厂镜像下载 | ~1.5 GB |
| **总计** | **~13 GB** |
| 编译时间 (16核 -j12) | ~10 分钟 |
| 内存峰值 | ~6 GB |
## 最终效果
刷入后 KernelSU 正常运行,内核版本 4.4.210,Manager 版本 v0.9.5:

- **Status**: Working
- **Kernel**: 4.4.210-g9cb5a881-dirty
- **Fingerprint**: google/walleye/walleye:10/QQ3A.200605.001/6392402:user/release-keys
- **SELinux**: Enforcing
- **Superusers**: 1 | **Modules**: 1
## 附件
附件中提供了 Ubuntu 环境下的一键编译脚本 `build_kernelsu_walleye_fix.sh`,在 Ubuntu 22.04 上可直接以 root 权限运行:
```bash
chmod +x build_kernelsu_walleye_fix.sh
sudo ./build_kernelsu_walleye_fix.sh
```
脚本涵盖从依赖安装、源码下载、KernelSU 集成、内核编译到 boot.img 打包的全部流程,支持单步调试(如 `./build_kernelsu_walleye_fix.sh build` 只执行编译步骤)。
## 总结
在现代 Linux (Ubuntu 22.04, GCC 11) 上编译 4.4 老内核,最大的挑战不在于 KernelSU 本身的集成,而在于**工具链兼容性**。核心教训:
1. **AOSP prebuilt 仓库必须指定分支**,默认分支可能是空的
2. **新旧编译器不兼容**是最常见的编译错误来源 (`python` / `-fno-common` / `CROSS_COMPILE_ARM32`)
3. **boot.img 参数必须精确匹配原始镜像**,尤其是 `cmdline` 和 `header_version`
4. **make 参数优先于 export 环境变量**,确保子 Makefile 能正确接收
5. KernelSU 非 GKI 集成最后支持的版本是 **v0.9.5**,不要用 v1.0+
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!