fix(host): name the lid-closed/no-frames failure — display-write decode, console-session guard, driver-truth attach diagnostics
Field report (Windows laptop, lid closed, Tailscale): v0.12.0's activation fix works — the pf-vdisplay target activates in ~200ms — but the session still dies at the first-frame gate: 'driver_status=1 but no frame published within 4s'. Triage showed three independent blind spots; this names all of them at their source instead of guessing downstream: - pf-win-display: decode ChangeDisplaySettingsExW failures (-1 FAILED — a display write rejected, the wrong/remote-session signature — vs -2 BADMODE, which the old 'mode not advertised?' text conflated), and WARN on every non-zero SetDisplayConfig rc in the CCD isolate even when verification passes vacuously (the lid-closed case: nothing else active, so the INFO swallowed rc=0x5 ERROR_ACCESS_DENIED while the load-bearing COMMIT_MODES → ASSIGN_SWAPCHAIN re-commit silently never applied). Access-denied rcs get the remedy appended (console session / installed service). - host: console-session guard (interactive::console_session_mismatch) — a host outside the active console session (a hand-launched host after an RDP round-trip) fails every display write, reads the wrong session's GDI view, and its SendInput compose kicks go nowhere. Named ERROR at vdisplay acquire + appended to the first-frame timeout, instead of the misleading generic failure. (The idd_push diagnosis half of this landed in 9a36ea21; this commit adds the proto helpers + session guard it references, healing the windows-cfg build.) - proto + driver: while OPENED, driver_status_detail now carries a live packed word (bit31 live-marker | offered 15-bit | mismatch-dropped 16-bit) maintained by the publisher, so the host's first-frame timeout can tell apart: never-attached (no swap-chain worker ran), attached-but-DWM-composed- zero-frames (undamaged/powered-off desktop, kicks blocked on the secure desktop), and composed-but-every-frame-mismatched (ring sized from a stale/ foreign-session GDI mode). Zero layout change, old drivers read as 'no detail'; unit-tested pack/unpack in pf-driver-proto. Verified on winbox: cargo check + clippy -p punktfunk-host -p pf-win-display -p pf-driver-proto EXIT 0, drivers ws cargo check -p pf-vdisplay EXIT 0 (Version_Number=10.0.26100.0), cargo fmt --all --check clean; pf-driver-proto tests 13/13 pass locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,27 @@ use windows::Win32::System::Threading::{
|
||||
CreateProcessAsUserW, CREATE_UNICODE_ENVIRONMENT, PROCESS_INFORMATION, STARTUPINFOW,
|
||||
};
|
||||
|
||||
/// `Some((own_session, console_session))` when this process is NOT in the active console session —
|
||||
/// the state in which every display write (`SetDisplayConfig` / `ChangeDisplaySettingsExW`) fails
|
||||
/// `ERROR_ACCESS_DENIED`, GDI reads describe the wrong session's displays, and `SendInput` compose
|
||||
/// kicks go nowhere. Field signature: a hand-launched host whose session later went remote (an RDP
|
||||
/// round-trip) — the installed service relaunches the host when the console session moves, a
|
||||
/// hand-launched one stays trapped. `None` in the console session, and `None` when the check
|
||||
/// itself can't answer (no console session attached — boot / session transition — or the session
|
||||
/// query failed): the guard exists to NAME a known-bad state, so an unknown state stays quiet.
|
||||
pub fn console_session_mismatch() -> Option<(u32, u32)> {
|
||||
use windows::Win32::System::RemoteDesktop::ProcessIdToSessionId;
|
||||
use windows::Win32::System::Threading::GetCurrentProcessId;
|
||||
let mut own: u32 = 0;
|
||||
// SAFETY: `own` is a live local out-param for this synchronous call; no pointer escapes it.
|
||||
if unsafe { ProcessIdToSessionId(GetCurrentProcessId(), &mut own) }.is_err() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: takes no arguments and returns the console session id by value.
|
||||
let console = unsafe { WTSGetActiveConsoleSessionId() };
|
||||
(console != 0xFFFF_FFFF && own != console).then_some((own, console))
|
||||
}
|
||||
|
||||
/// Spawn `cmdline` in the active console session, under the logged-in user's token, on the
|
||||
/// interactive desktop (`winsta0\default`). Returns the new process id.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user