我和 AI 一起修电视:索尼 CEC 失效排查实录
我和 AI 一起修电视:索尼 CEC 失效排查实录
TL;DR:电视的 HDMI-CEC 全链路瘫痪,根因是某根 HDMI 线把 CEC 总线(13 脚)拉死,导致电视开机时 CEC 初始化失败。而
mIsCecAvailable这个标志一旦为 false 就不会自愈,所以后续怎么重启、怎么改设置都没用。修复动作只有一个组合:拔光所有 HDMI 线 → 重启电视(不是待机)→ 插回设备。顺序不能反。
这篇文章除了讲技术,还想讲清楚一件事:这整个过程是我和一个 AI 智能体一来一回干完的。它负责敲命令、读 dumpsys、分析日志,我负责拔线、看画面、以及在关键时刻纠正它的误判。
〇、开场:我把 adb 交给了 AI
事情很简单:家里的 SONY XR-65X91J 接 Apple TV 4K,以前电视遥控器切到 HDMI3,Apple TV 自动亮,遥控器还能直接控制它。某天开始,这套流程全废了:
- 切到 HDMI3,Apple TV 没反应,屏幕黑着
- 电视遥控器按下去,Apple TV 毫无响应
- 得先摸出 Siri Remote 按一下,Apple TV 才醒
按以前的习惯,这种问题我会自己开终端,一条条 adb shell 试。但那天太晚了,我换了种干法——直接把电视的 adb 连接交给 WorkBuddy 里的智能体(小智),让它自己查。
我的开场白只有一句:
我:我的电视的 HDMI3 连接的是 Apple TV,分析一下为什么我将信号源切换到 HDMI3 的时候没有唤醒 Apple TV。
它回得也很干脆:
小智:我先连电视,把 HDMI-CEC 的实际配置和切换 HDMI3 时的日志抓出来,再下结论。
然后它就开始自己跑命令了。下面整个过程,都是真实发生的交互。
一、第一回合:AI 交上来的"体检报告"
它做的第一件事不是猜,是分层取证——先查 settings 三层,再查服务,再查 dumpsys 状态机,最后翻 logcat。
几分钟后它给出的核心结论只有一行:
mIsCecAvailable: false
再往下是设备表:
mDeviceInfos:
CEC: logical_address: 0x00 device_type: 0 ... display_name: TV
只有电视自己(地址 0x00),一个下游设备都没有。
以及报文历史:
CEC message history:
[S] time=2026-06-05 18:35:46 message=<Report Physical Address> 0F:84:00:00:00
[S] time=2026-06-05 18:35:48 message=<Device Vendor Id> 0F:87:08:00:46
[S] time=2026-06-05 18:35:54 message=<Active Source> 0F:82:00:00
...
12 条记录,全是 [S](Send),一条 [R](Receive)都没有。
它给我的解释是:
小智:CEC 是双向总线协议。一条
[R]都没有,意味着这块电视从来没有成功接收过任何 CEC 报文。这不是"Apple TV 没开某个开关"能解释的。
同时它发现 HAL 层在刷屏:
E/CEC_HAL: Tx notify NOT coming, Timeout return
W/HdmiCecController: Failed to send <Active Source> 0F:82:00:00 with errorCode=2
到这里,它给了一个初步判断,而且是错的:
小智:从首次开机起每条发送就都是
errorCode=2……这台电视的 CEC 可能一直就没工作过,只是你之前没用过这个功能。
二、第二回合:我的一句话,把方向掰回来了
它问了我一个关键问题:
小智:顺便问一句,你用 Apple TV 遥控器能开关电视或者调电视音量吗?如果完全没反应,基本就坐实是 CEC 整条链路的问题。
我的回答同时也否掉了它前面的推测:
我:能,以前用电视遥控器切换到 HDMI3,会唤醒 Apple TV,然后用电视遥控器也能够控制 Apple TV,现在不行了。
它立刻改了判断:
小智:这条信息很关键。既然以前能用,那说明这不是"出厂即坏",我收回"一直没工作"的判断。CEC 硬件是好的,现在处于卡死状态。
这是整个排查的转折点。
如果它继续沿着"硬件从来没工作过"推下去,结论会变成"主板故障,送修";而"曾经好过、现在坏了"这个前提,把方向引向了"后来发生了什么变化"——这才有了后面的隔离实验。
我后来复盘时觉得,这是人机协作里最值钱的部分:AI 能看到我看不到的数据,但它不知道我的生活史。有些信息只存在于人脑里,必须由人补给它。
三、第三回合:AI 自己设计并执行了五次"抢救"
确认是"后天失效"之后,它没有停在分析上,而是自己列了一串恢复手段,一条条试:
| # | 手段 | 命令 | 结果 |
|---|---|---|---|
| 1 | CEC 开关重置 | cmd hdmi_control cec_setting set hdmi_cec_enabled 0 → 1 | ❌ 无效 |
| 2 | ARC 通道重置 | cmd hdmi_control setarc off → on | ❌ 无效 |
| 3 | 重启 CEC HAL 进程 | kill -9 <pid> | ❌ Operation not permitted(无 root) |
| 4 | 端口抖动检测 | 10 秒 × 5 次采样 | ❌ 四口状态恒定,非接触不良 |
| 5 | 整机重启 | adb reboot | ❌ 无效 |
其中第 1 条实验,是它自己想到的,而且做得非常聪明:
23:52:19 setCecSettingIntValue hdmi_cec_enabled = 0 ← CEC 已关闭
23:52:20 E/CEC_HAL: Tx notify NOT coming, Timeout ← 照样超时
23:52:22 E/CEC_HAL: Tx notify NOT coming, Timeout ← 照样超时
23:52:24 setCecSettingIntValue hdmi_cec_enabled = 1 ← 再打开
23:52:26 E/CEC_HAL: Tx notify NOT coming, Timeout ← 还是超时
它的解读是:
小智:CEC 在软件层都关掉了,驱动层还在每 2 秒报一次发送超时。这一条就够了——问题与 Android 的 CEC 状态机无关,与 BRAVIA Sync 的设置无关,是驱动/物理层的持续故障。
这是全篇最有说服力的一段证据。 我自己想不到这么试,一般人的思路是"打开看看",而它是"关掉看看——如果关了还在报错,说明报错的根本不是这一层"。
四、第四回合:它给不了手,于是给我造了把工具
到这一步它已经很明确了:问题在物理层,而物理层它碰不到。
小智:软件层能试的全试完了,四条路全堵死。剩下的必须动手了。我做了个实时监控,让你拔线的瞬间就能看到结果。
然后它写了两个脚本扔进项目目录:
./cec_live.sh # 实时监控,每 2 秒一行
./cec_probe.sh 10 # 单次采样,输出完整体检报告
cec_live.sh 的输出长这样:
23:58:19 -- [重连中]
23:58:22 1 [总线异常]
23:58:24 1 [总线异常]
它的原理很简单——把 Tx notify NOT coming 的出现频率当成 CEC 总线的健康度指标。正常应该是 0 次,每当 2 秒出现 1 次,就说明有东西在拉着总线。
这个设计让我不用反复跑命令、翻日志,只要看着屏幕拔线就行。 这是我觉得 AI 在这类任务里最实用的能力:它能把"你去做物理动作,我盯着数据"这种配合变成现实。
五、第五回合:我拔线,它看数据
我按它说的,把四根 HDMI 线全拔了,然后截了张监控图发过去。
00:01:02 [总线异常]
...
00:02:12 [总线异常]
00:02:14 [总线正常] ← 从这里开始,一次超时都没有了
...
00:03:01 [总线正常]
它的反应:
小智:这个结果很关键,四根线全拔掉后 TX 超时在同一瞬归零了。说明电视的 CEC 控制器本身没坏,问题出在外部。
它还注意到一个我没在意的细节:
小智:注意那个 70 秒的延迟——拔线之后不是立刻恢复,而是过了一分多钟才彻底安静。说明 CEC 控制器需要重新检测 HPD 状态、重新初始化才能脱离异常态。
这句话后来成了修复方案的关键。
六、第六回合:为什么之前那次重启没用
在等我的过程中,它自己去重启了一次电视(adb reboot),然后查状态——还是坏的。
它当时的解释:
小智:
mIsCecAvailable是开机时一次性判定的,一旦变成 false 就不会自愈,只有重启才能重新初始化。之前那次重启时,线还插着、总线还是坏的,所以重启后照样失败。必须先拔线、再重启,顺序反了就是白折腾。
这个因果链一说通,整件事就闭环了:
某根线把 CEC 总线拉死
↓
电视开机时 CEC 初始化失败 → mIsCecAvailable = false
↓
这个标志不会自愈,只有重启有机会翻盘
↓
重启的那一刻如果总线还是坏的 → 依然失败
↓
所以必须:先拔线制造干净环境,再重启
它甚至主动承认了这个顺序问题:
小智:这也是我一开始没让你先拔线就重启的原因——当时我还没排除"是电视本身坏了"。
七、第七回合:验证
四根线全拔 + 重启之后,我按它的要求,只插回 Apple TV 那一根。
它一查,电视立刻识别到了:
mDeviceInfos:
CEC: logical_address: 0x04 device_type: 4 cec_version: 5
vendor_id: 4346 display_name: Apple TV
physical_address: 0x3000 port_id: 3
logical_address 0x04→ Playback Device 1vendor_id 4346(0x10FA)→ Apple Inc.physical_address 0x3000→ HDMI3
它自己的评价是:
小智:
vendor_id 4346、physical_address 0x3000、device_type 4——它是一个完整、合法的 CEC 设备,被电视正常纳管了。
然后它直接发了个 intent 切到 HDMI3,抓下了修复后的完整握手:
00:08:55 [S] <Give Device Power Status> 04:8F ← 问 Apple TV 状态
00:08:55 [R] <Report Power Status> 40:90:00 ← 答:我开着
00:08:56 [S] <Set Stream Path> 0F:86:30:00 ← ★ 关键报文,之前根本发不出去
00:08:56 [R] <Image View On> 40:04 ← Apple TV:收到,醒了
00:08:56 [R] <Active Source> 4F:82:30:00 ← Apple TV:我接管画面
mActiveSource: (0x04, 0x3000) ← Apple TV 是当前活跃源
mActiveRoutingPath: 0x3000 ← 路由锁定 HDMI3
一步不缺,教科书级的 One Touch Play。
八、被忽略的技术细节:Routing Change 和 Set Stream Path 不是一回事
报告里有一段我觉得最值得单独拎出来的分析——为什么设备表为空的时候,切信号源更不容易唤醒设备。
它抓到了故障期间切 HDMI3 的轨迹:
23:43:52.995 TIS_HdmiControlHelper: portSelect() id: 3
23:43:53.006 HdmiControlService: portSelect: portId: 3
23:43:54.001 addAndStartAction RoutingControlAction
23:43:54 [S]: <Routing Change> 0F:80:00:00:30:00 ← 只发了这一条
23:43:56.003 removeAction: RoutingControlAction ← 2 秒后放弃
两条报文的区别是致命的:
| 报文 | Opcode | 语义 | 能唤醒设备吗 |
|---|---|---|---|
<Routing Change> | 0x80 | “我的路由要变了,通知你们一声” | ❌ 只是告知 |
<Set Stream Path> | 0x86 | “我要显示 3.0.0.0 的画面” | ✅ One Touch Play 的触发点 |
原因在 HdmiControlService 的逻辑:目标地址上的设备已知就发 <Set Stream Path> 精准投递,未知就只能广播 <Routing Change> 让设备自己宣告。
而故障期间设备表本来就是空的。所以形成了双重故障:
- CEC 物理层发不出报文
- 即使发得出,发的也是"通知"而不是"唤醒指令"
这一点在中文资料里几乎查不到,是它逐行对比修复前后的日志才发现的。
九、复盘:人机怎么分工才高效
这件事做完,我认真想了想这种协作的边界在哪。
AI 做得好、人做不了的部分
| 能力 | 具体表现 |
|---|---|
| 批量取证 | 十几分钟内跑了上百条 adb 命令,翻了 setting/secure/global 三层、包列表、dumpsys、logcat 全量 |
| 交叉验证 | 从"设备表为空"和"零条 [R]"两个独立证据推出同一个结论 |
| 反向实验设计 | 主动把 CEC 关掉,用"关了还报错"来证明问题不在这一层 |
| 自己造工具 | 发现需要人配合做物理动作,当场写了监控脚本 |
| 不漏细节 | 从一堆日志里挑出 70 秒延迟、errorCode=2、mConfigs 变空这些线索 |
| 不嫌烦 | 凌晨一点,反复采样、反复对比,没有"差不多就这样吧" |
只有人能做的部分
| 能力 | 为什么 AI 不行 |
|---|---|
| 拔线 / 插线 | 物理世界没有 API |
| 补充生活史 | "以前能用"这句话决定了整个排查方向,AI 无从得知 |
| 质疑结论 | 它说"可能一直没工作过",我一句"以前能用"就把它掰回来了 |
| 看画面 | “切过去了但黑屏"和"切过去了有画面”,只能人眼判断 |
| 量电压 | 万用表是它碰不到的东西 |
AI 在这件事里犯的两个错
写出来才有参考价值:
- 过早下结论:看到"首次开机就失败",就推断"从没工作过"。它缺的是时间维度的信息(用户的使用史),这个必须人补。
- 顺序搞错:先提议重启、后提出拔线。虽然它后来自己纠正了(“必须先拔线再重启”),但这个顺序问题导致了中间一次无效尝试,白等了 45 秒。
规律是:AI 在"信息完备的确定性推理"上极强,在"信息缺失时该不该下结论"上容易冒进。
十、技术总结:三条能省下几小时的经验
1. mIsCecAvailable 不会自愈
这个字段在 HdmiControlService 初始化时一次性判定,一旦为 false,后续无论开关 CEC、改设置、切输入都不会翻回来。唯一出路是重新初始化,也就是重启。
看到 mIsCecAvailable: false,别浪费时间调设置。
2. 必须"先拔线,再重启"
顺序反了等于白做。开着机的设备状态是"坏的快照",重启会把这个快照固化下来。
推广一下:任何"开机自检 + 状态锁死"型故障,都要先制造干净环境再重启。
3. cable_connection_status 字段不可信
排查中一度被它误导:明明线拔了,还是显示 cable_connection_status=1(已连接)。
可靠的判断依据是 mConfigs 数组:
mConfigs: [] ← 没信号
mConfigs: [TvStreamConfig {mStreamId=0;...}] ← 有信号
前者是缓存值,只在特定事件刷新;后者反映真实的流配置状态。
十一、附:排查命令速查
# 1. CEC 总体状态(先看这个)
adb shell dumpsys hdmi_control | head -5
# 2. CEC 设备表(有没有识别到下游设备)
adb shell dumpsys hdmi_control | sed -n '/mDeviceInfos:/,/mCecController/p'
# 3. 报文历史([S] 发送 / [R] 接收,重点看有没有 [R])
adb shell dumpsys hdmi_control | sed -n '/CEC message history/,/mCec/p'
# 4. 发送失败日志
adb shell logcat -d | grep "Failed to send"
# 5. 物理层超时(CEC 总线健康度核心指标)
adb shell logcat -d | grep -c "Tx notify NOT coming"
# 6. HDMI 端口真实状态(看 mConfigs,别看 cable_connection_status)
adb shell dumpsys tv_input | grep TvInputHardwareInfo | grep hdmi
# 7. 切换输入时抓 CEC 报文
adb shell logcat -c
# ...在电视上切到目标输入...
adb shell logcat -d | grep -E "HdmiCecController|portSelect"
健康基线:
| 指标 | 正常值 | 故障值 |
|---|---|---|
Tx notify NOT coming | 0 次/分钟 | 每 2 秒 1 次 |
Failed to send | 0 | 每条报文都失败 |
[R] 接收记录 | 有 | 零 |
mDeviceInfos | 含下游设备 | 只有 TV 自己 |
mIsCecAvailable | true | false(需重启恢复) |
十二、后记
这次真正花时间的不是找答案,而是证伪——把"Apple TV 设置问题"“固件 bug”"主板硬件故障"一个个排除掉。
而排除的过程,是人和 AI 交替推进的:
- 它挖数据,我提供它拿不到的事实
- 它试软件手段,我做物理动作
- 它下结论,我负责质疑
- 它写工具,我负责用
最有价值的两个技术动作,也正好一人一半:
- 看
[R]记录(AI 发现)——一条接收都没有,比任何猜测都硬。 - 隔离变量,拔光所有线(人执行)——有时候"拔掉一切"比任何高级命令都有效。
至于到底是哪根线的问题,目前还没定论:HDMI2 上还有一台设备没插回去,可能是它,也可能只是某次插拔导致 13 脚接触劣化、重新插拔就恢复了。这类故障有复发风险,先把流程记下来,下次直接照做。
更多推荐

所有评论(0)