summaryrefslogtreecommitdiff
path: root/debugger-tests/src/com/android/tools/debuggertests/Debugger.kt
diff options
context:
space:
mode:
Diffstat (limited to 'debugger-tests/src/com/android/tools/debuggertests/Debugger.kt')
-rw-r--r--debugger-tests/src/com/android/tools/debuggertests/Debugger.kt80
1 files changed, 80 insertions, 0 deletions
diff --git a/debugger-tests/src/com/android/tools/debuggertests/Debugger.kt b/debugger-tests/src/com/android/tools/debuggertests/Debugger.kt
new file mode 100644
index 0000000000..f1044c2390
--- /dev/null
+++ b/debugger-tests/src/com/android/tools/debuggertests/Debugger.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tools.debuggertests
+
+import com.sun.jdi.Bootstrap.virtualMachineManager
+import com.sun.jdi.VirtualMachine
+import com.sun.jdi.connect.Connector
+import com.sun.jdi.event.ClassPrepareEvent
+import com.sun.jdi.event.Event
+import com.sun.jdi.event.VMStartEvent
+
+private const val LAUNCH_CONNECTOR = "com.sun.jdi.CommandLineLaunch"
+private const val ATTACH_CONNECTOR = "com.sun.jdi.SocketAttach"
+
+/** A simple JDI client that can set a breakpoint */
+internal class Debugger private constructor(private val vm: VirtualMachine) {
+
+ private val requestManager = vm.eventRequestManager()
+ private val eventChannel = EventChannel(vm.eventQueue())
+
+ suspend fun start() {
+ eventChannel.receive<VMStartEvent>()
+ }
+
+ /** Resume execution and return the next event. */
+ suspend inline fun <reified T : Event> resume(): T {
+ vm.resume()
+ return eventChannel.receive()
+ }
+
+ /** Set a breakpoint */
+ suspend fun setBreakpoint(className: String, line: Int) {
+ requestManager.createClassPrepareRequest().apply {
+ addClassFilter(className)
+ addCountFilter(1)
+ enable()
+ }
+ val event = resume<ClassPrepareEvent>()
+
+ requestManager
+ .createBreakpointRequest(event.referenceType().locationsOfLine(line).first())
+ .apply { enable() }
+ }
+
+ companion object {
+
+ fun launch(mainClass: String, classpath: String): Debugger {
+ val connector = virtualMachineManager().launchingConnectors().named(LAUNCH_CONNECTOR)
+ val arguments = connector.defaultArguments()
+ arguments["main"]?.setValue("MainKt $mainClass")
+ arguments["options"]?.setValue("-classpath $classpath")
+ return Debugger(connector.launch(arguments))
+ }
+
+ fun attachToProcess(hostname: String, port: Int): Debugger {
+ val connector = virtualMachineManager().attachingConnectors().named(ATTACH_CONNECTOR)
+ val arguments = connector.defaultArguments()
+ arguments["hostname"]?.setValue(hostname)
+ (arguments["port"] as? Connector.IntegerArgument)?.setValue(port)
+ return Debugger(connector.attach(arguments))
+ }
+ }
+}
+
+private inline fun <reified T : Connector> List<T>.named(name: String): T = first {
+ it.name() == name
+}