android-client-sdk icon indicating copy to clipboard operation
android-client-sdk copied to clipboard

LDConfig.java line 36 com.launchdarkly.sdk.android.LDConfig.<clinit>

Open mohanK22 opened this issue 3 years ago • 8 comments

Hi LaunchDarkly Team,

We are getting the following the ANR report in our firebase crashlytics.

Logs as per Firebase Crashlytics

main (runnable): tid=1 systid=14022 at com.google.gson.Gson.(Gson.java:202) at com.google.gson.GsonBuilder.create(GsonBuilder.java:597) at com.launchdarkly.sdk.android.LDConfig.(LDConfig.java:36) at com.launchdarkly.sdk.android.LDConfig$Builder.(LDConfig.java:299) at com.tatadigital.tcp.common.di.AppModule.provideLaunchDarklyInstance(AppModule.java:831) at com.tatadigital.tcp.common.di.AppModule_ProvideLaunchDarklyInstanceFactory.provideLaunchDarklyInstance(AppModule_ProvideLaunchDarklyInstanceFactory.java:42) at com.tatadigital.tcp.DaggerTcpApplication_HiltComponents_SingletonC$SwitchingProvider.get(DaggerTcpApplication_HiltComponents_SingletonC.java:11475) at dagger.internal.DoubleCheck.get(DoubleCheck.java:47) at com.tatadigital.tcp.DaggerTcpApplication_HiltComponents_SingletonC.injectTcpApplication2(DaggerTcpApplication_HiltComponents_SingletonC.java:2177) at com.tatadigital.tcp.DaggerTcpApplication_HiltComponents_SingletonC.injectTcpApplication(DaggerTcpApplication_HiltComponents_SingletonC.java:2143) at com.tatadigital.tcp.Hilt_TcpApplication.onCreate(Hilt_TcpApplication.java:43) at com.tatadigital.tcp.TcpApplication.onCreate(TcpApplication.java:48) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1192) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7294) at android.app.ActivityThread.access$1700(ActivityThread.java:299) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2184) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:264) at android.app.ActivityThread.main(ActivityThread.java:8312) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:632) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)

Implementation

We are using the hilt library in our project and the following function is created in the AppModule class which is annotated with @Module and @InstallIn(SingletonComponent::class).

    @Provides
    fun provideLaunchDarklyInstance(@ApplicationContext appContext: Context): LDClient {
        val ldConfig: LDConfig = LDConfig.Builder()
            .mobileKey(BuildConfig.LD_KEY)
            .build()

        val user: LDUser = LDUser.Builder(LD_USER_KEY)
            .custom(TEST_KEY_1, TEST_VALUE_1)
            .custom(TEST_KEY_2, TEST_VALUE_2)
            .build()

        return LDClient.init(appContext as MyApplication, ldConfig, user, 0)
    }

In our application class, we are just injecting the ldClient object.

@Inject
lateinit var ldClient: LDClient

SDK version We are using launchDarkly SDK version 3.1.1 implementation 'com.launchdarkly:launchdarkly-android-client-sdk:3.1.1'

Let me know if you need more information. Thank you

mohanK22 avatar May 23 '22 11:05 mohanK22

Hello @mohanK22, I have a couple of questions to try to narrow down the issue.

Does this happen every time, or only occasionally? If the ANR doesn't happen every time, does Firebase give you information about which kind of devices this method gives you ANR?

Based on the stack trace this is happening inside the GSON builder, and seems to be happening before any LaunchDarkly specific operations (seems you are building the LDConfig in order to set up the LDClient). I wonder does the GSON library has some non-deterministic issues when operating with hilt. ANR typically is related to slow or completely deadlock behavior in the main thread, and the line 202 in GSON is the constructors with lots of input arguments.

  Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
      Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
      boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
      boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
      LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
      int timeStyle, List<TypeAdapterFactory> builderFactories,
      List<TypeAdapterFactory> builderHierarchyFactories,
      List<TypeAdapterFactory> factoriesToBeAdded)

louis-launchdarkly avatar May 23 '22 21:05 louis-launchdarkly

As per firebase crashlytics, it occurs as soon as the app launches.

Screenshot 2022-05-25 at 12 10 29 PM

mohanK22 avatar May 25 '22 06:05 mohanK22

We addressed several synchronization issues in the 3.1.7 release. Please let us know if updating to this release helps.

eli-darkly avatar Aug 23 '22 20:08 eli-darkly

Hi @louis-launchdarkly I am still seeing this issue.

I am using Hilt, plus jetpack compose single activity.

Here is the code for the injection:

@InstallIn(SingletonComponent::class)
class AppModule {
    @Singleton
    @Provides
    fun providesLaunchDarkly(@ApplicationContext applicationContext: Context): LDClient {
        val ldConfig: LDConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
            .mobileKey(BuildConfig.LAUNCH_DARKLY)
            .build()
        val context = LDContext.create("context-key-123abc")
        return LDClient.init(applicationContext as HonestApplication, ldConfig, context, 5)
    }
}```

Here is the log for the crash:

`Fatal Exception: java.lang.NullPointerException
Attempt to invoke interface method 'java.lang.Object java.util.Map.get(java.lang.Object)' on a null object reference
com.launchdarkly.sdk.android.LDClient.init (LDClient.java:234)
com.mobile.honest.di.AppModule.providesLaunchDarkly (AppModule.kt:28)
com.mobile.honest.di.AppModule_ProvidesLaunchDarklyFactory.providesLaunchDarkly (AppModule_ProvidesLaunchDarklyFactory.java:51)
com.mobile.honest.DaggerHonestApplication_HiltComponents_SingletonC$SingletonCImpl$SwitchingProvider.get (DaggerHonestApplication_HiltComponents_SingletonC.java:1357)
dagger.internal.DoubleCheck.get (DoubleCheck.java:47)
com.mobile.honest.DaggerHonestApplication_HiltComponents_SingletonC$ViewModelCImpl$SwitchingProvider.get (DaggerHonestApplication_HiltComponents_SingletonC.java:1019)
dagger.hilt.android.internal.lifecycle.HiltViewModelFactory$1.create (HiltViewModelFactory.java:102)
androidx.lifecycle.AbstractSavedStateViewModelFactory.create (AbstractSavedStateViewModelFactory.kt:90)
dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.create (HiltViewModelFactory.java:114)
androidx.lifecycle.ViewModelProvider.get (ViewModelProvider.kt:184)`

JoaoPint0 avatar Feb 12 '24 10:02 JoaoPint0

Do we have any solution for this crash?

rccl-pranit avatar May 21 '24 09:05 rccl-pranit

Apologies for the delay in noticing your recent comments @JoaoPint0 and @rccl-pranit . For some reason Github wasn't giving me notifications for this issue.

Could you provide the versions of the SDK you are seeing the issue in?

@rccl-pranit, could you provide a snippet of your injection/provider?

tanderson-ld avatar Jun 11 '24 20:06 tanderson-ld

I tried to reproduce this issue in a rudimentary way, but didn't see it happen. Does it happen 100% of the time? Are you able to reproduce it on demand?

Here is the branch I used for trying to reproduce it.

A theory I have at the moment is this: The LDClient should be treated as a singleton and we recommend initializing it once as part of the base Application class creation. I am not an expert on Hilt, perhaps Hilt is trying to create multiple instances simultaneously or shortly after the LDClient singleton is closed and that is leading to this issue. I saw there is a Singleton annotation that Hilt has, perhaps that is critical here.

tanderson-ld avatar Jun 11 '24 22:06 tanderson-ld

@JoaoPint0 , do you ever close the LDClient in your application?

tanderson-ld avatar Jun 11 '24 22:06 tanderson-ld