[READ] Step 1: Are you in the right place?
Issues filed here should be about bugs in the code in this repository.
If you have a general question, need help debugging, or fall into some
other category use one of these other channels:
- For general technical questions, post a question on StackOverflow
with the firebase tag.
- For general Firebase discussion, use the firebase-talk
google group.
- For help troubleshooting your application that does not fall under one
of the above categories, reach out to the personalized
Firebase support channel.
[REQUIRED] Step 2: Describe your environment
- Android Studio version: Android Studio Ladybug Feature Drop | 2024.2.2 Canary 7
- Firebase Component: Performance (com.google.firebase:firebase-perf)
- Component version: 21.0.2 (Firebase BOM 33.4.0)
[REQUIRED] Step 3: Describe the problem
Steps to reproduce:
Every firebase performance trace function call makes the following check while starting a trace.
|
if (!ConfigResolver.getInstance().isPerformanceMonitoringEnabled()) { |
This check calls the following function:
https://github.com/firebase/firebase-android-sdk/blob/main/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigResolver.java#L207-L209
And this call reaches to the following function that edits a shared preference and applies the change.
This is done for every trace.
https://github.com/firebase/firebase-android-sdk/blob/main/firebase-perf/src/main/java/com/google/firebase/perf/config/DeviceCacheManager.java#L133-L146
If network performance traces are enabled, screen traces are enabled and if you have some custom traces, you end up with hundreds of calls to trace start function which edits preferences and calls apply function.
Since apply does the persistence in a background thread we can think that it is safe and it will not cause any issues in main thread. However, it has a significant impact on main thread and it causes significant number of ANRs. In our 9 applications this ANR is in top 3. We identified that more than 80% of SharedPreferencesImpl.apply calls are coming from firebase performance library among all the calls to the apply function.
Every apply function calls creates a task to be awaited by QueuedWork which is an internal utility class to keep track of process-global work that’s outstanding and hasn’t been finished yet.This was created for writing SharedPreference edits out asynchronously so we’d have a mechanism to wait for the writes in Activity.onPause and similar places, but we may use this mechanism for other things in the future. (This is from documentation)
https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/android/app/SharedPreferencesImpl.java#503
When activity is stopped and if you have several pending work that are scheduled through several apply functions, then QueuedWork runs all the remaining task on main thread to ensure that all shared preferences are persisted. As expected in some cases this is causing ANRs. This ANRs become more visible when a new ANR reporting is included with Android 14.
Here is a screenshot of a trace for this scenario.
I think reducing the usage of shared preferences apply usage and finding a more performant check for isPerformanceMonitoringEnabled could be the solution. Rather then calling this function every time maybe we can consider caching the value which will prevent excessive calls to SharedPreferences.apply function.
Relevant Code:
com.google.firebase.perf.trace("test_trace") {
test()
}
[READ] Step 1: Are you in the right place?
Issues filed here should be about bugs in the code in this repository.
If you have a general question, need help debugging, or fall into some
other category use one of these other channels:
with the firebase tag.
google group.
of the above categories, reach out to the personalized
Firebase support channel.
[REQUIRED] Step 2: Describe your environment
[REQUIRED] Step 3: Describe the problem
Steps to reproduce:
Every firebase performance
tracefunction call makes the following check while starting a trace.firebase-android-sdk/firebase-perf/src/main/java/com/google/firebase/perf/metrics/Trace.java
Line 209 in a00c310
This check calls the following function:
https://github.com/firebase/firebase-android-sdk/blob/main/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigResolver.java#L207-L209
And this call reaches to the following function that edits a shared preference and applies the change.
This is done for every trace.
https://github.com/firebase/firebase-android-sdk/blob/main/firebase-perf/src/main/java/com/google/firebase/perf/config/DeviceCacheManager.java#L133-L146
If network performance traces are enabled, screen traces are enabled and if you have some custom traces, you end up with hundreds of calls to trace start function which edits preferences and calls apply function.
Since apply does the persistence in a background thread we can think that it is safe and it will not cause any issues in main thread. However, it has a significant impact on main thread and it causes significant number of ANRs. In our 9 applications this ANR is in top 3. We identified that more than 80% of
SharedPreferencesImpl.applycalls are coming from firebase performance library among all the calls to the apply function.Every apply function calls creates a task to be awaited by
QueuedWorkwhich is an internal utility class to keep track of process-global work that’s outstanding and hasn’t been finished yet.This was created for writing SharedPreference edits out asynchronously so we’d have a mechanism to wait for the writes in Activity.onPause and similar places, but we may use this mechanism for other things in the future. (This is from documentation)https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/android/app/SharedPreferencesImpl.java#503
When activity is stopped and if you have several pending work that are scheduled through several apply functions, then
QueuedWorkruns all the remaining task on main thread to ensure that all shared preferences are persisted. As expected in some cases this is causing ANRs. This ANRs become more visible when a new ANR reporting is included with Android 14.Here is a screenshot of a trace for this scenario.
I think reducing the usage of shared preferences apply usage and finding a more performant check for
isPerformanceMonitoringEnabledcould be the solution. Rather then calling this function every time maybe we can consider caching the value which will prevent excessive calls toSharedPreferences.applyfunction.Relevant Code:
com.google.firebase.perf.trace("test_trace") { test() }