前言
我的电视系统是MiTV 2.10.3982,设备型号:L75MA-AC,Android9,这个 root 教程算是全网首发?至少我在相关论坛没有看到我这种 root 教程,理论上版本号差不多本教程差不多通用的。下面教程不涉及到 Magisk 补丁 root,第三方 recovery 刷入等教程,并且我使用的是 macOS 环境,不提供其他系统详情教学,可以根据文章实际情况来变动。
本教程配合我写的脚本通过 UART/CP2102 → U-Boot/Recovery → 部署 Magisk 启动链实现的持久 root。
1. 准备
下载我的附件,然后新建 xiaomi 文件夹将附件里面内容解压进去,不要根解压。
使用 CP2102 UART 连接电视:这边参考论坛教程:
2022新款小米电视(安卓6以上)硬核root教程(需要USB转TTL)
小米电视硬核root教程(需要USB转TTL硬件工具)
电脑设置终端环境变量:
# 小米电视ip地址
export TV=192.168.50.202:5555
# 工作目录地址
export XIAOMI=/Users/jaxson/Downloads/xiaomi
# 附件地址,放在工作目录地址里面
export ROOT_BUNDLE=$XIAOMI/final-root-bundle
# magisk 安装包
export MAGISK_APK=$ROOT_BUNDLE/apps/Magisk-v27.0.apk
CP2102:921600 baud / 8N1 / 无流控。
| HDMI 1 | CP2102 |
|---|---|
| 14 | +5V |
| 15 | TXD |
| 16 | RXD |
| 20 / 屏蔽地 | GND |
2. 核对设备
打开终端输入:
adb connect "$TV"
adb -s "$TV" shell '
getprop ro.product.model
getprop ro.product.device
getprop ro.build.version.release
getprop ro.build.version.sdk
getenforce
'
必须得到:
MiTV-ASTP0
mulan
9
28
Enforcing
3. 进入 Recovery Root
启动 UART,注意在 window 使用 putty 的话,设置波特921600,新开一个终端A,输入:
mkdir -p "$XIAOMI/logs"
"$ROOT_BUNDLE/tools/uart921600" \
/dev/cu.usbserial-0001 \
921600 \
"$XIAOMI/logs/mulan-root-install.raw.log"
另一个终端 B 重启电视:
adb -s "$TV" reboot
U-Boot 出现时按回车。看到 mulan# 后逐条执行:
factorydata read console_enable
factorydata write console_enable 1
factorydata read console_enable
setenv reboot_mode update
printenv reboot_mode
run switch_bootmode
不要执行 saveenv。
Recovery 中确认:
grep -E '^(Uid|Gid|CapEff|Seccomp):' /proc/self/status
cat /sys/fs/selinux/enforce
必须是 UID 0,SELinux 输出 0。
4. 完整分区备份
Recovery:
B=/sbin/busybox
$B mount /dev/block/data /data
D=/data/local/tmp/mulan-full-backup
$B mkdir -p "$D"
$B umount /cache
f(){ $B dd if=/dev/block/$1 of=$D/$1.img bs=1M; }
逐条执行:
f bootloader
f reserved
f cache
f env
f logo
f recovery
f misc
f dtbo
f cri_data
f param
f boot
f rsv
f metadata
f vbmeta
f tee
f secure_recovery
f factorydata
f vendor
f odm
f system
f product
$B dd if=/dev/block/mmcblk0boot0 of=$D/mmcblk0boot0.img bs=1M
$B dd if=/dev/block/mmcblk0boot1 of=$D/mmcblk0boot1.img bs=1M
$B dd if=/dev/block/mtdblock0 of=$D/mtdblock0.img bs=1M
$B dd if=/dev/block/mmcblk0 of=$D/emmc-before-data.img bs=1M count=3184
$B chown -R 2000:2000 "$D"
$B chmod 700 "$D"
$B chmod 600 "$D"/*
$B sync
$B reboot
Android 启动后重新开启 ADB,把备份拉到 Mac,并复制一份到其他存储:
mkdir -p "$XIAOMI/backups/mulan-full-backup"
adb connect "$TV"
adb -s "$TV" pull \
/data/local/tmp/mulan-full-backup/. \
"$XIAOMI/backups/mulan-full-backup/"
5. 安装 Stage-B
确认远端安装目录不存在,然后推送:
adb -s "$TV" shell 'test ! -e /data/local/tmp/mulan-stage-b-install-20260719'
adb -s "$TV" push \
"$ROOT_BUNDLE/stage-b" \
/data/local/tmp/mulan-stage-b-install-20260719
adb -s "$TV" shell '
cd /data/local/tmp/mulan-stage-b-install-20260719
chmod 0700 install-recovery.sh rollback-recovery.sh payload/busybox
'
adb -s "$TV" reboot recovery
Recovery:
B=/sbin/busybox
$B mount /dev/block/data /data
/sbin/sh /data/local/tmp/mulan-stage-b-install-20260719/install-recovery.sh
必须看到:
[mulan-stage-b-install] INSTALL_SUCCESS
成功后:
$B sync
$B reboot
等待 Android 和 ADB 恢复:
adb connect "$TV"
adb -s "$TV" shell '
/sbin/magisk -v
/sbin/magisk su -c "id"
/sbin/magisk su -c "cat /data/adb/magisk/bootstrap.rc"
cat /data/local/tmp/mulan-adb-persist.log
'
必须是 Magisk 27.0、uid=0、bootstrap.rc=0,ADB 日志包含 SERVICE_SUCCESS。
6. 启用内置 Zygisk
Stage-C Final 安装前,先写入 Magisk 的内置 Zygisk 设置:
adb -s "$TV" shell
/sbin/magisk su
/sbin/magisk --sqlite "INSERT OR REPLACE INTO settings (key,value) VALUES ('zygisk',1);"
/sbin/magisk --sqlite 'SELECT key,value FROM settings WHERE key="zygisk";'
exit
exit
输出必须包含:
key=zygisk|value=1
7. 安装 Stage-C Final
正常 Android:
adb -s "$TV" shell 'test ! -e /data/local/tmp/mulan-stage-c-final'
adb -s "$TV" push \
"$ROOT_BUNDLE/stage-c-final" \
/data/local/tmp/mulan-stage-c-final
adb -s "$TV" shell '
cd /data/local/tmp/mulan-stage-c-final
chmod 0700 *.sh payload/busybox
/sbin/magisk su -c "./prepare-android.sh"
'
必须看到:
[mulan-stage-c-final-prepare] PREPARE_SUCCESS
进入 Recovery:
adb -s "$TV" reboot recovery
Recovery:
B=/sbin/busybox
$B mount /dev/block/data /data
/sbin/sh /data/local/tmp/mulan-stage-c-final/install-recovery.sh
必须看到:
[mulan-stage-c-final-install] INSTALL_SUCCESS
出现 FAILED 时不要重启。成功后:
$B sync
$B reboot
8. 最终验证
等待约 90 秒,不要手动重新开启电视设置中的 ADB:
adb connect "$TV"
adb -s "$TV" shell '
getprop sys.boot_completed
getenforce
/sbin/magisk -v
/sbin/magisk su -c "id"
/sbin/magisk su -c "cat /data/adb/magisk/stage-c-early.rc"
/sbin/magisk su -c "cat /data/adb/magisk/stage-c-service.rc"
/sbin/magisk su -c "grep STAGE_C_LATE_SUCCESS /data/adb/magisk/bootstrap.log"
/sbin/magisk su -c "cat /data/adb/magisk/stage-c-zygisk-mode"
cat /data/local/tmp/mulan-adb-persist.log
'
必须满足:
sys.boot_completed=1
SELinux=Enforcing
uid=0
stage-c-early.rc=0
stage-c-service.rc=0
STAGE_C_LATE_SUCCESS
Zygisk mode=builtin
ADB 日志包含 STABILIZATION_SUCCESS 和 SERVICE_SUCCESS
检查 Zygisk:
adb -s "$TV" shell "/sbin/magisk su -c '
P=\$(pidof zygote | awk \"{print \\$1}\")
grep libzygisk.so /proc/\$P/maps
'"
必须看到 /system/lib/libzygisk.so。再正常重启一次并重复本节。
9. Magisk App 和模块
adb -s "$TV" install -r "$MAGISK_APK"
不要点击“修复运行环境”、Direct Install、核心更新或卸载。
模块必须兼容 Android 9、Magisk 27 和 32 位 zygote。安装模块后正常重启。
LSPosed 1.9.2 (7024) - Zygisk 已验证。
10. 给应用授予 Root 权限
目前 magisk app 在小米电视系统无法正常弹窗授权,直到超时提示拒绝授权,这时候可以用下面 UID 授权:
1. 查应用 UID
把包名替换成目标应用:
export TV=192.168.50.202:5555
adb -s "$TV" shell
pm list packages -U | grep 'package:com.example.app '
示例输出:
package:com.example.app uid:10075
记下 UID。不要直接给 uid:1000 等共享系统 UID 授权,否则同一 UID 下的其他系统组件也会获得 Root。
2. 永久允许
先确认 Magisk daemon 正常:
pidof magiskd
/sbin/magisk su -c id
然后进入 Root shell,把 10075 换成实际 UID:
/sbin/magisk su
APP_UID=10075
/sbin/magisk --sqlite "INSERT OR REPLACE INTO policies (uid,policy,until,logging,notification) VALUES ($APP_UID,2,0,1,0);"
/sbin/magisk --sqlite "SELECT uid,policy,until,logging,notification FROM policies WHERE uid=$APP_UID;"
exit
exit
正确结果包含:
uid=10075
policy=2
until=0
含义:
policy=2 允许
until=0 永不过期
logging=1 记录新的 su 请求
notification=0 不显示授权通知
这会覆盖该 UID 原有的拒绝记录,不再依赖电视上无法操作的 Magisk 弹窗。
3. 重新启动应用
adb -s "$TV" shell 'am force-stop com.example.app'
重新打开应用,再执行它的 Root 功能。
Magisk 日志中的旧“拒绝”不会自动消失,应以新的请求时间和 policies 查询结果为准。
4. 查看全部授权
/sbin/magisk su -c '/sbin/magisk --sqlite "SELECT uid,policy,until,logging,notification FROM policies ORDER BY uid;"'
5. 撤销授权
/sbin/magisk su
APP_UID=10075
/sbin/magisk --sqlite "DELETE FROM policies WHERE uid=$APP_UID;"
/sbin/magisk --sqlite "SELECT uid,policy FROM policies WHERE uid=$APP_UID;"
exit
exit
查询无结果表示已撤销。
6. 常见问题
No daemon is currently running!
这不是 App 授权问题,而是 magiskd 没有运行。先正常重启电视,确认以下命令成功后再授权:
pidof magiskd
/sbin/magisk su -c id
已写入 policy=2,应用仍提示没有 Root
依次检查:
- 包名对应的 UID 是否正确;
- 应用是否在授权后被完全停止并重新打开;
- 应用是否使用了其他进程或不同 UID;
pidof magiskd是否有输出;/sbin/magisk su -c id是否仍返回uid=0。
不要通过 Magisk App 的“修复运行环境”或 Direct Install 处理授权弹窗问题。
11. 细节讨论
1. 结论
TvService 和 Magisk 是两条独立的 Root 链路:
TvService是小米厂商诊断服务提供的一次性 Root 脚本执行入口;- Magisk 是开机自动建立、支持
su授权、Zygisk 和模块的持久 Root 框架; - 当前
Stage-B → Stage-C Final方案使用 UART/Recovery Root 安装 Magisk,不依赖TvService; - Magisk 正常启动后,日常获取 Root 不需要再次调用
TvService。
2. TvService 临时 Root
小米电视里面的服务名 TvService 作为突破口,这个服务名把一个脚本路径交给高权限服务,由 uid=0 的 misysdiagnose SELinux 域执行:
service call TvService 4400 s16 s s16 /sdcard/Download/script.sh
执行链:
ADB shell
uid=2000(shell)
SELinux=u:r:shell:s0
│
│ Binder transaction 4400
▼
Xiaomi TvService
│
│ 将脚本路径交给厂商诊断执行组件
▼
misysdiagnose 执行脚本
uid=0(root)
SELinux=u:r:misysdiagnose:s0
提权发生在 Binder 服务端,不是把当前 ADB shell 进程改成 UID 0。脚本结束后,这次 Root 执行也随之结束。
u:r:misysdiagnose:s0 仍受 SELinux Enforcing 限制。UID 0 不代表一定可以 remount 分区、写入 /vendor、/odm、boot 或 vbmeta。
3. Magisk 持久 Root
Magisk 的执行链是:
Android init
→ 执行植入的启动 Hook
→ bootstrap.sh 建立 /sbin Magisk runtime
→ 启动 magiskd
→ magiskd 进入 u:r:magisk:s0
→ shell 或 App 通过 su 请求 Root
日常验证命令:
pidof magiskd
/sbin/magisk su -c id
正常结果应包含:
uid=0(root)
context=u:r:magisk:s0
Magisk App 只是管理界面。真正提供 Root 的是启动 Hook、/sbin/magisk、magiskd、SELinux 策略和 /data/adb/magisk.db。
4. 当前方案如何安装 Magisk
当前生产流程是:
UART
→ U-Boot
→ Recovery UID 0 + SELinux Permissive
→ 完整分区备份
→ 安装 Stage-B
→ 启动并验证 Magisk Root
→ 安装 Stage-C Final
→ 启用内置 Zygisk 和模块生命周期
Stage-B 在 Recovery 中完成:
- 将 Magisk 27 核心文件部署到
/data/adb/magisk; - 修改
/vendor/bin/init.post-fs-data.sh,让系统启动时执行bootstrap.sh; - 修改
/odm/etc/selinux/precompiled_sepolicy,允许启动 Hook 建立 Magisk 域; - 启动时建立
/sbinruntime,执行magisk --daemon; - 为 ADB shell UID 2000 写入 Magisk 允许策略。
Stage-C Final 再补齐:
post-fs-data、service、boot-complete生命周期;- Magisk 27 内置 Zygisk;
- Magisk 模块和模块
sepolicy.rule; - 32 位
magisk32、stub.apk和重启后 TCP ADB 5555。
因此,当前持久 Root 的来源是 Recovery 中安装的启动链,不是 TvService。
5. 两者的关系
| 项目 | TvService | Magisk |
|---|---|---|
| 入口 | Binder transaction 4400 | 启动 Hook 和 magiskd |
| Root 上下文 | u:r:misysdiagnose:s0 |
u:r:magisk:s0 |
| ADB shell 是否直接变成 Root | 否 | 通过 su 获取 |
| 重启后是否自动恢复 | 否 | 是 |
| App 授权 | 不支持 | 支持 |
| Zygisk/模块 | 不支持 | 支持 |
| 当前生产安装是否依赖 | 否 | 是 |
理论上可以尝试利用 TvService 临时 Root 部署持久化文件,但其 SELinux 域未验证具备完整的分区挂载和启动链写入权限,因此不能替代已经验证的 Recovery 安装流程。
6. Magisk 丢失时 TvService 能做什么
如果 magiskd 没有运行,TvService 仍可能独立提供临时 Root,因为它不依赖 Magisk。它适合读取以下诊断信息:
/data/adb/magisk/bootstrap.log
/data/adb/magisk/bootstrap.rc
/data/adb/magisk/stage-c-early.log
/data/adb/magisk/stage-c-early.rc
/data/adb/magisk/stage-c-service.log
/data/adb/magisk/stage-c-service.rc
不要直接用 TvService 执行 bootstrap.sh:脚本要求 u:r:run_post_fs_data:s0,而 TvService 脚本运行在 u:r:misysdiagnose:s0,上下文不匹配。
涉及 /init.rc、/vendor、/odm 或 SELinux 策略的恢复,应使用 Recovery 中保存的回滚脚本。
7. 不要混淆
安装 Magisk APK ≠ 获得 Root
TvService UID 0 ≠ Magisk su
TvService 临时 Root ≠ adb root
UID 0 ≠ 绕过 SELinux
Magisk Root 丢失 ≠ TvService 一定失效
本方案不是 Magisk 官方 boot.img patch 流程。不要在 Magisk App 中执行“修复运行环境”、Direct Install、核心更新或卸载,否则可能破坏当前自定义启动链。