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