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