Anamorphosee / stacktrace-decoroutinator

Small lib for recovering stack trace in exceptions thrown in Kotlin coroutines
Apache License 2.0
158 stars 4 forks source link

Android: InternalError: Attempt to register dex file /data/user/.../<EMAIL_ADDRESS> with multiple class loaders #29

Open nordfalk opened 3 weeks ago

nordfalk commented 3 weeks ago

After rolling out a version with SD to a small fraction of our users on Google Play we see crashes at startup: image

The trace is always the same:

Exception java.lang.InternalError: Attempt to register dex file /data/user/0/dk.dinero.android/<EMAIL_ADDRESS> with multiple class loaders
  at dalvik.system.DexFile.defineClassNative
  at dalvik.system.DexFile.defineClass (DexFile.java:328)
  at dalvik.system.DexFile.loadClassBinaryName (DexFile.java:321)
  at dalvik.system.DexPathList$Element.findClass (DexPathList.java:775)
  at dalvik.system.DexPathList.findClass (DexPathList.java:532)
  at dalvik.system.BaseDexClassLoader.findClass (BaseDexClassLoader.java:245)
  at java.lang.ClassLoader.loadClass (ClassLoader.java:379)
  at java.lang.ClassLoader.loadClass (ClassLoader.java:312)
  at dev.reformator.stacktracedecoroutinator.runtime.DecoroutinatorRuntime.load (runtime-android.kt:52)
  at dev.reformator.stacktracedecoroutinator.runtime.DecoroutinatorRuntime.load$default (runtime-android.kt:25)
  at dk.dinero.dinero.DineroApp.<init> (DineroApp.kt:46)

To me it seems that somehow dex_file becomes something with at https://android.googlesource.com/platform/art/+/refs/heads/master/runtime/class_linker.cc#3432

Its not tied to a specific Android version: image

Nor device vendor: image

nordfalk commented 2 weeks ago

Hello again, it turns out that it was probably Google Play that masked the exception and hided something with @ that looked like an email adress :rofl:

The real exception is:

java.lang.InternalError: Attempt to register dex file /data/user/0/dk.dinero.android/Anonymous-DexFile@188495102.jar with multiple class loaders
    at dalvik.system.DexFile.defineClassNative(Native Method)
    at dalvik.system.DexFile.defineClass(DexFile.java:328)
    at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:321)
    at dalvik.system.DexPathList$Element.findClass(DexPathList.java:775)
    at dalvik.system.DexPathList.findClass(DexPathList.java:532)
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:245)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    at dev.reformator.stacktracedecoroutinator.runtime.DecoroutinatorRuntime.load(runtime-android.kt:175)
    at dev.reformator.stacktracedecoroutinator.runtime.DecoroutinatorRuntime.load$default(runtime-android.kt:16)
    at dk.dinero.dinero.DineroApp.<init>(DineroApp.kt:19)

Any ideas?

I dont know if it helps, but I am logging the classloader.toString().

Here you have an example of it when it fails with the above exception dalvik.system.PathClassLoader[DexPathList[[dex file "InMemoryDexFile[cookie=[0, -5476376637481455120]]", zip file "/data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/base.apk", zip file "/data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/split_config.arm64_v8a.apk", zip file "/data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/split_config.da.apk", zip file "/data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/split_config.xxhdpi.apk"],nativeLibraryDirectories=[/data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/lib/arm64, /data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/base.apk!/lib/arm64-v8a, /data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/split_config.arm64_v8a.apk!/lib/arm64-v8a, /data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/split_config.da.apk!/lib/arm64-v8a, /data/app/~~KJ8JyQFydoxB7WNVmVqUpQ==/dk.dinero.android-bowEEPOORFOOVUQiikWYgg==/split_config.xxhdpi.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]]]

here is an example when it doesent fail: dalvik.system.PathClassLoader[DexPathList[[dex file "InMemoryDexFile[cookie=[531515716432, 530979610896]]", zip file "/data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/base.apk", zip file "/data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/split_config.arm64_v8a.apk", zip file "/data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/split_config.da.apk", zip file "/data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/split_config.xxhdpi.apk"],nativeLibraryDirectories=[/data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/lib/arm64, /data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/base.apk!/lib/arm64-v8a, /data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/split_config.arm64_v8a.apk!/lib/arm64-v8a, /data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/split_config.da.apk!/lib/arm64-v8a, /data/app/~~1fWzNIhgdry_D1AYgyucAw==/dk.dinero.android-RInUf0k5pf31i2uVjIR0tw==/split_config.xxhdpi.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]]]

If looked thru a lot of failing and non-failing cases. Seems the ratio is 10 to 1. The only difference I can see is that cookie=[0, appears in all failing cases. But it also sometimes appears in non-failing cases.

Heres an example screenshot of logs on different devices and users: image

If you study it you will see that the error only appears sometimes, even for the same user on the same device.

Note that even if I catch the exception in DecoroutinatorRuntime.load() the app will crash at the first time a coroutine is being used.

For example:

java.lang.InternalError: Attempt to register dex file /data/user/0/dk.dinero.android/Anonymous-DexFile@188495102.jar with multiple class loaders
    at androidx.work.CoroutineWorker.startWork(CoroutineWorker.kt:17)
    at androidx.work.impl.h0$a.run(WorkerWrapper.java:55)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:230)
    at android.os.Looper.loop(Looper.java:319)

or

java.lang.InternalError: Attempt to register dex file /data/user/0/dk.dinero.android/Anonymous-DexFile@188495102.jar with multiple class loaders
    at dk.dinero.dinero.app.navigation.NavigationViewModel.h(NavigationViewModel.kt:12)
    at dk.dinero.dinero.app.navigation.NavigationActivity.onCreate(NavigationActivity.kt:61)
    at android.app.Activity.performCreate(Activity.java:8944)
    at android.app.Activity.performCreate(Activity.java:8913)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4146)
nordfalk commented 5 days ago

@Anamorphosee does the above give you any hints?

Could it be a concurrency issue - that something else in the app (a library) is initializing something that starts a coroutine before SD has finished its initialization ?

In case SD fails initialization, would there be some possibility to roll back the initialization so that the rest of the app would work and not crash when using coroutines ?