sk eat
12/04/2024, 6:22 AMsk eat
12/04/2024, 6:25 AMBroadcastReceiver
and a ForegroundService
. There seems to be a discrepancy between the metrics collected inside and outside a coroutine, and I would appreciate your insights or advice.
Code:
class SampleForegroundService : Service() {
init {
startReceiver()
}
private fun startReceiver() {
val filter = IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_ON)
}
SampleReceiver.getInstance().let { receiver ->
ContextCompat.registerReceiver(
this,
receiver,
filter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
class SampleReceiver : BroadcastReceiver() {
private val externalScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
override fun onReceive(context: Context?, intent: Intent?) {
if(intent?.action == Intent.ACTION_SCREEN_ON) {
reportOutCoroutine()
reportInCoroutine()
}
}
private fun reportOutCoroutine() {
// Reporting code
}
private fun reportInCoroutine() = externalScope.launch {
runCatching {
sampleUseCase()
}.onSuccess {
// Reporting code
}.onFailure {
// Failure reporting code
}
}
companion object {
private var instance: LockReceiver? = null
fun getInstance(): LockReceiver {
return instance ?: synchronized(this) {
instance ?: LockReceiver().also {
instance = it
}
}
}
}
}
Issue:
1. There is a discrepancy between the metrics collected by reportOutCoroutine()
and reportInCoroutine()
.
2. The metric count from reportOutCoroutine is consistently higher.
3. Even under identical app versions and OS environments, there is about a 10% difference between the two metrics.
Additional Information:
• SampleForegroundService
is rarely destroyed. If it is, it gets recreated using AlarmManager
.
• I initially suspected a memory leak in externalScope
, but this would primarily impact resource usage over time and not the execution of coroutines.
• The discrepancy remains consistent across devices and configurations.
Question:
• Why might there be a difference in metrics between reportOutCoroutine
and reportInCoroutine
?
• Have you experienced a similar issue, or do you have any suggestions on how to investigate or resolve this?
Any advice or insights would be greatly appreciated. Thank you in advance for your help! 😊streetsofboston
12/04/2024, 3:31 PMdelay(1000)
(or even a bit larger delay) as the first statement inside your externalScope.launch { ... }
block. Does the discrepancy go even higher (more than 10%). If so, maybe the externalScope
gets cancelled (not so likely) or the dispatcher may get starved...?
Overall, BroadcastReceivers should do very very little work. If something needs to run in a background thread based on an event that is received by a BroadcastReceiver, an (Intent)Service should do the actual (background) work.Peter Farlow
12/06/2024, 3:51 PMreportInCoroutine()
wraps it with runCatching
which breaks coroutine cancellation https://kotlinlang.slack.com/archives/C1CFAFJSK/p1679326509883299sk eat
12/09/2024, 1:24 AMCoroutineScope
is canceled, the onFailure
block in runCatching
does not log the event, which leads to a discrepancy in metrics. Thank you for the detailed explanation so far!
I have an additional question:
In the sample code below, the CoroutineScope
is declared as a member variable of a singleton instance
. It uses SupervisorJob
to prevent cancellation from child coroutines, and no explicit cancellation is being performed.
Are there any scenarios in which this scope could still be canceled?
Additionally, I’d appreciate any advice on how to ensure the scope remains stable or solutions to prevent such issues. 😊streetsofboston
12/09/2024, 3:19 AMsk eat
12/18/2024, 1:15 AM