Skip to content

Instantly share code, notes, and snippets.

@johnsonlee
Last active March 13, 2021 08:17
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnsonlee/154671b11f7e8c068aa6966ac72aeb7f to your computer and use it in GitHub Desktop.
Save johnsonlee/154671b11f7e8c068aa6966ac72aeb7f to your computer and use it in GitHub Desktop.
DDMS
#!/usr/bin/env kotlinc -script --
@file:Repository("https://dl.google.com/dl/android/maven2/")
@file:DependsOn("com.android.tools.ddms:ddmlib:27.1.0")
import com.android.ddmlib.*
import com.android.ddmlib.internal.*
import java.io.*
import java.util.concurrent.*
import kotlin.system.*
fun waitForDevice(): IDevice {
val signal = CountDownLatch(1)
var remote: IDevice? = null
AndroidDebugBridge.addDeviceChangeListener(object : AndroidDebugBridge.IDeviceChangeListener {
override fun deviceChanged(device: IDevice, mask: Int) {
if (0 != (mask and IDevice.CHANGE_CLIENT_LIST)) {
AndroidDebugBridge.removeDeviceChangeListener(this)
remote = device
signal.countDown()
}
}
override fun deviceDisconnected(device: IDevice) = Unit
override fun deviceConnected(device: IDevice) = Unit
})
val exe = System.getenv("PATH").split(':').map {
File(it, "adb")
}.firstOrNull(File::exists)?.canonicalPath ?: error("adb not found")
AndroidDebugBridge.createBridge(exe, true, Long.MAX_VALUE, TimeUnit.MILLISECONDS)
signal.await()
return remote!!
}
fun IDevice.watchThread(app: String) {
println("* ${serialNumber} ${name} ${version} ${state}")
clients.filterIsInstance(ClientImpl::class.java).filter {
it.clientData.packageName == app
}.forEach { client ->
// enable thread update
client.isThreadUpdateEnabled = true
// request thread update
val signal = CountDownLatch(1)
AndroidDebugBridge.addClientChangeListener(object : AndroidDebugBridge.IClientChangeListener {
var lastSize = 0
override fun clientChanged(client: Client, mask: Int) {
val threads = client.clientData.threads.takeIf {
val result = it.size == lastSize
lastSize = it.size
result
} ?: return
AndroidDebugBridge.removeClientChangeListener(this)
println("""
|-------------------------------------------------------------------------------------
| id | tid | stime | utime | name
|------+---------+---------+---------+------------------------------------------------
""".trimMargin())
threads.forEach { thread ->
println("${if (thread.isDaemon) "*" else " "}${thread.threadId.toString().padStart(4)} | ${thread.tid.toString().padStart(7)} | ${thread.stime.toString().padStart(7)} | ${thread.utime.toString().padStart(7)} | ${thread.threadName}")
}
signal.countDown()
}
})
client.requestThreadUpdate()
signal.await()
}
}
if (args.isEmpty()) {
println("application name is required")
} else {
AndroidDebugBridge.init(true)
waitForDevice().watchThread(args[0])
}
exitProcess(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment