Anamorphosee / stacktrace-decoroutinator

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

[despite using init] Android: Stacktrace-decoroutinator runtime can not be loaded because BaseContinuationImpl was already loaded. #27

Closed cee-dee closed 3 weeks ago

cee-dee commented 6 months ago

I've got this IllegalStateException although I'm using DecoroutinatorRuntime.load() in the init { } block of my Application class. In order to rule out that it is a general problem, I used an Android Studio template and created a simple sample app, added a custom MyApplication to the manifest and confirmed that DecoroutinatorRuntime.load() is not throwing.

To compare the initialization process of the two apps (the working and the not working one) I replaced the call to DecoroutinatorRuntime.load() with error("Error message"). It looks like it's exactly the same:

I noticed that the callstacks then load pretty identical:

Simple Sample App (Decoroutinator working)

Process: com.example.myapplication, PID: 21334
java.lang.RuntimeException: Unable to instantiate application com.example.myapplication.MyApplication package com.example.myapplication: 
java.lang.IllegalStateException: Error message
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1466)
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1395)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6959)
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: java.lang.IllegalStateException: Error message
    at com.example.myapplication.MyApplication.<init>(MyApplication.kt:8)
    at java.lang.Class.newInstance(Native Method)
    at android.app.AppComponentFactory.instantiateApplication(AppComponentFactory.java:76)
    at androidx.core.app.CoreComponentFactory.instantiateApplication(CoreComponentFactory.java:52)
    at android.app.Instrumentation.newApplication(Instrumentation.java:1282)
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1458)
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1395) 
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6959) 
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loopOnce(Looper.java:205) 
    at android.os.Looper.loop(Looper.java:294) 
    at android.app.ActivityThread.main(ActivityThread.java:8177) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 

my real app (Decoroutinator not working)

Process: de.company.android.component.alpha, PID: 26890
java.lang.RuntimeException: Unable to instantiate application de.company.android.component.MyApplication package de.check24.android.homes.alpha:
java.lang.IllegalStateException: Error message
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1466)
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1395)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6959)
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: java.lang.IllegalStateException: Error message
    at de.company.android.component.MyApplication.<init>(MyApplication.kt:18)
    at java.lang.Class.newInstance(Native Method)
    at android.app.AppComponentFactory.instantiateApplication(AppComponentFactory.java:76)
    at androidx.core.app.CoreComponentFactory.instantiateApplication(CoreComponentFactory.java:51)
    at android.app.Instrumentation.newApplication(Instrumentation.java:1282)
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1458)
    at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1395) 
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6959) 
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loopOnce(Looper.java:205) 
    at android.os.Looper.loop(Looper.java:294) 
    at android.app.ActivityThread.main(ActivityThread.java:8177) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 

Any ideas how I can find out what is causing this or how to fix this? I could imagine that some part of the app is doing some static initialization and is using Coroutines there. But since it is a huge codebase, I don't have a clue how I could start investigating on that -- exchanging the ClassLoader and setting a breakpoint has the same issue: it's already too late.

Anamorphosee commented 6 months ago

@cee-dee Maybe you can add a breakpoint on the constructor of the class kotlin.coroutines.jvm.internal.BaseContinuationImpl to try to figure out when this class loads initially.

cee-dee commented 6 months ago

Thank's for the awesome speed of your support! I've already tried to set breakpoints, but either no breakpoint actually breaks, or it never reaches the init block of my App.

This setup with emulated breakpoints (basically) never reaches the init block: BaseContinuationImpl

Do you have a concrete suggestion of where I should set breakpoints?

cee-dee commented 4 months ago

Is there anything else I can try to find the cause?

Anamorphosee commented 1 month ago

@cee-dee Just released SD version 2.4.1 with a big rework for Android. From now on SD for Android requires only the Gradle plugin and no other dependencies or method calls are required.