fix(background): improve foreground service lifecycle and keep-alive handling

This commit is contained in:
cogwheel0
2025-10-24 12:23:56 +05:30
parent c5f4168d47
commit af2d70ba31
2 changed files with 49 additions and 17 deletions

View File

@@ -116,7 +116,6 @@ jobs:
fi fi
# Generate commit messages since the previous tag # Generate commit messages since the previous tag
echo "## What's Changed" > release_notes.md
echo "" >> release_notes.md echo "" >> release_notes.md
git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..${{ github.ref_name }} >> release_notes.md git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..${{ github.ref_name }} >> release_notes.md

View File

@@ -29,6 +29,7 @@ class BackgroundStreamingService : Service() {
private val activeStreams = mutableSetOf<String>() private val activeStreams = mutableSetOf<String>()
private var isForeground = false private var isForeground = false
private var currentForegroundType: Int = 0 private var currentForegroundType: Int = 0
private var foregroundStartTime: Long = 0
companion object { companion object {
const val CHANNEL_ID = "conduit_streaming_channel" const val CHANNEL_ID = "conduit_streaming_channel"
@@ -51,6 +52,12 @@ class BackgroundStreamingService : Service() {
} }
} }
// For KEEP_ALIVE, only refresh the wake lock without restarting foreground
if (intent?.action == "KEEP_ALIVE") {
keepAlive()
return START_STICKY
}
val notification = createMinimalNotification() val notification = createMinimalNotification()
val desiredType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val desiredType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
resolveForegroundServiceType(intent) resolveForegroundServiceType(intent)
@@ -74,9 +81,6 @@ class BackgroundStreamingService : Service() {
acquireWakeLock() acquireWakeLock()
println("BackgroundStreamingService: Started foreground service") println("BackgroundStreamingService: Started foreground service")
} }
"KEEP_ALIVE" -> {
keepAlive()
}
} }
return START_STICKY return START_STICKY
@@ -92,9 +96,12 @@ class BackgroundStreamingService : Service() {
startForeground(NOTIFICATION_ID, notification) startForeground(NOTIFICATION_ID, notification)
} }
isForeground = true isForeground = true
foregroundStartTime = System.currentTimeMillis()
println("BackgroundStreamingService: Foreground service started at $foregroundStartTime")
true true
} catch (e: SecurityException) { } catch (e: Exception) {
println("BackgroundStreamingService: Failed to enter foreground: ${e.message}") // Catch all exceptions including ForegroundServiceStartNotAllowedException
println("BackgroundStreamingService: Failed to enter foreground: ${e.javaClass.simpleName}: ${e.message}")
false false
} }
} }
@@ -154,7 +161,9 @@ class BackgroundStreamingService : Service() {
PowerManager.PARTIAL_WAKE_LOCK, PowerManager.PARTIAL_WAKE_LOCK,
"Conduit::StreamingWakeLock" "Conduit::StreamingWakeLock"
).apply { ).apply {
acquire(3 * 60 * 60 * 1000L) // 3 hours max (refreshed every 5 minutes) // Use shorter wake lock duration to comply with Android restrictions
// Refresh periodically via keepAlive instead of long timeout
acquire(10 * 60 * 1000L) // 10 minutes (refreshed every 5 minutes)
} }
println("BackgroundStreamingService: Wake lock acquired") println("BackgroundStreamingService: Wake lock acquired")
} }
@@ -170,6 +179,18 @@ class BackgroundStreamingService : Service() {
} }
private fun keepAlive() { private fun keepAlive() {
// Check if we're approaching Android 14's 6-hour dataSync limit
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && isForeground) {
val uptime = System.currentTimeMillis() - foregroundStartTime
val fiveHours = 5 * 60 * 60 * 1000L // 5 hours in milliseconds
if (uptime > fiveHours) {
println("BackgroundStreamingService: Approaching time limit (${uptime / 3600000}h), stopping service")
stopStreaming()
return
}
}
// Refresh wake lock to extend background processing time // Refresh wake lock to extend background processing time
releaseWakeLock() releaseWakeLock()
acquireWakeLock() acquireWakeLock()
@@ -177,15 +198,20 @@ class BackgroundStreamingService : Service() {
} }
private fun stopStreaming() { private fun stopStreaming() {
println("BackgroundStreamingService: Stopping service...")
activeStreams.clear() activeStreams.clear()
releaseWakeLock() releaseWakeLock()
if (isForeground) { if (isForeground) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { try {
stopForeground(STOP_FOREGROUND_REMOVE) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
} else { stopForeground(STOP_FOREGROUND_REMOVE)
@Suppress("DEPRECATION") } else {
stopForeground(true) @Suppress("DEPRECATION")
stopForeground(true)
}
} catch (e: Exception) {
println("BackgroundStreamingService: Error stopping foreground: ${e.message}")
} }
isForeground = false isForeground = false
} }
@@ -194,9 +220,18 @@ class BackgroundStreamingService : Service() {
println("BackgroundStreamingService: Service stopped") println("BackgroundStreamingService: Service stopped")
} }
override fun onTaskRemoved(rootIntent: Intent?) {
println("BackgroundStreamingService: Task removed, stopping service")
stopStreaming()
super.onTaskRemoved(rootIntent)
}
override fun onDestroy() { override fun onDestroy() {
println("BackgroundStreamingService: onDestroy called")
releaseWakeLock() releaseWakeLock()
activeStreams.clear()
isForeground = false isForeground = false
foregroundStartTime = 0
super.onDestroy() super.onDestroy()
println("BackgroundStreamingService: Service destroyed") println("BackgroundStreamingService: Service destroyed")
} }
@@ -382,11 +417,9 @@ class BackgroundStreamingHandler(private val activity: MainActivity) : MethodCal
streamsRequiringMic.isNotEmpty(), streamsRequiringMic.isNotEmpty(),
) )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Use startService (not startForegroundService) for keep-alive pings
context.startForegroundService(serviceIntent) // to avoid ForegroundServiceStartNotAllowedException on Android 14+
} else { context.startService(serviceIntent)
context.startService(serviceIntent)
}
} catch (e: Exception) { } catch (e: Exception) {
println("BackgroundStreamingHandler: Failed to keep alive service: ${e.message}") println("BackgroundStreamingHandler: Failed to keep alive service: ${e.message}")
} }