Skip to content

Record dropped schedules, and ask Android whether it is restricting this app - #4

Merged
TargetCrafter merged 2 commits into
mainfrom
fix/schedule-drop-audit
Sep 4, 2026
Merged

TargetCrafter merged 2 commits into
mainfrom
fix/schedule-drop-audit

Conversation

@TargetCrafter

@TargetCrafter TargetCrafter commented Sep 4, 2026 •

Copy link
Copy Markdown
Owner

What's now established

Two observations settle the mechanism:

  • The alarm was still showing as enabled in the app's own widget the morning after a failure. That widget only renders enabled alarms — so AlarmReceiver never ran and never consumed it.
  • binary_sensor.<phone>_ringing never changed state overnight. The ring service never started.

Together: AlarmManager never delivered the alarm. The entry was gone before its trigger time ever arrived. This was never a "didn't ring" problem — it's a "wasn't scheduled any more" problem, which is why none of the ring-path fixes moved the needle.

1. Record the drop before repairing it

The self-repair from #3 had a flaw: re-arming on app start erases the evidence that it was needed. By the time anyone looks, it's fixed and everything reads healthy.

The startup path now runs the health check first, records the finding via AlarmScheduleAudit, and only then re-arms. Settings shows the count and most recent occurrence, so future failures leave a trail rather than costing a night of observing at exactly the right moment — which, as it turns out, is impossible anyway while asleep.

2. Ask the OS what it thinks of this app

Force-stopping is what drops alarm entries, and Android will simply say whether it has the app in that position instead of leaving it inferred from a missed alarm:

  • ActivityManager.isBackgroundRestricted() — Restricted background mode.
  • UsageStatsManager.getAppStandbyBucket() — the standby bucket (Rare/Restricted are the dangerous ones).

Both are unprivileged for the calling app, so neither needs a permission. Settings warns when either says alarms can't be relied on, and opens the app's settings page — no intent toggles this directly.

Scope

This is diagnosis, not a fix. Nothing here can prevent a force-stop. What it does is turn "the alarm didn't ring and nobody knows why" into the OS stating its own position — which is what has been missing across five failures.

Not verified

Uncompiled here — ./gradlew assembleDebug first.

Re-arming on app start fixes a dropped schedule, but on its own it also
destroys the evidence that anything went wrong: by the time anyone opens
the app to look, it has been repaired and everything reads healthy. That
is exactly the case where knowing whether it happened at all IS the
diagnosis - a dropped schedule means the OS killed the app, while an
alarm that stayed registered and still didn't ring is a bug in here, and
the two need completely different fixes.

The startup path now runs the health check first, records the finding,
and only then re-arms. Settings shows the count and the most recent
occurrence when there is one, so each failure leaves a trail instead of
costing a night of observation to catch in the act.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C7x8v5c5Lu29PBWy1LdfCe
Confirmed today that the ringing sensor never changed state, so the ring
service never started; combined with the alarm still showing as enabled
in the app's own widget yesterday (which means the receiver never ran and
never consumed it), AlarmManager did not deliver the alarm at all. The
entry was gone before its trigger time.

Force-stopping an app is what drops its alarm entries, and Android will
say whether it has this app in that position rather than leaving it to be
inferred from a missed alarm. ActivityManager.isBackgroundRestricted()
reports Restricted background mode, and UsageStatsManager
.getAppStandbyBucket() reports the standby bucket - unprivileged for the
calling app, so neither needs a permission. Settings now warns when
either says alarms cannot be relied on, and opens the app's settings page,
since no intent toggles this directly.

This is diagnosis rather than a fix: nothing here can stop a force-stop.
But it turns "the alarm didn't ring and we don't know why" into the OS
stating its own position, which is what has been missing for five
failures.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C7x8v5c5Lu29PBWy1LdfCe
@TargetCrafter TargetCrafter changed the title Record when Android drops the alarm schedule, before repairing it Record dropped schedules, and ask Android whether it is restricting this app Sep 4, 2026
@TargetCrafter
TargetCrafter merged commit 69a05d7 into main Sep 4, 2026
4 checks passed
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