mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 16:57:39 +00:00
fix(notif): always stopSelf when foreground promotion fails
ForegroundServiceDidNotStartInTimeException crashes the whole app when a service started via startForegroundService() never successfully calls startForeground() within Android's ~10s window. NotificationRelayService.initializeForeground() only called stopSelf() on ForegroundServiceStartNotAllowedException. Any other failure to promote to the foreground (OEM-specific RemoteException/IllegalStateException, a resource lookup failure while building the notification, etc.) was logged but left the service in a "started but not foregrounded" zombie state, guaranteeing the timeout crash. Now stopSelf() runs on every failure path, which clears the OS's fgRequired flag and cancels the pending timeout. onStartCommand also bails early (START_NOT_STICKY) when foreground promotion failed, so we don't spin up relay coroutines on a service that's tearing itself down. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012hCJDhJmCNkzqb7SaMWQgB
This commit is contained in:
+15
-2
@@ -152,6 +152,10 @@ class NotificationRelayService : Service() {
|
||||
// Safety: also call startForeground from onStartCommand in case
|
||||
// onCreate didn't complete before onStartCommand fired (ntfy #1520)
|
||||
initializeForeground()
|
||||
// If we couldn't promote to the foreground, initializeForeground() already
|
||||
// called stopSelf(); don't spin up relay coroutines on a service that's
|
||||
// tearing itself down.
|
||||
if (!foregroundStarted) return START_NOT_STICKY
|
||||
startRelayConnection()
|
||||
return START_STICKY
|
||||
}
|
||||
@@ -222,14 +226,23 @@ class NotificationRelayService : Service() {
|
||||
)
|
||||
foregroundStarted = true
|
||||
} catch (e: Exception) {
|
||||
// Any failure to promote to the foreground leaves the service in a
|
||||
// "started but not foregrounded" zombie state. Once startForegroundService()
|
||||
// has been called, Android expects startForeground() within ~10s; if it never
|
||||
// lands it fires ForegroundServiceDidNotStartInTimeException and crashes the
|
||||
// whole app. Tearing the service down clears the OS's fgRequired flag, which
|
||||
// cancels that pending timeout, so we must stopSelf() on EVERY failure path —
|
||||
// not just ForegroundServiceStartNotAllowedException. Other causes include
|
||||
// OEM-specific RemoteException/IllegalStateException and resource lookup
|
||||
// failures while building the notification.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
|
||||
e is ForegroundServiceStartNotAllowedException
|
||||
) {
|
||||
Log.w(TAG, "Foreground service start not allowed, stopping self")
|
||||
stopSelf()
|
||||
} else {
|
||||
Log.e(TAG, "Failed to start foreground", e)
|
||||
Log.e(TAG, "Failed to start foreground, stopping self", e)
|
||||
}
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user