xref: /aosp_15_r20/external/kotlinx.coroutines/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)
1 package kotlinx.coroutines.debug
2 
3 import android.annotation.*
4 import kotlinx.coroutines.debug.internal.*
5 import org.codehaus.mojo.animal_sniffer.*
6 import sun.misc.*
7 import java.lang.instrument.*
8 import java.lang.instrument.ClassFileTransformer
9 import java.security.*
10 
11 /*
12  * This class is loaded if and only if kotlinx-coroutines-core was used as -javaagent argument,
13  * but Android complains anyway (java.lang.instrument.*), so we suppress all lint checks here
14  */
15 @Suppress("unused")
16 @SuppressLint("all")
17 @IgnoreJRERequirement // Never touched on Android
18 internal object AgentPremain {
19 
<lambda>null20     private val enableCreationStackTraces = runCatching {
21         System.getProperty("kotlinx.coroutines.debug.enable.creation.stack.trace")?.toBoolean()
22     }.getOrNull() ?: DebugProbesImpl.enableCreationStackTraces
23 
24     @JvmStatic
25     @Suppress("UNUSED_PARAMETER")
premainnull26     fun premain(args: String?, instrumentation: Instrumentation) {
27         AgentInstallationType.isInstalledStatically = true
28         instrumentation.addTransformer(DebugProbesTransformer)
29         DebugProbesImpl.enableCreationStackTraces = enableCreationStackTraces
30         DebugProbesImpl.install()
31         installSignalHandler()
32     }
33 
34     internal object DebugProbesTransformer : ClassFileTransformer {
transformnull35         override fun transform(
36             loader: ClassLoader?,
37             className: String,
38             classBeingRedefined: Class<*>?,
39             protectionDomain: ProtectionDomain,
40             classfileBuffer: ByteArray?
41         ): ByteArray? {
42             if (loader == null || className != "kotlin/coroutines/jvm/internal/DebugProbesKt") {
43                return null
44             }
45             /*
46              * DebugProbesKt.bin contains `kotlin.coroutines.jvm.internal.DebugProbesKt` class
47              * with method bodies that delegate all calls directly to their counterparts in
48              * kotlinx.coroutines.debug.DebugProbesImpl. This is done to avoid classfile patching
49              * on the fly (-> get rid of ASM dependency).
50              * You can verify its content either by using javap on it or looking at out integration test module.
51              */
52             AgentInstallationType.isInstalledStatically = true
53             return loader.getResourceAsStream("DebugProbesKt.bin").readBytes()
54         }
55     }
56 
installSignalHandlernull57     private fun installSignalHandler() {
58         try {
59             Signal.handle(Signal("TRAP")) { // kill -5
60                 if (DebugProbesImpl.isInstalled) {
61                     // Case with 'isInstalled' changed between this check-and-act is not considered
62                     // a real debug probes use-case, thus is not guarded against.
63                     DebugProbesImpl.dumpCoroutines(System.out)
64                 } else {
65                     println("Cannot perform coroutines dump, debug probes are disabled")
66                 }
67             }
68         } catch (t: Throwable) {
69             // Do nothing, signal cannot be installed, e.g. because we are on Windows
70         }
71     }
72 }
73