Skip to content

fix(hook): keep the short budget for tap teardown after a probe break - #1600

Open
TheMedpreneur wants to merge 4 commits into
AprilNEA:masterfrom
TheMedpreneur:fix/hook-probe-teardown-budget
Open

TheMedpreneur wants to merge 4 commits into
AprilNEA:masterfrom
TheMedpreneur:fix/hook-probe-teardown-budget

Conversation

@TheMedpreneur

Copy link
Copy Markdown

Summary

Stacked on #1282. The first commit is #1282 unchanged; only the second commit is new.

In #1282, the revocation break and the re-arm-exhausted break leave TapPhase::Probing published. Tearing down a tap that outlived its Accessibility grant is the freeze hazard this watchdog exists for, but it would then be judged against the 10 s probe budget instead of 1.5 s.

Changes

  • hook (macos.rs): return to Armed with a fresh progress mark before both breaks, so teardown keeps the short budget.

Testing

  • cargo fmt --all -- --check, cargo clippy -p openlogi-hook --all-targets -- -D warnings, cargo test -p openlogi-hook.
  • Hardware: MX Master 4 over Bluetooth LE, macOS 27.0 (26A428). Before fix(hook): give the macOS tap's capability probes their own watchdog budget #1282 my logs had four phase=Armed force-exits around wake and unlock. With it applied there have been 0 across 24 display/session resumes, including an overnight sleep. The revocation path is not runtime-tested.

Refs #1282, #952

hyspacex and others added 2 commits September 27, 2026 07:41
…budget

`service_tap` marks tap progress immediately before and immediately after its
500 ms `CFRunLoopRunInMode` slice, then runs the between-slice capability
probe — `AXIsProcessTrusted()`, the throwaway `CGEventTapCreate` in
`can_filter_events()`, `CGEventTapIsEnabled`, `CGEventTapEnable` — without
marking again until the top of the next iteration. That window is charged to
`TAP_SHUTDOWN_BUDGET`, so a probe slower than 1.5 s reads as a wedged tap
thread and the lifecycle watchdog force-exits the agent with
`FREEZE_HAZARD_EXIT_CODE`.

Those calls are WindowServer and TCC round trips, and while the display is
asleep they take seconds. A user's agent log shows the resulting exit repeat
27 times across 2.5 h of display sleep, always
`reason="HID tap thread stopped making progress while tap remained active"`,
`phase=Armed`, `elapsed_ms` between 1555 and 1740, with launchd restarting the
agent 4-8 s later each time. Since the run-loop slice is bounded at 500 ms and
re-marks progress on both sides, the whole overrun is inside the probe.

The tap thread now publishes `TapPhase::Probing` for that window and returns
to `Armed` with a fresh progress mark once `CGEventTapEnable` returns. The
watchdog judges `Probing` against a separate `TAP_PROBE_BUDGET` for both exit
reasons, so a stop request landing on a slow probe is treated the same way; a
thread that reached the `Probing` store is demonstrably alive and inside a
named CoreGraphics/TCC call rather than wedged servicing the tap. Everything
else keeps the 1.5 s budget, `Probing` stays hazardous for the re-check before
exiting, and a probe that never returns — the TCC-revocation stall this
watchdog exists for — still force-exits. The freeze exposure does not grow
with the budget: an active tap whose thread is not servicing its run loop is
already bounded by CoreGraphics' own tap timeout, which disables the tap and
lets events through.

The break paths deliberately leave `Probing` published; the thread is still
inside CoreGraphics for the synchronous teardown, and the watchdog stays armed
on that phase either way.

Refs AprilNEA#952
Follow-up to the Probing phase: the revocation and re-arm-exhausted
breaks left Probing published, so tearing down a tap that outlived its
permission got the 10 s probe budget instead of 1.5 s. Return to Armed
with a fresh progress mark before breaking.
@greptile-apps

greptile-apps Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Adjusts watchdog timeouts for a system probe phase.

The PR appears safe to merge; no outstanding finding or new actionable issue was identified.

Summary

This PR gives capability probes a longer watchdog budget while returning to the short budget for tap servicing and teardown.

  • The change since the previous review replaces a timing-dependent test assertion with one that checks the refreshed progress mark without a post-return deadline.

Reviews (3) · Last reviewed commit: "test(hook): make the resume_armed test i..."

Comment thread crates/openlogi-hook/src/macos/watchdog.rs
Comment thread crates/openlogi-hook/src/macos.rs Outdated
Comment thread crates/openlogi-hook/src/macos.rs Outdated
…op clock on progress

Review follow-up. Leaving Probing stored Armed before the fresh progress
mark, so a watchdog poll between the two stores could pair the short
budget with the pre-probe timestamp and force-exit a healthy agent; a
single resume_armed() now marks progress first at all three probe exits.
A stop request landing during a slow probe kept measuring from the stop
time, so teardown could start with its budget already spent; the stop
deadline now runs from the later of the request and the last progress
mark, which a wedged thread never advances.
Comment thread crates/openlogi-hook/src/macos/watchdog.rs Outdated

This branch has not been deployed

No deployments
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.

2 participants