Last active
March 13, 2021 08:17
-
-
Save johnsonlee/154671b11f7e8c068aa6966ac72aeb7f to your computer and use it in GitHub Desktop.
DDMS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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