我把一台 2018 年的「钉钉专用」投影仪,改成了家庭影音中心(没有 root)

摘要:一台被钉钉会议系统和阿里 YunOS 双重锁死的老投影仪,默认只能开会投屏。本文记录如何在不 root、不刷机的前提下,用 ADB + 自写遥控 App + 当贝桌面,把它从「会议砖」改造成可遥控、可装 App、可当数字相框的家庭设备;以及中途一段让手机扮演蓝牙遥控器的、踩遍 Android 隐藏 API 的史诗级翻车。


一、缘起:一台被「钉钉化」的老投影

手头有一台 大眼橙 V1(内部代号 DingProjector_A2),2018 年的机器,原本是给钉钉会议室做「Focus 投屏」配套的。

买来之后发现:开机直接进钉钉桌面,没有应用商店入口,没有文件管理,遥控器按键被钉钉抢走一大半。本质上——它被钉钉 + 阿里 YunOS 双重锁死,成了一块「只能开会」的砖

但我记得它里面是一颗 Amlogic S905 芯片,性能放今天当个本地影音盒绰绰有余。于是目标很明确:

在不拆机、不刷机、不 root 的前提下,尽可能把它改造成一个「能遥控、能装 App、能投屏、能当数字相框」的家庭设备。


二、设备体检:用 ADB 给老机器做全身 CT

投影开着 ADB 调试(TCP 5555),在屏幕点一下「允许」就拿到 shell。

一眼看清它的底细:

  • SoC:Amlogic S905(GXL 平台),ARMv7 32 位
  • 系统:Android 5.1(SDK 22)+ 阿里 YunOS TV 外壳
  • 内核:3.14.29(2018 年编译)
  • 默认桌面com.alibaba.dingtalk.focus(钉钉 Focus)
  • 屏幕:1280×720 / 160dpi
  • 权限ro.debuggable=0adb root 直接被拒,SELinux Enforcing,/system 只读 —— 无 root 实锤

端口普查更有意思:除了 ADB 的 5555,还有一堆钉钉私有端口(7100/11222/12345/52288),以及一组 uid 0 的 root 守护进程(9751/3988/3999)。其中 9751 是 autofocus_server——一个对焦马达服务,帧结构是 [40 字节头] + [1 字节 JSON 长度] + [JSON],理论上能远程触发自动对焦。再往深看,设备还有出向 MQTT 连到阿里云 IoT——这台投影一直是能被云端远程控制的

结论很乐观:虽然没有 root,但 shell 能用、input 能模拟按键、/data/local/tmp 可写、能 adb install 侧载 APK。能玩的空间比想象中大得多。


三、无 root,到底能玩什么

很快就把基础能力跑通了:

  1. PC 遥控:写了个 remote.py,用 input keyevent / am start 在电脑上遥控投影——方向键、主页、音量、启动指定 App 全没问题。设备上一共能拉起 53 个 Activity,包括数字相框、媒体播放器、梯形校正、亮度调节等。
  2. 数字相框am start 直接拉起 YunOS 自带的 PhotoPlayerActivity 显示图片,做成「开机即相框」一键命令。
  3. 侧载 App:装了当贝桌面、当贝市场、当贝文件管理器、Kodi、B站 TV 版。老 Android 5.1 兼容性意外地好。
  4. 无线镜像scrcpy 连上去,PC 实时看到投影画面并鼠标操控(注意 Android 5.1 没有音频捕获,要加 --no-audio;中文输入法注入不支持 CJK,得走设备端输入法)。

投屏的真相值得一提,避免后来人踩坑:

  • 钉钉投屏码可用:手机钉钉输码 DJ1JK 直接投,这是最稳的官方通道。
  • 乐播云已死:这台 8 年老设备在乐播云端的注册早已过期,登录二维码、投屏码全部「加载失败」,用户侧无解。
  • iPhone AirPlay / 安卓 Miracast 搜不到:厂商把 mDNS/Bonjour 发现关掉了(mdnsEnable=0),乐播也不支持 Miracast。即使用户端能建 Lelink 会话,老 Amlogic 硬解现代手机实时流也不兼容,画面出不来。

所以最终投屏就两条实在的路:钉钉码scrcpy 无线镜像


四、开机自启:和「默认桌面」较劲

装了当贝桌面后,问题来了:按 HOME 永远回钉钉,因为系统把钉钉固化成了默认 HOME,而无 root 改不了这件事(pm disable 系统组件会 SecurityException,pm clear 清完重启又恢复)。

折腾一圈后,最稳的免 root 方案是 AutoStart(一个不需要 root 的开机自启 App):配置它开机延迟 60 秒、自动拉起当贝桌面。实测重启后:

钉钉桌面(~1 分钟)→ AutoStart 到点拉起当贝 → 当贝稳定接管前台。

借人、带出门、只有手机的场景全部零操作可用。

顺带还解了两个「老设备综合症」:

  • 电池是假的:BMS 显示 4166mAh / 97% 零衰减,但实测拔电即整机断电——2018 年的电芯深度放电后已锁死,带不动投影灯珠负载。结论:当固定 AC 投影用,电池只是个好看的读数。
  • RTC 失忆:硬件时钟永远停在 2015-01-01。无 root 改不了硬件时钟,但开了 auto_time 后每次开机联网自动校时,系统时间就正常了。

五、高光时刻:自己写一个 ADB 客户端,干翻 YunOS 的魔改认证

为了能用手机直接遥控投影(而不是每次开电脑),我做了个安卓遥控 App。难点是:App 要自己在 WiFi 上扮演 ADB 客户端连投影,而不能 exec 原生 adb 二进制(现代 Android SELinux 禁止)。

于是用了纯 JVM 的 ADB 协议实现(cgutman 的 adb-java),并把 PC 的 adbkey 打包进 App——因为投影的 /data/misc/adb/adb_keys 白名单里已经有这把公钥,手机复用同一把私钥就能免二次授权直连。

真机一跑,翻车了:标准 ADB 的 AUTH_SIGNATURE 握手被 YunOS 的魔改 adbd 全部拒绝(SHA1/MD5/SHA256/裸 RSA 都试过)。

继续刨,发现三个老设备专属的坑:

  1. 校验和是字节求和,不是 CRC32——2018 年老 adbd 用 sum,错一个字节直接断连。
  2. 消息常量是小端 ASCIIAUTH=0x48545541 这种,写反端序 mock 能过、真机必挂。
  3. 真相:这台 adbd 不收签名,但收到合法的 AUTH_RSAPUBKEY直接回 CNXN 放行,无需签名。而 RSAPUBKEY 的载荷是原始 272 字节 RSAPublicKey 结构体(含 n0inv 牛顿迭代、rr=2^2048 mod n 计算),不是 base64。

把认证流改成「发原始公钥结构体 → 直接连」,真机全通:连上、读 getprop、发 input keyevent 全部成功。等于自己实现了一遍 ADB 协议,还逆向出了 YunOS 对认证的特殊处理。


六、史诗级翻车:让手机当蓝牙遥控,踩遍 Android 隐藏 API

接下来想更进一步——不依赖 USB 调试,让手机像实体遥控一样直接控投影。

先拆解实体遥控:用 getevent -l 抓包,发现事件来自 bus: 0005(蓝牙),scan code 全是 0x0700xx(HID Keyboard 用法页)。原来这遥控是个蓝牙 HID 键盘,不是红外(系统里那份 NEC 红外码表其实是休眠配置,对 V1 无效)。

于是方向变成:让手机扮演 BluetoothHidDevice(蓝牙 HID 键盘),配对投影后发标准键盘报告。键码表我都抓全了(上/下/左/右/OK/主页/返回/菜单/音量/对焦/电源)。

然后是从 build36 一路翻车到 build45 的、关于 Android 隐藏 API 的连续暴击:

  1. SDP 构造器签名被定制:小米 HyperOS 上 BluetoothHidDeviceAppSdpSettings 的构造器末参是byte[16](UUID 二进制),不是标准 AOSP 的 ParcelUuid[]。硬编码标准签名直接 NoSuchMethodException
  2. Callback 是 abstract class,不是 interface:JDK 动态代理只支持接口,碰上抽象类必报 not an interface
  3. ART 只认 DEX,不认 JVM class:改用 ASM 字节码生成子类,结果 can't load this type of class file——Android 运行时根本不加载 .class,必须生成真正的 DEX。
  4. 换 dexmaker 运行时生成 DEX 子类:这回过了编译,又卡在 NoSuchMethodException: (dexmaker 不自动生成构造器)、返回类型不匹配、android.os.Executor 类名拼写错、Manifest 给权限加了 maxSdkVersion=32 导致高版本系统看不见权限……
  5. 终于走到注册:权限弹窗都点了,却卡在「正在注册 HID 键盘…」6 秒超时,永远收不到系统回调。

最后在小米 + 华为两台不同品牌手机上复现了完全相同的症状,且回显的回调签名都是 AOSP 标准——说明不是某家厂商砍了,而是国产手机蓝牙栈普遍没实现 HID Device 这个服务端角色getProfileProxy 拿到的 proxy 有效,但底层协议栈从不真正注册)。

实体遥控能用,是因为 V1 端是 HID Host;手机端是 HID Device,而这条路在国产 ROM 上被普遍砍掉了。

这条路线被判死。我清掉所有蓝牙代码,回退到纯 ADB 遥控,出了 build46(1.0.0-adb),8.36MB,覆盖安装即用。

(这段经历单独看比主项目还精彩:从一个错误假设出发,连过 SDP、Proxy、DEX 生成、Manifest 四道隐藏 API 关卡,最后撞上一道硬件级天花板。)


七、关于 root:能,但要拆机焊线

期间也认真评估过 root。结论很现实:

  • A. boot.img 重签注入 su —— 死。YunOS 锁了 bootloader,reboot bootloader / fastboot 全被拦截。
  • B. Dirty COW —— 死。YunOS 加固剥掉了所有 setuid 位,没有可提权的执行载体。
  • C. MaskRom 硬件线读 eMMC —— 唯一可行。拆机短接 eMMC 的 CLK-GND 进 MaskRom 模式,用 Amlogic USB Burning Tool 读全片备份、改镜像、写回。

但有个红线:全网搜不到 V1 的原厂固件(大眼橙官方 OSS 只托管 2021 年后的新型号)。也就是说,本机 eMMC 的备份是唯一的救砖底牌,在拿到备份前绝不能刷任何东西。

权衡之后,用户选择暂不拆机,保留无 root 现状。C 方案存档待用。


八、现在它能做什么(避坑清单)

最终形态,无 root、零拆机

  • ✅ 开机自动进当贝家庭桌面(AutoStart 60s 延迟拉起)
  • ✅ 手机遥控 App(ADB 直连,免授权)
  • ✅ PC 遥控脚本 + scrcpy 无线镜像
  • ✅ 钉钉投屏码投屏
  • ✅ Kodi / B站TV / 数字相框 / 当贝市场装 App
  • ❌ 远程真正关机(只有待机键有效,无法远程唤醒)
  • ❌ 改默认桌面 / 改 DNS(无 root 动不了)

给后来人的几条硬经验:

  1. 老设备先 adb shell 摸一遍 getprop / 端口 / 能拉起的 Activity,比盲改高效十倍。
  2. YunOS 老 adbd 的 ADB 认证是魔改的:不收签名、只认原始 RSAPUBKEY 结构体,校验和是字节求和。自己写客户端时别按标准 AOSP 来。
  3. 想让手机当蓝牙遥控?先确认手机 ROM 实现了 HID Device 角色——国产定制系统(小米/华为/OPPO 等)大多没有,别像我一样从 build36 翻到 build45。
  4. 无 root 改不了默认桌面:用开机自启类 App(AutoStart 之类)兜底,比死磕 HOME 现实。
  5. 老设备云端服务基本已死(乐播、当贝云都靠老 API),本地功能优先,别赌联网能力。
  6. 电池读数和实际往往两码事:BMS 好看 ≠ 电芯能带载,拔电测试最实在。

九、写在最后

这台 8 年前的「会议砖」,最后没 root、没刷机,靠 ADB + 自写客户端 + 当贝桌面,活成了家庭影音盒。最有价值的不是某个具体命令,而是那个反复验证过的认知:

一台被锁死的设备,真正的大门往往在 ADB 和协议层,而不在 root。

至于那段蓝牙 HID 的翻车——它没让投影更好用,但让我把 Android 蓝牙隐藏 API 的坑踩了个遍。哪天换台原生系统的手机,也许还能把这半截轮子装上。


(本文已对设备局域网 IP、主机名、MAC 地址、用户名等敏感信息做脱敏处理。)