Skip to content

fix(tracker): harden ActivityWatcherService foreground start against platform rejection - #244

Merged
adsamcik merged 1 commit into
dev/v10from
fix/fgs-lifecycle-robustness-v2
Jul 21, 2026
Merged

fix(tracker): harden ActivityWatcherService foreground start against platform rejection#244
adsamcik merged 1 commit into
dev/v10from
fix/fgs-lifecycle-robustness-v2

Conversation

@adsamcik

Copy link
Copy Markdown
Owner

Summary

Supersedes #221 (closed, stale/conflicting against current dev/v10).

Re-investigated the original PR's scope against current dev/v10 before writing any code:

  • Already done, more thoroughly, by other work: the reviewer's core request on fix(tracker): harden foreground-service startup and handle FGS timeouts #221 -- deriving the foreground-service type from active tracking configuration/tier rather than permission possession -- is already implemented via TrackerService.foregroundServiceTypeCandidates() / resolveInitialPolicyTier(), with dedicated tests (ForegroundServiceTypeCandidatesTest, TierConfigurationTest) and full SecurityException/ForegroundServiceStartNotAllowedException handling (tryStartForeground) plus a user-visible failure notification. Nothing to port here.
  • Verified inapplicable, dropped from scope: Service.onTimeout(int, int) (Android 15+) only fires for dataSync/mediaProcessing foreground-service types per current platform docs, not location/health/specialUse -- which is all TrackerService and ActivityWatcherService declare. Implementing it would be dead code the system never calls.
  • Real remaining gap (this PR): ActivityWatcherService.startForegroundCompat() had no exception handling at all around startForeground(), unlike TrackerService's already-hardened equivalent. This service can be started from background contexts (e.g. after an activity-recognition transition), so an Android 12+ ForegroundServiceStartNotAllowedException or a SecurityException on the declared type would crash it with an uncaught exception.

Changes

  • Extracted the tolerant-start logic into two small, directly testable top-level functions in ActivityWatcherService.kt, mirroring TrackerService's pattern:
    • isForegroundServiceStartRestriction(sdkInt, exceptionClassName) -- pure string/SDK check, plain JUnit5 test (IsForegroundServiceStartRestrictionTest).
    • startForegroundTolerant(sdkInt, tag, start) -- try/catch + Reporter logging, Robolectric test (StartForegroundTolerantTest).
  • onCreate() now calls stopSelf() and returns instead of continuing setup when the foreground declaration is rejected.

Verification

  • .\gradlew.bat :tracker:engine:testDebugUnitTest (no filters, full module): BUILD SUCCESSFUL, 955 tests, 0 failures, 0 errors (includes the 7 new test cases).
  • Branch rebased onto current dev/v10 tip (post source-evidence-tracking refactor); no conflicts.

…platform rejection

ActivityWatcherService.startForegroundCompat had no exception handling around
startForeground() at all, unlike TrackerService's already-hardened equivalent
(tryStartForeground). This service can be started from background contexts
(e.g. after activity-recognition transitions), so an Android 12+
ForegroundServiceStartNotAllowedException or a SecurityException on the
declared foreground-service type would crash it with an uncaught exception.

Extracts the tolerant-start logic into two top-level, directly testable
functions mirroring TrackerService's pattern: isForegroundServiceStartRestriction
(pure class-name/SDK check) and startForegroundTolerant (try/catch + Reporter
logging). onCreate() now stops the service cleanly via stopSelf() instead of
continuing setup when the foreground declaration is rejected.

Supersedes PR #221 (closed, stale/conflicting): dev/v10 already contains a far
more thorough version of that PR's core request (foreground-service type derived
from active tracking config/tier rather than permission possession, with
dedicated tests) via TrackerService.foregroundServiceTypeCandidates /
resolveInitialPolicyTier. Service.onTimeout(int, int) (Android 15+) was verified
inapplicable here -- it only fires for dataSync/mediaProcessing foreground-service
types, not location/health/specialUse -- so it was dropped from scope rather than
added as dead code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 48e20dfd-a1bb-4266-bba5-2646e115c5cf
@adsamcik
adsamcik merged commit 571265a into dev/v10 Jul 21, 2026
3 of 4 checks passed
@adsamcik
adsamcik deleted the fix/fgs-lifecycle-robustness-v2 branch July 21, 2026 10:28
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