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