Unable to resume activity: java.util.ConcurrentModificationException in Remote Config #5439
Open
Description
opened on Oct 18, 2023
- Android Studio version: Android Studio Giraffe | 2022.3.1
- Firebase Component: Remote Config
- Component version: 21.4.1 (BOM 32.2.2)
I'm seeing a crash from my bug tracker that appears to be coming from remote config, here's the stack trace:
java.util.ConcurrentModificationException: null
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:760)
at java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:782)
at com.google.firebase.remoteconfig.internal.ConfigRealtimeHttpClient.propagateErrors(ConfigRealtimeHttpClient.java:225)
at com.google.firebase.remoteconfig.internal.ConfigRealtimeHttpClient.makeRealtimeHttpConnection(ConfigRealtimeHttpClient.java:387)
at com.google.firebase.remoteconfig.internal.ConfigRealtimeHttpClient.startHttpConnection(ConfigRealtimeHttpClient.java:355)
at com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler.beginRealtime(ConfigRealtimeHandler.java:81)
at com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler.setBackgroundState(ConfigRealtimeHandler.java:96)
at com.google.firebase.remoteconfig.FirebaseRemoteConfig.setConfigUpdateBackgroundState(FirebaseRemoteConfig.java:674)
at com.google.firebase.remoteconfig.RemoteConfigComponent.notifyRCInstances(RemoteConfigComponent.java:341)
at com.google.firebase.remoteconfig.RemoteConfigComponent.access$100(RemoteConfigComponent.java:60)
at com.google.firebase.remoteconfig.RemoteConfigComponent$GlobalBackgroundListener.onBackgroundStateChanged(RemoteConfigComponent.java:363)
at com.google.android.gms.common.api.internal.BackgroundDetector.zza(com.google.android.gms:play-services-basement@@18.2.0:3)
at com.google.android.gms.common.api.internal.BackgroundDetector.onActivityResumed(com.google.android.gms:play-services-basement@@18.2.0:3)
at android.app.Application.dispatchActivityResumed(Application.java:450)
at android.app.Activity.dispatchActivityResumed(Activity.java:1482)
at android.app.Activity.onResume(Activity.java:2043)
at com.truescreen.android.MainActivity.onResume(MainActivity.kt:280)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1531)
at android.app.Activity.performResume(Activity.java:8734)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:5351)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:5444)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8757)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
java.lang.RuntimeException: Unable to resume activity {com.truescreen.app/com.truescreen.android.MainActivity}: java.util.ConcurrentModificationException
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:5378)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:5444)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8757)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
From the stack trace itself it's hard to tell exactly where the issue arises. Some code I use from remote config:
private val configCoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val configStatus: MutableStateFlow<ConfigStatus> =
MutableStateFlow(ConfigStatus.Uninitialized)
private enum class ConfigStatus {
Uninitialized, DefaultsReady, RemoteReady
}
override val appUrls = configStatus.filter {
it == ConfigStatus.DefaultsReady || it == ConfigStatus.RemoteReady
}.flatMapLatest {
streamRemoteConfig(
setOf(
"example", "test"
)
).retryWithExponentialBackoff(onError = {
Timber.w(it)
})
}.map {
ExampleData(
example = getString("example"),
test = getString("test"),
)
}
private fun streamRemoteConfig(keys: Set<String>): Flow<FirebaseRemoteConfig> {
return callbackFlow {
val listener = object : ConfigUpdateListener {
override fun onUpdate(configUpdate: ConfigUpdate) {
Firebase.remoteConfig.activate()
if (configUpdate.updatedKeys.intersect(keys).isNotEmpty()) {
runBlocking {
send(Firebase.remoteConfig)
}
}
}
override fun onError(error: FirebaseRemoteConfigException) {
close(error)
}
}
send(Firebase.remoteConfig)
val registration = Firebase.remoteConfig.addOnConfigUpdateListener(listener)
awaitClose {
registration.remove()
}
}
}
override fun initialize() {
configCoroutineScope.launch {
retryWithExponentialBackoff {
Firebase.remoteConfig.setDefaultsAsync(
mapOf(
// Here i set some defaults...
)
).await()
configStatus.value = ConfigStatus.DefaultsReady
}
retryWithExponentialBackoff {
Firebase.remoteConfig.fetch(0).await()
Firebase.remoteConfig.activate()
configStatus.value = ConfigStatus.RemoteReady
}
}
}
Activity