Use retained resource ownership instead of Deferred cancellation as the cleanup barrier

This commit is contained in:
evgeny committed 2026-10-29 13:34:23 +01:00
1 parent a5d8131d8d
commit ca7b23909b
2 files changed
+11 -6

No files matched your search

@@ -328,7 +328,7 @@ object CallController : TelecomCallManager.Listener {
_state.value = st.copy(phase = CallPhase.ENDED, reason = reason, preparing = false,
connectionType = CallConnectionType.NONE, connectionNextHop = 0)
syncCoreActivity()
LogManager.addLog("INFO", "Call", "finished id=$id reason=$reason serviceCleanupComplete=${serviceReleased?.isCompleted != false}")
LogManager.addLog("INFO", "Call", "finished id=$id reason=$reason serviceCleanupComplete=${!CallService.cleanupPending()}")
val released = mediaPreparation
scope.launch {
serviceReleased?.await()
@@ -47,7 +47,8 @@ class CallService : Service() {
fun requireReleased() {
checkMain()
val previous = pendingCleanup ?: return
check(previous.shutdown().isCompleted) {
previous.shutdown()
check(pendingCleanup == null) {
val message = "Call service cleanup still pending id=${previous.callId}"
LogManager.addLog("ERROR", "CallService", message)
message
@@ -170,7 +171,7 @@ class CallService : Service() {
}
return START_NOT_STICKY
}
if (stopping && !released.isCompleted) {
if (stopping && pendingCleanup === this) {
LogManager.addLog("ERROR", "CallService", "start blocked by pending cleanup id=$id owned=$callId")
try { CallController.audioFailed(id, "previous service cleanup pending") } catch (e: Exception) {
LogManager.addLog("ERROR", "CallService", "cleanup refusal callback failed id=$id: $e")
@@ -332,7 +333,7 @@ class CallService : Service() {
return builder.build()
}
/** На main независимо очистить владельцев. Deferred завершается только после подтверждения всех операций.
/** На main независимо очистить владельцев. Deferred успешно завершается после подтверждения всех операций.
* При отказе сохраняется один process-владелец и отменяемый retry 250мс..30с; main не ждёт Deferred. */
fun shutdown(): Deferred<Unit> {
checkMain()
@@ -356,7 +357,11 @@ class CallService : Service() {
val pending = audioOwned || video != null || wakeLock != null || powerEventsRegistered ||
foregroundOwned || openIntent != null || endIntent != null || !stopRequested
if (pending) {
check(pendingCleanup == null || pendingCleanup === this) { "Two retained call service owners" }
check(pendingCleanup == null || pendingCleanup === this) {
val message = "Two retained call service owners: current=$callId previous=${pendingCleanup?.callId}"
LogManager.addLog("ERROR", "CallService", message)
message
}
pendingCleanup = this
val delay = retryDelayMs
retryDelayMs = (retryDelayMs * 2).coerceAtMost(30_000L)
@@ -428,7 +433,7 @@ class CallService : Service() {
try { CallController.serviceLost(id, this) } catch (e: Exception) {
LogManager.addLog("ERROR", "CallService", "service lost callback failed id=$id: $e")
}
LogManager.addLog("INFO", "CallService", "destroyed id=$id cleanupComplete=${released.isCompleted}")
LogManager.addLog("INFO", "CallService", "destroyed id=$id cleanupComplete=${pendingCleanup !== this}")
} finally { super.onDestroy() }
}