Pixel 6 自编译 AOSP 卡在 android Logo 与触屏失效:一次 vendor_dlkm 集成问题排查
这次问题发生在 Pixel 6(oriole)自编译 Android 15 / BP1A.250305.019 镜像时。系统镜像可以刷入,内核也能启动,Google Logo 之后进入 android 启动画面,但长时间无法进入桌面;另一个相关现象是触屏模块没有按预期工作。
最终定位结果不是 system 分区、userdata 格式化、fastboot 刷机流程,也不是 6.1 内核本身不能用于 Pixel 6,而是本地集成 6.1 内核产物时错误使用了 kernel dist 目录里预生成的 vendor_dlkm.img。这个镜像只包含模块和模块列表,缺少设备侧启动时需要的 /vendor_dlkm/etc/init.insmod.oriole.cfg,导致设备专属模块加载链路没有跑完。
环境背景
这次基线组合如下:
Device: Pixel 6 / oriole
Android: Android 15
Build ID: BP1A.250305.019
AOSP tag: android-15.0.0_r20
Kernel branch: android-gs-raviole-6.1-android15-qpr2-beta
Kernel version: 6.1.99一开始容易被历史经验带偏:Pixel 6 很长时间对应的是 5.10 内核,但官方 Android 15 的 BP1A.250305.019 镜像实际已经是 6.1 内核。
设备上官方镜像的确认结果是:
Linux localhost 6.1.99-android14-11-gd6f926cfde54-ab12786694
google/oriole/oriole:15/BP1A.250305.019/13003188:user/release-keys所以这次方向不是“Pixel 6 能不能刷 6.1”,而是“本地 6.1 内核产物如何正确接入 AOSP 打包流程”。
故障现象
刷入自编译包后,设备表现为:
- bootloader 和 fastboot update 流程正常;
boot.img、vendor_boot.img、vendor_dlkm.img都可以写入;- Google Logo 之后进入
android启动画面; - 启动画面停留很久,随后可能回到 bootloader 或持续重启;
- 早期阶段能看到系统服务启动迹象,但无法进入桌面;
- 触屏相关模块没有按预期可用。
这个阶段最容易怀疑的是 userdata 或动态分区刷写问题,但 logcat 里已经能看到 /metadata、/data、zygote 和 system_server 的启动过程,说明系统已经走到比较靠后的 Android userspace 阶段。
logcat 里的关键线索
问题的关键不在“卡 Logo”本身,而在 system_server 为什么被卡住。
logcat 中的异常路径集中在:
VibratorManagerService.nativeGetVibratorIds()随后 watchdog 超时杀掉 system_server。同时,android.hardware.vibrator.IVibrator/default 没有注册成功。
Pixel 6 的 vibrator HAL 由 vendor 侧服务提供,服务二进制位于:
/vendor/bin/hw/android.hardware.vibrator-service.cs40l25它不是无条件启动,而是受 init 属性触发。关键触发条件是:
vendor.all.modules.ready=1也就是说,vibrator HAL 没有启动只是表层现象,更上游的问题是“模块加载完成”的属性没有被设置。
为什么触屏也会失效
Pixel 6 的设备专属模块加载依赖 /vendor_dlkm/etc/init.insmod.oriole.cfg。这个配置里不仅设置 ready 属性,也会加载触屏、Wi-Fi、安全芯片等设备模块:
modprobe|bcmdhd4389.ko
modprobe|ftm5.ko
modprobe|sec_touch.ko
modprobe|st33spi.ko
setprop|vendor.device.modules.ready
setprop|vendor.all.modules.ready
setprop|vendor.all.devices.ready其中 ftm5.ko、sec_touch.ko 就和触屏链路直接相关。因此当 init.insmod.oriole.cfg 没有被打进 vendor_dlkm.img 时,不只是 vibrator HAL 等不到 ready 属性,触屏模块也可能没有按设备预期加载。
这就是“卡 android Logo”和“触屏失效”看起来像两个问题,但实际共享同一个根因。
根因:直接使用了 kernel dist 的 vendor_dlkm.img
本次集成 6.1 内核产物时,曾经在 vendor/google_devices/oriole/BoardConfigPartial.mk 里优先选择本地 kernel dist 的 vendor_dlkm.img:
BOARD_PREBUILT_VENDOR_DLKMIMAGE := $(TARGET_KERNEL_DIR)/vendor_dlkm.img这个做法看起来直接,但会绕过 AOSP 对 vendor_dlkm 分区的正常 staging 流程。
kernel dist 里的 vendor_dlkm.img 主要来自内核构建产物,它包含 .ko 模块和 vendor_dlkm.modules.load,但它不知道 Pixel 6 设备目录里还需要额外打进去的:
device/google/raviole/init.insmod.oriole.cfg结果就是:
vendor_dlkm.img里有模块;- 但缺少
/etc/init.insmod.oriole.cfg; insmod_sh_raviole找不到设备配置;vendor.all.modules.ready不会被设置;- vibrator HAL 不启动;
system_server卡在 vibrator service 初始化;- watchdog 杀掉
system_server; - 表现为长时间卡在
androidLogo。
正确修复方式
修复思路是:本地内核产物只提供模块、模块加载列表和内核镜像,不直接接管整个 vendor_dlkm.img。让 AOSP 重新生成 vendor_dlkm.img,这样设备侧的 PRODUCT_COPY_FILES 和 BOARD_VENDOR_KERNEL_MODULES 规则才能一起生效。
修正后的 BoardConfigPartial.mk 逻辑是:
BOARD_PREBUILT_VENDORIMAGE := vendor/google_devices/oriole/proprietary/vendor.img
ifneq (,$(wildcard $(TARGET_KERNEL_DIR)/vendor_dlkm.modules.load))
BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE := ext4
else
BOARD_PREBUILT_VENDOR_DLKMIMAGE := vendor/google_devices/oriole/proprietary/vendor_dlkm.img
endif
TARGET_COPY_OUT_VENDOR_DLKM := vendor_dlkm这里的含义是:
- 如果正在使用本地 kernel dist,并且存在
vendor_dlkm.modules.load,就让 AOSP 从本地.ko重新构建vendor_dlkm.img; - 如果没有本地 kernel dist,就继续使用官方 proprietary 里的预编译
vendor_dlkm.img; - 不再直接使用 kernel dist 里那个完整的
vendor_dlkm.img。
重新打包后的 vendor_dlkm staging 目录需要能看到:
vendor_dlkm/etc/init.insmod.oriole.cfg
vendor_dlkm/lib/modules/haptics-cs40l2x.ko
vendor_dlkm/lib/modules/ftm5.ko
vendor_dlkm/lib/modules/sec_touch.ko
vendor_dlkm/lib/modules/modules.load临时验证方法
如果设备已经卡在启动动画,但 adb 还能连上,可以临时设置属性验证判断:
adb root
adb wait-for-device
adb shell getprop vendor.all.modules.ready
adb shell setprop vendor.all.modules.ready 1
adb shell getprop init.svc.vendor.vibrator.cs40l25如果设置后 vibrator HAL 从未启动变成 running,说明方向基本正确。不过这只是验证手段,不是最终修复。最终还是要把 init.insmod.oriole.cfg 正确打进 vendor_dlkm.img。
刷机包检查
重新生成的 fastboot update 包至少应包含:
android-info.txt
fastboot-info.txt
boot.img
dtbo.img
product.img
pvmfw.img
super_empty.img
system.img
system_ext.img
system_other.img
userdata.img
vbmeta.img
vbmeta_system.img
vendor.img
vendor_boot.img
vendor_dlkm.img其中 super_empty.img 对 fastboot update 的动态分区流程有意义;vendor_dlkm.img 则必须是 AOSP 重新 staging 后的版本,而不是直接从 kernel dist 复制出来的版本。
Windows 下刷入方式:
fastboot -w update C:\Users\7owe2\Desktop\image-oriole-bp1a.250305.019.zip这个包不包含 bootloader 和 radio 时,不需要先刷 bootloader,也不应该把“官方 factory image 的 flash-all 流程”机械套到这个自编译 image zip 上。fastboot update 会按 zip 内的 android-info.txt 和 fastboot-info.txt 执行已有分区镜像的刷写。
经验沉淀
这次问题的教训比较明确:
vendor_dlkm.img不是“只要有模块就行”,它还承载设备启动时的模块加载配置。- kernel dist 里的完整镜像不一定等价于 AOSP product out 里的最终分区镜像。
- Pixel 设备的 vendor HAL 可能依赖
vendor.all.modules.ready这类属性触发,某个 HAL 不启动时要往上查 init 触发条件。 - 卡在
androidLogo 不一定是 system 镜像或 userdata 问题,system_serverwatchdog 也会表现成类似现象。 - 自编译内核接入 AOSP 时,优先让 AOSP 完成最终镜像 staging,而不是手动替换完整分区镜像。
后续如果继续做 Pixel 6 / Android 15 / 6.1 内核自编译,应该把这条规则固定下来:本地 kernel dist 提供 boot.img、dtbo.img、.ko 和模块列表,最终的 vendor_dlkm.img 由 AOSP 产品构建系统生成。这样设备侧的 init.insmod.oriole.cfg、模块加载顺序和 ready 属性才能保持一致。