结论
不是卡死、也不是显示故障。开机后 19 秒系统就按「合盖即睡」策略进入了睡眠(s2idle),两次;被 USB 键盘唤醒后,登录界面(greeter)阶段的画面没有恢复 ⇒ 表现为「内屏点亮但没有登录画面、像卡住」。第二次开机(盖子已打开)入睡次数为 0,一切正常。与当天的系统改动无关。
现象
- 重启后进桌面阶段,内屏亮着但没出登录画面,看起来卡住;用户强制关机后再次开机即可正常登录。
- 失败那次的登录界面进程其实一直在运行:它仍能与守护进程通信,并在日志里处理了两次密码校验(均失败,属盲打/界面不可用所致)⇒ 不是服务挂死。
时间线(实测,失败那次开机)
| 时刻 | 事件 |
|---|---|
| T+0:00 | 内核启动(与上次成功开机同一内核) |
| T+0:10 | X 服务器启动,已给内屏与三路外接输出设定模式(所以内屏是「亮」的) |
| T+0:10 | 登录界面(greeter)启动,加载 breeze 主题 |
| T+0:29 | systemd-logind: Suspending... ⇒ 随即内核 PM: suspend entry (s2idle) |
| T+0:47 | 被 USB 键盘唤醒(睡了 17 秒) |
| T+1:12 | 再次 Suspending(盖子仍处闭合)⇒ 又睡 |
| T+1:25 | 再次被 USB 键盘唤醒(睡了 12 秒) |
| T+1:41 | 用户打开盖子 ⇒ 日志出现 Lid opened. |
| T+2:25 | 一次密码校验失败(界面不可用下的盲打) |
| T+2:27 | 强制关机;36 秒后第二次开机,入睡 0 次,正常登录 |
根因
- 重启时盖子就是关着的:前一次会话里最后一条盖子事件是「关闭」,之后一直没打开过。所以这次开机时盖子开关一注册到 logind 就已经是闭合状态(因此日志里没有「关闭」事件、只有后来那次「打开」)。
- 策略就是「合盖即睡」,且三档全是睡:
HandleLidSwitch/HandleLidSwitchDocked/HandleLidSwitchExternalPower全部为suspend(IdleAction为ignore)⇒ 盖子闭合时无论是否接着外接屏、是否插着电源,logind 都会让系统睡 ⇒ 登录界面刚出来就被送去睡。 - 唤醒后的画面补救在登录界面阶段覆盖不到:针对「睡醒后显示不对」的重放钩子是会话内机制(脚本里有明确的「无会话则跳过」分支)。登录界面阶段还没有用户会话 ⇒ 那次日志只留下
display-refresh-nudge: queued=1 no-session=none,画面并未恢复 ⇒ 于是「内屏亮、没有登录画面」。 - 因盖子仍闭合,被键盘唤醒后会再次入睡(第二次入睡的具体触发者 logind 未留痕,按机制推断为「盖子仍闭合」,标注待实测)⇒ 表现为反复黑屏、像死机。
实测证据
| 判据 | 实测 |
|---|---|
| 入睡次数(失败那次 / 成功那次) | 2 次 / 0 次 |
| 入睡发起者 | systemd-logind: Suspending...(非内核自发、非定时任务) |
| 睡眠方式与时长 | s2idle;两次分别 17 秒、12 秒 |
| 唤醒源(本机唤醒记录) | USB 键盘(键盘设备 + 对应 USB 控制器计数)⇒ 与「按键盘唤醒」一致 |
| 盖子状态变化 | 全程只有一条 Lid opened.(在两次睡眠之后)⇒ 说明此前一直是闭合 |
| 登录界面是否存活 | 存活:日志里能处理登录请求、并返回校验失败 |
| 内屏为什么「亮」 | X 启动时已给内屏设了模式(2560x1600),所以背光/画面已建立 |
与当天系统改动无关的判据
- 两次开机用的是同一个内核与同一份 X 配置(配置文件的取用路径两次完全相同)。
- 两次都不存在独立显卡(日志里两次都报「未找到该 GPU」、其驱动均未加载)⇒ 差异不在这里。
- 两次的 X 初始化序列逐行一致(含同样的输出与模式设定)⇒ 区别只在于「盖子是否闭合」这一个变量。
处置与判据
- 最省事:开机时保持盖子打开;合盖使用场景下不要指望登录界面在合盖状态出现。
- 已弃用的候选方案:把
HandleLidSwitchDocked由suspend改成ignore。实测其口径是「插在坞站 或接了多于一个显示器」,而这一档不看供电状态 ⇒ 改它会连累所有供电档,故不采用。实际做法见下节「处置落地」。 - 「睡醒后登录界面也能重画」目前没有机制:现有补救钩子按会话工作,登录界面阶段无会话可用;若要覆盖这一段,需要另做一条「不依赖用户会话」的重放(拿到登录界面的显示授权后执行重放),属新需求。
边界
本档只覆盖「因合盖睡眠导致登录界面不可见」这一条链路;不含睡眠/唤醒源策略本身的取舍。第二次入睡的具体触发者在日志中没有留痕(logind 不记录触发者),推断依据是「盖子仍闭合」,标注待实测。该次排查全程只读、未改动配置;随后的处置改动见下节。
处置落地(只作用于交流供电档)
结论先行:登录前(开机、登录界面、关机这些没有桌面电源管理在跑的阶段)由系统层在交流供电时持住 systemd 的低层抑制锁 handle-lid-switch,使 logind 完全不处理合盖;非交流供电时只释放这把锁、交回原生处理。这样「插着电合盖 / 合盖状态 / 合盖开机都不睡」就成立,且手动睡眠(快捷键、菜单)不受影响 —— 该锁只挡「合盖开关」这一路。
为什么不只改那三个取值:HandleLidSwitchDocked 的口径含「接了多于一个显示器」且不看供电状态;本机常接外接屏 ⇒ 恒为该档 ⇒ 三个取值组合不出「一档永不睡、另一档按设置」。所以要靠抑制锁把「交流」这一档单独摘出来。
作用范围(明确):只管交流供电。电池档、低电档的合盖行为一律以桌面电源管理界面的设置为准,系统层不干预;系统层对非交流档只做一件事 —— 把交流档拿着的锁释放掉(否则拔电后合盖就永远不睡了)。
| 验收判据 | 实测 |
|---|---|
| 有效合盖取值 | HandleLidSwitch=suspend / HandleLidSwitchDocked=suspend(保持原生行为)/ HandleLidSwitchExternalPower=ignore(交流档第二道保险) |
| 抑制锁是否在持 | 是:抑制锁清单里出现 root 的 handle-lid-switch … block |
| 释放单元的行为 | 只执行「停掉持锁服务」,不含任何睡眠动作 |
| 插拔电是否有人响应 | 有:由电源设备的 udev 事件触发持锁 / 释放单元(不轮询) |
| 系统健康 | 无失败单元;当次开机睡眠次数 0 |
撤回记录(越界部分已撤净):过程中曾一度把界面里「电池档的合盖动作」写成睡眠、并在释放单元里自造「转为电池且已合盖就立即睡」—— 两处都被判定为越界(非交流档以界面设置为准),已全部撤回:界面配置恢复后与改动前逐字节一致,释放单元现只剩释放锁这一个动作。
待实测(需要物理动作):① 交流供电 + 合盖静置 ⇒ 应不睡;② 合盖状态下开机(交流)⇒ 应正常出登录界面;③ 非交流档的合盖行为 ⇒ 以界面设置为准。关机流程中 logind 是否处理合盖:仍未实测。