Skip to content

fix(power): prevent wake-key rebound after mem resume#96

Draft
enjihn wants to merge 1 commit into
virtudude:mainfrom
enjihn:chz/odin3-wake-press-guard
Draft

fix(power): prevent wake-key rebound after mem resume#96
enjihn wants to merge 1 commit into
virtudude:mainfrom
enjihn:chz/odin3-wake-press-guard

Conversation

@enjihn

@enjihn enjihn commented Jul 15, 2026

Copy link
Copy Markdown

Summary

Armada already ships mem suspend for the Odin 3. This PR does not enable, select, or replace that suspend path; it prevents the physical power-key input used to wake the kernel from being interpreted after resume as a new steam://shortpowerpress.

The guard establishes an explicit input boundary around suspend:

  • a systemd-sleep hook atomically publishes one root-owned generation as prepared before suspend and the same generation as resumed afterward;
  • post-resume locates only the configured session user's exact, ready, top-level powerbuttond invocation and sends SIGUSR1;
  • the signal closes Bash's blocked read fd, then normal (non-trap) code terminates and reaps the old evtest process and opens a new descriptor;
  • because evdev queues belong to the open file description, replacing that descriptor discards historical wake-key backlog; and
  • a line that wins the signal/read race is still passed through the fresh guard before normal short/long-press handling.

Normal awake operation remains blocking and event-driven—there is no idle polling loop. Existing short press, long press, lid, and fake-suspend behavior is preserved.

Guard lifetime and failure behavior

  • A prepared generation can remain pending across an arbitrarily long suspend dwell; its bounded window begins only at the matching resumed phase or the first guarded key event.
  • A normally discovered resumed marker uses absolute monotonic deadlines anchored to publication. A forced post-signal refresh uses fresh bounded deadlines. Both use a 1.5-second soft window and an unconditional 5-second hard limit, checked on timer and event paths.
  • A valid marker that predates a newly started daemon is cached but does not arm the guard. The new daemon already owns a fresh evdev descriptor, so swallowing a later legitimate press would be incorrect.
  • Markers must be one exact record, current-boot, root-owned mode 0644, and not a symlink. Invalid or stale data is ignored.
  • Startup candidates without the daemon's fd 3 and same-script child/subshell processes are not signaled.
  • If the pre phase is missing, post publishes a fallback generation. If signaling is missed, powerbuttond still refreshes the marker before interpreting an input line.
  • If a signal arrives with a missing or malformed marker, the descriptor is still reopened so power-button handling remains usable.
  • A missing guard library is treated as a partial installation: powerbuttond logs and exits instead of running a half-installed path.

Why

On a physical Odin 3 running Armada Preview's existing mem implementation, local instrumentation captured the wake press being translated into another Steam short-power action within milliseconds of resume. One user-visible wake-then-immediate-sleep loop was reproduced.

An earlier live guard prototype then published a resume generation before session thaw and prevented the second Steam action in guarded cycles. Those observations establish the race and the value of a wake boundary, but they are local hardware evidence—not CI—and this redesigned descriptor-replacement implementation still needs installed-image qualification on the Odin 3. It does not claim to fix unrelated kernel, controller, audio, fan, or power-consumption behavior.

Scope and attribution

The underlying Odin 3 suspend enablement and Armada's ROCKNIX-derived kernel/GPU work are pre-existing and unchanged; this PR contains no kernel code and claims no credit for making mem work. PR #34 concerns suspend-mode selection/fallback and is orthogonal to this post-resume input race.

Development and analysis used substantial AI assistance, disclosed in the spirit of #27. AI helped inspect logs, refine the state machine, implement the patch, and build the tests. A human directed the scope, performed the physical device actions, and evaluated the observed behavior. The change is presented as a scoped, independently reviewable userspace patch.

Tests

  • git diff --check
  • bash tests/run.sh (also wired into just check), covering:
    1. Bash syntax for shipped and test scripts
    2. marker validation, stale-cache behavior, phase continuation, and absolute/forced deadlines
    3. pre/post publication, post fallback, and exact ready-PID matching
    4. normal short/long presses plus resume-boundary state-machine replay
    5. deterministic evtest process/descriptor replacement with backlog rejection
    6. SIGUSR1 interruption of a blocking Bash read and forced refresh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant