firebase / firebase-android-sdk

Firebase Android SDK
https://firebase.google.com
Apache License 2.0
2.26k stars 572 forks source link

RemoteConfigComponent and FirebaseMessaging return null for some users #5691

Open wdziemia opened 7 months ago

wdziemia commented 7 months ago

Step 2: Describe your environment

[REQUIRED] Step 3: Describe the problem

https://github.com/firebase/firebase-android-sdk/blob/5ef5cdda14666df3f6727719f4d3344c8286ef32/firebase-config/src/main/java/com/google/firebase/remoteconfig/FirebaseRemoteConfig.java#L87

The code block above returns null for about ~1,500 users a day when we attempt to configure RemoteConfig. We are forced to check if RemoteConfigComponent is available before calling the config-ktx helper function:

firebase.get(RemoteConfigComponent::class.java) != null

and when we dont we see the following crash in production.

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'dbxyzptlk.h41.g dbxyzptlk.h41.k.d()' on a null object reference
        at com.google.firebase.remoteconfig.FirebaseRemoteConfig.getInstance(FirebaseRemoteConfig.java:86)
        at com.google.firebase.remoteconfig.ktx.RemoteConfigKt.remoteConfig(RemoteConfig.kt:32)

We also see the same behavior when it comes to getting the FirebaseMessaging and do a similar check:

firebase.get(FirebaseMessaging::class.java) != null

I do see the ComponentDiscoveryService have the Registrars populated for Messaging and RemoteConfig as well:

image

google-oss-bot commented 7 months ago

I found a few problems with this issue:

lehcar09 commented 7 months ago

Hi @wdziemia, thank you for reaching out. I've been trying to reproduce this issue but haven't been successful. Below is how I initialize the RemoteConfig instance.

MainActivity.kt

//Initialization
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_layout)

        FirebaseApp.initializeApp(this)
        remoteConfig = FirebaseRemoteConfig.getInstance(FirebaseApp.getInstance())
    }

Any chance you could provide detailed steps to reproduce the issue or an MCVE where the issue is reproducible? Aside from that, does the issue occur on a specific set of users or devices?

wdziemia commented 7 months ago

@lehcar09 Hello! Yes we initialize RC similarly. We use dagger though so its a bit more indirect than your example but the calls and flow are the same. I dont know how to reproduce this issue locally but can provide more details:

We have a more aggressive fetch for Firebase Messaging which uses some exponential backoff with an interval of 10ms delay between checking if Firebase Messaging returns an instance or null. There is a max delay between checks being 1000ms. Ive set up some metrics to track the total duration it takes to return the Messaging component and have some prelim data below. This data should be of Developer & Alpha users (<200). I will update once this build hits beta and prod environments.

Screenshot 2024-02-09 at 10 55 41 AM

google-oss-bot commented 7 months ago

Hey @wdziemia. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

wdziemia commented 7 months ago

Some data over the last 24 hours - Firebase Messaging shows the following:

Screenshot 2024-02-15 at 9 03 46 PM

lehcar09 commented 7 months ago

Hi @wdziemia, sorry for the hold up. I can't say for sure if this is due to lazy initialization. Based on your description, it seems like you're using Dagger to initialize Firebase. Something like:

@Provides
@Singleton
fun provideFirebaseRC(@ApplicationContext appContext: Context): FirebaseRemoteConfig {
   FirebaseApp.initializeApp(appContext)
   return FirebaseRemoteConfig.getInstance(FirebaseApp.getInstance())
}

Just to note, FirebaseInitProvider initializes Firebase APIs at app startup time, not being able to initialize them properly (considering the inter-dependency) might cause conflicts. Also, as per the documentation of FirebaseApp:

Any FirebaseApp initialization must occur only in the main process of the app. Use of Firebase in processes other than the main process is not supported and will likely cause problems related to resource contention.

Useful References

Take Control of Your Firebase Init on Android How does Firebase initialize on Android?

Can you share how and when are you calling FirebaseApp.initializeApp() and FirebaseMessaging.getInstance()? Is your app a multi process app?

wdziemia commented 6 months ago

We are calling it as part of our Dagger object graph creation which is done in Applicaiton.onCreate(), there are no calls to use Firebase / RemoteConfig / Messaging that are outside of dependency injections. I also see no usages of android:process in the codebase.

Messaging shows the following results, with an overall 23.6% success rate in returning an instance, this number is quite a surprise.

Screenshot 2024-03-11 at 7 33 25 PM

Remote Config has about 1300 instances of being unavailable during Application.onCreate() - this is a relatively small number compared to the amount of app starts per day we have (~5 million)