fix(win-display): a failed devnode re-enable must keep its crash-journal entry
ci / rust-arm64 (pull_request) Successful in 1m36s
ci / docs-site (pull_request) Successful in 1m22s
apple / swift (pull_request) Successful in 1m43s
apple / screenshots (pull_request) Skipped
ci / bun-nix (pull_request) Successful in 3m34s
ci / web (pull_request) Successful in 4m2s
android / android (pull_request) Successful in 4m13s
ci / rust (pull_request) Successful in 5m56s
ci / rust-arm64 (pull_request) Successful in 1m36s
ci / docs-site (pull_request) Successful in 1m22s
apple / swift (pull_request) Successful in 1m43s
apple / screenshots (pull_request) Skipped
ci / bun-nix (pull_request) Successful in 3m34s
ci / web (pull_request) Successful in 4m2s
android / android (pull_request) Successful in 4m13s
ci / rust (pull_request) Successful in 5m56s
enable_instances cleared every requested id from the pnp-disabled-monitors journal unconditionally — a mid-life re-enable failure erased its own crash-recovery entry, so neither the running host nor the next start would ever retry, leaving the operator's monitor disabled (invisible to Windows and every display listing) until a manual Device Manager fix. Field 2026-08-12 (Android-client host running the pnp_disable_monitors axis): displays gone from the client after 2-3 sessions, only a full host restart bringing them back — the restart path only works while the journal still has the entry. Only successfully re-enabled ids clear now; failures stay journaled (and are logged with the consequence) so startup_recover retries them.
This commit is contained in:
@@ -217,18 +217,32 @@ fn journal_and_disable(targets: Vec<(String, String)>) -> Vec<String> {
|
||||
disabled
|
||||
}
|
||||
|
||||
/// Re-enable `ids` (teardown / recovery) and clear them from the journal.
|
||||
/// Re-enable `ids` (teardown / recovery) and clear the ones that actually re-enabled from the
|
||||
/// journal. A FAILED re-enable must keep its journal entry: it is the only record that the
|
||||
/// devnode is still disabled, and the next host start's [`startup_recover`] is the only thing
|
||||
/// left that will retry it. (The old behavior cleared every requested id unconditionally — a
|
||||
/// mid-life re-enable failure erased its own crash-recovery entry, leaving the operator's
|
||||
/// monitor invisible to Windows AND to every display listing until they re-enabled it by hand
|
||||
/// in Device Manager: the "my displays are gone until I restart everything" field class.)
|
||||
pub fn enable_instances(ids: &[String]) -> u32 {
|
||||
let mut ok = 0u32;
|
||||
let mut reenabled: Vec<&String> = Vec::with_capacity(ids.len());
|
||||
for id in ids {
|
||||
if set_devnode(id, false) {
|
||||
tracing::info!(id, "PnP-disable: monitor devnode re-enabled");
|
||||
reenabled.push(id);
|
||||
ok += 1;
|
||||
} else {
|
||||
tracing::warn!(
|
||||
id,
|
||||
"PnP-disable: monitor devnode re-enable FAILED — keeping its crash-journal \
|
||||
entry so the next host start retries (until then this monitor stays disabled)"
|
||||
);
|
||||
}
|
||||
}
|
||||
let journal: Vec<String> = read_journal()
|
||||
.into_iter()
|
||||
.filter(|j| !ids.contains(j))
|
||||
.filter(|j| !reenabled.contains(&j))
|
||||
.collect();
|
||||
write_journal(&journal);
|
||||
ok
|
||||
|
||||
Reference in New Issue
Block a user