title: "给一加 Ace 3 Pro 换上赛博朋克开关机动画:从 EROFS 到 KernelSU 持久化模块"
slug: "ace3pro-cyberpunk-boot-animation"
date: "2026-08-05"
categories:
- "Android"
tags:
- "OnePlus Ace 3 Pro"
- "ColorOS"
- "KernelSU Next"
- "BootAnimation"
- "Root"
description: "记录一次从动画文件分析、只读分区适配、bind mount 测试,到 KernelSU 持久化模块和三版本发布的完整过程。"
draft: false最近给一加 Ace 3 Pro 折腾 Root 环境时,我顺手把开机和关机动画也换成了 Cyberpunk 2077 风格。
最终效果是:
电源菜单重启
→ Cyberpunk 关机动画
→ Bootloader unlocked 黄色提示
→ Cyberpunk 开机动画
→ 进入系统
看起来只是“换两个 ZIP”,真正动手以后才发现,ColorOS 16 下的动画文件位于只读的 EROFS 分区,普通替换根本行不通;不同重启方式、软重启和第三方预览工具还各有各的问题。
这篇文章记录一下整个适配过程,以及最后如何把它做成一个可安装、可禁用、可恢复原厂动画的 KernelSU 模块。
测试环境
| 项目 | 信息 |
|---|---|
| 设备 | OnePlus Ace 3 Pro / PJX110 |
| 系统 | ColorOS 16 / Android 16 |
| 固件 | PJX110_16.0.5.701(CN01) |
| Root | KernelSU Next 3.3.0 |
| 内核 | WildKernel 6.1.141-android14-OP-WILD |
| 模块机制 | Magisk-style / systemless module |
本文所有结论都基于上面这套环境。其他 ColorOS 版本、Magisk、APatch 或其他机型可能也能用,但我没有替它们做完整实机验证。
动画文件到底在哪里
一加 Ace 3 Pro 的开机和关机动画分别位于:
/my_product/media/bootanimation/bootanimation.zip
/my_product/media/bootanimation/rbootanimation.zip
先确认文件和 SELinux 标签:
su
ls -lZ \
/my_product/media/bootanimation/bootanimation.zip \
/my_product/media/bootanimation/rbootanimation.zip
问题在于 /my_product 是 EROFS,只读。
也就是说,下面这种最直接的思路并不可行:
cp bootanimation.zip \
/my_product/media/bootanimation/bootanimation.zip
即使拿到了 Root 权限,也不能把 EROFS 当成普通可写分区处理。
为什么最后选择 bind mount
既然不能真正改写原文件,就让系统在运行时看到另一个文件。
手动测试时,可以这样做:
su
mount --bind \
/data/local/tmp/bootanimation.zip \
/my_product/media/bootanimation/bootanimation.zip
mount --bind \
/data/local/tmp/rbootanimation.zip \
/my_product/media/bootanimation/rbootanimation.zip
bind mount 生效以后,目标路径没有变化,但打开它时读到的已经是自定义动画。
这种方式有几个优点:
- 不改写
/my_product - 不破坏原厂动画
- 挂载消失后自动恢复原文件
- 很适合封装为 systemless 模块
- 出问题时禁用模块并重启即可回退
手动挂载确认开机、关机动画都能正常播放以后,剩下的工作就是让它在每次完整启动时自动执行。
模块结构
最终模块结构很简单:
cyberpunk-animation.zip
├── module.prop
├── post-fs-data.sh
├── skip_mount
├── bootanimation.zip
└── rbootanimation.zip
module.prop 用于声明模块信息:
id=cyberpunk_dual_animation
name=Cyberpunk Boot + Shutdown Animation - Flatline
version=1.1.0-flatline
versionCode=110
author=akizukishiro
description=Cyberpunk 2077 Flatline boot and shutdown animations for OnePlus Ace 3 Pro
三个动画版本都使用相同的模块 ID:
id=cyberpunk_dual_animation
这样切换版本时会替换当前模块,而不是出现三个模块同时争抢相同挂载路径。
skip_mount 是一个空文件,用来阻止模块管理器自动把模块目录映射进系统。真正的替换工作全部由 post-fs-data.sh 完成。
核心脚本
持久化模块的核心脚本如下:
#!/system/bin/sh
MODDIR=${0%/*}
BOOT_SRC="$MODDIR/bootanimation.zip"
BOOT_DST="/my_product/media/bootanimation/bootanimation.zip"
SHUTDOWN_SRC="$MODDIR/rbootanimation.zip"
SHUTDOWN_DST="/my_product/media/bootanimation/rbootanimation.zip"
LOG="$MODDIR/bootanimation.log"
echo "start" > "$LOG"
prepare_source() {
SOURCE_FILE="$1"
chown 0:0 "$SOURCE_FILE" 2>> "$LOG"
chmod 0644 "$SOURCE_FILE" 2>> "$LOG"
chcon u:object_r:system_file:s0 "$SOURCE_FILE" 2>> "$LOG"
}
bind_animation() {
SOURCE_FILE="$1"
TARGET_FILE="$2"
LABEL="$3"
if [ ! -f "$SOURCE_FILE" ]; then
echo "$LABEL source missing" >> "$LOG"
return
fi
if [ ! -f "$TARGET_FILE" ]; then
echo "$LABEL target missing" >> "$LOG"
return
fi
prepare_source "$SOURCE_FILE"
if mount --bind "$SOURCE_FILE" "$TARGET_FILE"; then
echo "$LABEL bind ok" >> "$LOG"
else
echo "$LABEL bind failed" >> "$LOG"
fi
}
bind_animation "$BOOT_SRC" "$BOOT_DST" "boot"
bind_animation "$SHUTDOWN_SRC" "$SHUTDOWN_DST" "shutdown"
exit 0
启动后可以查看日志:
su
cat /data/adb/modules/cyberpunk_dual_animation/bootanimation.log
正常情况下会看到:
start
boot bind ok
shutdown bind ok
还可以通过 PID 1 的 mountinfo 确认挂载确实存在:
su
grep -E \
" /my_product/media/bootanimation/(bootanimation|rbootanimation)\.zip " \
/proc/1/mountinfo
为什么先做 One-Shot 测试模块
开机动画模块最麻烦的地方在于:测试失败时,可能要等到下一次启动才能处理。
为了避免一个错误模块持续生效,我先做了 One-Shot 测试版。它在第一次启动时完成挂载,同时自动创建:
/data/adb/modules/<module-id>/disable
这样本次启动仍然能播放测试动画,但下一次启动模块会自动禁用,恢复原厂动画。
One-Shot 版本额外包含这一行:
touch "$MODDIR/disable"
完整测试流程是:
安装测试模块
→ 第一次重启播放自定义开机动画
→ 进入系统后检查日志和哈希
→ 使用电源菜单重启,检查关机动画
→ 第二次启动自动恢复原厂动画
三个版本都通过了开机、关机、挂载和自动回退测试以后,才生成正式持久化包。
三种动画版本
动画素材来自 sodasoba1/ONEPLUS9-OOS13-BootAnimation。我为 Ace 3 Pro 打包了三个版本。
OnePlus Glitch
将原本的 Cyberpunk 标志替换为 OnePlus 标志,并加入故障效果和配套关机动画。
| 开机动画 | 关机动画 |
|---|---|
![]() |
![]() |
CyberGlitch
在 OnePlus Glitch 的基础上增加了更多故障效果。
它的 desc.txt 是:
g 1080 2400 0 0 60
c 1 0 part1
c 1 0 part2
两个部分都只播放一次。实机表现不是播放结束后黑屏,而是停留在最后一帧,直到 Android 进入下一阶段。
| 开机动画 | 关机动画 |
|---|---|
![]() |
![]() |
Cyberpunk Flatline
这是我最后选择长期使用的版本。
它重新编辑了启动文字、存储设备文字和控制台动画,第二部分会持续循环,关机动画也带有 Flatlined 循环效果。
g 1080 2400 0 0 60
c 1 0 part1
c 0 0 part2
其中 part1 播放一次,part2 循环到 Android 启动完成。
关机动画为 30 FPS:
g 1080 300 0 641 30
p 1 0 part0
p 0 0 part1
| 开机动画 | 关机动画 |
|---|---|
![]() |
![]() ![]() |
原仓库 README 中把 Flatline 写成过 Flateline,这里统一使用正确拼写 Flatline。
实际重启表现
不同重启方式并不完全一样。
电源菜单普通重启
Cyberpunk 关机动画
→ unlocked 黄色提示
→ Cyberpunk 开机动画
这是最完整的效果。
KernelSU Next 普通重启
表现和电源菜单一致:
Cyberpunk 关机动画
→ unlocked 黄色提示
→ Cyberpunk 开机动画
终端执行 reboot
短暂黑屏
→ unlocked 黄色提示
→ Cyberpunk 开机动画
终端中的 reboot 可能直接跳过关机动画。
KernelSU Next 软重启
不建议使用。
在这台设备上,软重启会让原厂和自定义开机动画都只显示左上角区域,右侧和下方被裁切。既然原厂动画也会复现,就说明问题不在动画文件,而在软重启后的显示管线状态。
一个非常坑的预览功能
某些工具箱带有“播放当前开机动画”的预览功能。我测试后,整个系统画面被缩到了左上角,右侧和底部出现大块黑边,但触控坐标仍按原分辨率计算。
最危险的是,这时不能盲目执行:
wm size reset
wm density reset
ColorOS 在这台设备上本来就使用逻辑分辨率和密度覆盖,直接 reset 反而会把显示参数改错。
正常参数为:
Physical size: 1264x2780
Override size: 1080x2376
Physical density: 560
Override density: 480
对应恢复命令:
su
wm size 1080x2376
wm density 480
reboot
这些数值只适用于本文测试的 Ace 3 Pro,不应照搬到其他设备。
黄色 unlocked 提示为什么换不掉
开机时出现的黄色 unlocked 提示属于 Bootloader 阶段。
Android 的 bootanimation.zip 还没开始播放时,它就已经显示了。因此这个模块无法修改或隐藏该提示。
完整顺序实际上是:
Bootloader 提示
→ Android BootAnimation 服务
→ 系统界面
开关机动画模块只能控制中间的 Android BootAnimation 阶段。
导出 MP4 预览时遇到的另一个问题
为了发博客和朋友圈,我还把 Flatline 动画导出成了四段 MP4:
开机初始动画:part1
开机循环动画:part2
关机初始动画:part0
关机循环动画:part1
循环段导出 20 秒,初始段完整播放一次。
需要注意的是,desc.txt 中的 60 FPS 和 30 FPS 是目标帧率。实际开机时还要解码 PNG、上传纹理和渲染;设备处理某些帧超过目标间隔时,BootAnimation 不一定会跳帧追赶。
所以用 FFmpeg 严格导出 60 FPS 的视频,可能会比手机实机播放稍快。想完全复刻实机速度,最好用手机录像测出每一段实际时长,再按:
实际平均帧率 = 该段总帧数 ÷ 实机播放时长
重新导出。
发布方式
完整模块包比较大,不适合直接塞进 Git 仓库历史。我把脚本、README 和预览 GIF 放在仓库中,把可安装 ZIP 放到 GitHub Releases。
项目仓库:
Release 中提供三个安装包:
OnePlus-Ace3Pro-Cyberpunk-OnePlusGlitch-v1.1.0.zip
OnePlus-Ace3Pro-Cyberpunk-CyberGlitch-v1.1.0.zip
OnePlus-Ace3Pro-Cyberpunk-Flatline-v1.1.0.zip
三个包只能选择一个安装。由于它们使用相同模块 ID,安装另一个版本会覆盖当前版本。
GitHub 自动生成的:
Source code (zip)
Source code (tar.gz)
只是仓库快照,不是完整可刷入模块。
如何恢复原厂动画
最简单的方法是在 KernelSU Next 中关闭或卸载模块,然后普通重启。
也可以手动禁用:
su
touch /data/adb/modules/cyberpunk_dual_animation/disable
reboot
重新启用:
su
rm -f /data/adb/modules/cyberpunk_dual_animation/disable
reboot
因为原厂文件从未被真正改写,模块不再挂载后,系统自然会重新读取原厂动画。
总结
这次适配表面上只是“换开关机动画”,实际涉及了:
- 确认 ColorOS 的真实动画路径
- 处理 EROFS 只读分区
- 使用 bind mount 做 systemless 替换
- 处理权限与 SELinux 标签
- 区分普通重启、终端重启和软重启
- 使用 One-Shot 模块做安全测试和自动回退
- 为三套动画分别验证开机与关机效果
- 打包持久化模块并发布 Release
- 处理 GitHub README、预览 GIF 和双语说明
最终的方案并没有直接修改系统分区,也不需要永久覆盖原厂动画文件。关闭模块并重启,一切就会恢复原样。
对我来说,这也是 systemless 模块最有意思的地方:不是强行把系统文件改掉,而是在合适的启动阶段,让系统临时看到我们希望它看到的内容。
来源与致谢
动画素材和预览 GIF 来自:
原仓库向原始模块作者 天伞桜 & PanL 致谢。
本文中的一加 Ace 3 Pro 路径适配、KernelSU 模块封装、bind mount 逻辑、权限与 SELinux 处理,以及三个版本的实机测试由 akizukishiro 完成。
Cyberpunk 2077 及相关名称和素材归各自权利方所有。本文与项目均为非商业社区分享,与 OnePlus、OPPO 或 CD PROJEKT RED 不存在官方关联。
风险提示
Root 模块始终存在风险。安装前请备份重要数据,了解 KernelSU 或其他 Root 管理器的安全模式,不要同时启用多个替换相同动画路径的模块。
本文中的显示恢复参数只适用于测试使用的一加 Ace 3 Pro,请勿在其他设备上直接照搬。






