Skip to content

Local server stops after swipe-away until app is reopened #252

Description

@TimeToBuildBob

Problem

On a OnePlus 7 / Android 12 running v0.14.0b2, the local server at localhost:5600 stops exposing newly recorded Android activity after the app is removed from recents. Reopening the app starts the server and backfills the missing interval from Android UsageStats, so the data was available to import but was not persisted or queryable while the app process was down.

The source report also mentions force-stop. Android deliberately prevents all app components, alarms, and sticky-service restarts after a force-stop until the user launches the app again; that case cannot provide an always-live local API. Swipe-away is distinct and should be investigated separately.

Source report: #247

Current implementation

In v0.14.0b2 and current master:

  • BackgroundService is a foreground service and returns START_STICKY.
  • The manifest leaves android:stopWithTask at its default (false).
  • The activity starts the service and schedules hourly event parsing.
  • There is no onTaskRemoved instrumentation or explicit restart fallback, so the report does not yet tell us whether OxygenOS destroys the service, suppresses the sticky restart, or only stops the native server.

Scope

  • Reproduce swipe-away separately from force-stop on Android 12 / OxygenOS.
  • Capture BackgroundService lifecycle and process-exit evidence around removal from recents.
  • Keep the local server/API available after a normal swipe-away, or restart it automatically when Android permits.
  • Document the unavoidable force-stop boundary rather than presenting it as recoverable.

Acceptance criteria

  • Swiping ActivityWatch away from recents does not permanently stop localhost:5600; if the process is killed, service/server recovery is verified without reopening the activity.
  • Activity events recorded after swipe-away become queryable without reopening the app.
  • The behavior is tested on Android 12, with OnePlus/OxygenOS battery-management behavior recorded.
  • Force-stop behavior is documented as an Android platform limitation.
  • Any restart fallback avoids a tight crash/restart loop and follows Android foreground-service restrictions.

Diagnostic request

For an affected device, capture the persistent-notification state and filtered logs while reproducing swipe-away only:

adb logcat -c
adb logcat -v time BackgroundService:I RustInterface:I ActivityManager:I AndroidRuntime:E '*:S'

The key distinction is whether BackgroundService destroyed appears, whether the process exits, and whether BackgroundService created / Starting server... follows without opening the activity.

Activity

  1. Ansar-04 commented on Sep 3, 2026

    @Ansar-04

    Device: OnePlus 7 / Android 12 (OxygenOS)
    AW version: v0.14.0b2

    Steps performed:

    1. Opened ActivityWatch (MainActivity visible).
    2. Swiped the app away from the recents screen.
    3. Waited ~30 seconds.
    4. Reopened ActivityWatch from the launcher.

    What the filtered log shows:

    • At 16:20:56.908: BackgroundService started (initial launch).
    • After swipe‑away (around 16:21:07, onTaskRemoved confirmed in the full log), there are NO new BackgroundService or RustInterface entries until:
    • At 16:21:34.404: BackgroundService started again – this only happened because I manually reopened the app.
    • At that moment, the service re‑started and backfilled the missing interval using Android UsageStats (as seen in the full log).

    Key observations:

    1. The local HTTP server (aw-server-rust, PID 6063) remained alive after swipe‑away – it still answered requests from Chrome.
    2. However, the background data collector (BackgroundService) was killed and did NOT restart automatically.
    3. START_STICKY does not seem to be honoured on this device/ROM; no automatic restart occurred.

    This matches the issue described in #252: data collection stops after swipe‑away, and only resumes when the user re‑opens the app.

    Attached is the filtered log (only BackgroundService:I, RustInterface:I, ActivityManager:I, AndroidRuntime:E).

    Log:
    09-03 16:20:46.277 W/ActivityManager( 2710): Unable to start service Intent { act=oplus.intent.action.SECURE_PAY_SCAN_RISK pkg=com.coloros.securepay (has extras) } U=0: not found
    09-03 16:20:47.288 D/ActivityManagerWrapper( 3666): startRecentsActivity()--onAnimationStart()
    09-03 16:20:56.818 W/ActivityManager( 2710): Unable to start service Intent { act=oplus.intent.action.SECURE_PAY_SCAN_RISK pkg=com.coloros.securepay (has extras) } U=0: not found
    09-03 16:20:56.893 I/RustInterface( 6063): Bucket with ID 'aw-watcher-android', already existed. Not creating.
    09-03 16:20:56.896 I/RustInterface( 6063): Bucket with ID 'aw-watcher-android-unlock', already existed. Not creating.
    09-03 16:20:56.908 I/BackgroundService( 6063): BackgroundService started
    09-03 16:20:56.908 I/BackgroundService( 6063): Scheduled event parsing worker with initial delay: 27543092ms
    09-03 16:20:56.908 I/BackgroundService( 6063): Scheduled activity-time notification worker (every 15 minutes)
    09-03 16:21:02.464 I/adbd (13523): adbd service requested 'shell,v2,TERM=xterm-256color:export ANDROID_LOG_TAGS=''; exec logcat '-v' 'time' 'BackgroundService:I' 'RustInterface:I' 'ActivityManager:I' 'AndroidRuntime:E' '''':S'''''
    09-03 16:21:05.310 D/ActivityManagerWrapper( 3666): startRecentsActivity()--onAnimationStart()
    09-03 16:21:09.748 D/OplusBaseActivityManagerWrapper( 3666): startActivityFromRecents: taskId = 1282
    09-03 16:21:09.783 W/ActivityManager( 2710): Unable to start service Intent { act=oplus.intent.action.SECURE_PAY_SCAN_RISK pkg=com.coloros.securepay (has extras) } U=0: not found
    09-03 16:21:11.077 I/ActivityManager( 2710): Process com.google.android.apps.maps (pid 11851) has died: cch+95 CEM
    09-03 16:21:11.077 W/ContextImpl( 2710): Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1175 com.android.server.am.OplusExtraActivityManagerService.setKeyLockModeNormal:51 com.android.server.am.ActivityManagerServiceExtImpl.setKeyLockModeNormal:851 com.android.server.am.ActivityManagerService.appDiedLocked:3389 com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied:1531
    09-03 16:21:25.047 W/ActivityManager( 2710): Receiver with filter android.content.IntentFilter@6395c1f already registered for pid 3292, callerPackage is com.android.systemui
    09-03 16:21:29.607 D/ActivityManagerWrapper( 3666): startRecentsActivity()--onAnimationStart()
    09-03 16:21:34.320 W/ActivityManager( 2710): Unable to start service Intent { act=oplus.intent.action.SECURE_PAY_SCAN_RISK pkg=com.coloros.securepay (has extras) } U=0: not found
    09-03 16:21:34.392 I/RustInterface( 6063): Bucket with ID 'aw-watcher-android', already existed. Not creating.
    09-03 16:21:34.393 I/RustInterface( 6063): Bucket with ID 'aw-watcher-android-unlock', already existed. Not creating.
    09-03 16:21:34.404 I/BackgroundService( 6063): BackgroundService started
    09-03 16:21:34.404 I/BackgroundService( 6063): Scheduled event parsing worker with initial delay: 27505596ms
    09-03 16:21:34.404 I/BackgroundService( 6063): Scheduled activity-time notification worker (every 15 minutes)
    09-03 16:21:37.518 D/ActivityManagerWrapper( 3666): startRecentsActivity()--onAnimationStart()
    09-03 16:21:46.011 W/ActivityManager( 2710): Receiver with filter android.content.IntentFilter@8abad16 already registered for pid 3292, callerPackage is com.android.systemui
    09-03 16:21:49.965 I/adbd (13523): adbd service requested 'shell,v2:export ANDROID_LOG_TAGS=''; exec logcat '-d' '-v' 'time' 'BackgroundService:I' 'RustInterface:I' 'ActivityManager:I' 'AndroidRuntime:E' ''''
    :S'''''

  2. TimeToBuildBob commented on Sep 3, 2026

    @TimeToBuildBob
    ContributorAuthor

    Thanks — this narrows it down, but the observations point to a different boundary than “the local server stops”:

    • PID 6063 and localhost:5600 remained alive after the swipe, so neither the process nor aw-server-rust was killed.
    • There is no BackgroundService destroyed entry and no replacement process/service start before reopening.
    • BackgroundService started is only emitted by onStartCommand; its absence is expected if the existing service/process survived. START_STICKY only asks Android to recreate a service after Android kills it, so there was nothing for it to restart here.

    The likely gap is therefore the usage-event ingestion path: ActivityWatch currently schedules normal ingestion through AlarmReceiver, while reopening additionally calls sendHeartbeatsSuspend() from MainActivity.onResume(). The reopen backfill does not prove that BackgroundService stopped.

    Could you run one more swipe-away test and leave it closed for at least 65 minutes, then query the Android bucket before reopening? The current logging alarm is hourly, so the 27-second window cannot distinguish a broken background alarm from expected batching. Please also include these tags in logcat so we can see the ingestion path itself:

    adb logcat -c
    adb logcat -v time BackgroundService:I RustInterface:I AlarmReceiver:V UsageStatsWatcher:V ActivityManager:I AndroidRuntime:E '*:S'

    Also confirm whether the persistent ActivityWatch notification remained visible throughout. If no ingestion happens after an hourly alarm window, the next fix belongs in alarm delivery / foreground ingestion rather than adding a service restart loop.

  3. ErikBjare commented on Sep 23, 2026

    @ErikBjare
    Member

    @TimeToBuildBob not sure how relevant #255 was. Closing.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions