The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | <html> |
| 2 | <head> |
| 3 | <title>Dalvik Debugger Support</title> |
| 4 | </head> |
| 5 | |
| 6 | <body> |
| 7 | <h1>Dalvik Debugger Support</h1> |
| 8 | |
| 9 | <p> |
| 10 | The Dalvik virtual machine supports source-level debugging with many popular |
| 11 | development environments. Any tool that allows remote debugging over JDWP |
| 12 | (the |
| 13 | <a href="http://java.sun.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html"> |
| 14 | Java Debug Wire Protocol</a>) is expected work. Supported debuggers |
| 15 | include jdb, Eclipse, IntelliJ, and JSwat. |
| 16 | </p><p> |
| 17 | The VM does not support tools based on JVMTI (Java Virtual |
| 18 | Machine Tool Interface). This is a relatively intrusive approach that |
| 19 | relies on bytecode insertion, something the Dalvik VM does not currently |
| 20 | support. |
| 21 | </p><p> |
| 22 | Dalvik's implementation of JDWP also includes hooks for supporting |
| 23 | DDM (Dalvik Debug Monitor) features, notably as implemented by DDMS |
| 24 | (Dalvik Debug Monitor Server) and the Eclipse ADT plugin. The protocol |
| 25 | and VM interaction is described in some detail |
| 26 | <a href="debugmon.html">here</a>. |
| 27 | </p><p> |
| 28 | All of the debugger support in the VM lives in the <code>dalvik/vm/jdwp</code> |
| 29 | directory, and is almost entirely isolated from the rest of the VM sources. |
| 30 | <code>dalvik/vm/Debugger.c</code> bridges the gap. The goal in doing so |
| 31 | was to make it easier to re-use the JDWP code in other projects. |
| 32 | </p><p> |
| 33 | |
| 34 | |
| 35 | <h2>Implementation</h2> |
| 36 | |
| 37 | <p> |
| 38 | Every VM that has debugging enabled starts a "JDWP" thread. The thread |
| 39 | typically sits idle until DDMS or a debugger connects. The thread is |
| 40 | only responsible for handling requests from the debugger; VM-initated |
| 41 | communication, such as notifying the debugger when the VM has stopped at |
| 42 | a breakpoint, are sent from the affected thread. |
| 43 | </p><p> |
Andy McFadden | e7307fa | 2009-07-06 13:56:24 -0700 | [diff] [blame] | 44 | When the VM is started from the Android app framework, debugging is enabled |
| 45 | for all applications when the system property <code>ro.debuggable</code> |
| 46 | is set to </code>1</code> (use <code>adb shell getprop ro.debuggable</code> |
| 47 | to check it). If it's zero, debugging can be enabled via the application's |
| 48 | manifest, which must include <code>android:debuggable="true"</code> in the |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 49 | <code><application></code> element. |
| 50 | |
| 51 | </p><p> |
| 52 | The VM recognizes the difference between a connection from DDMS and a |
| 53 | connection from a debugger (either directly or in concert with DDMS). |
| 54 | A connection from DDMS alone doesn't result in a change in VM behavior, |
| 55 | but when the VM sees debugger packets it allocates additional data |
| 56 | structures and may switch to a different implementation of the interpreter. |
| 57 | </p><p> |
Andy McFadden | af19f59 | 2010-02-16 14:08:29 -0800 | [diff] [blame] | 58 | Pre-Froyo implementations of the Dalvik VM used read-only memory mappings |
Andy McFadden | 9d0bdb0 | 2009-11-30 14:20:37 -0800 | [diff] [blame] | 59 | for all bytecode, which made it necessary to scan for breakpoints by |
Andy McFadden | af19f59 | 2010-02-16 14:08:29 -0800 | [diff] [blame] | 60 | comparing the program counter to a set of addresses. In Froyo this was |
Andy McFadden | 9d0bdb0 | 2009-11-30 14:20:37 -0800 | [diff] [blame] | 61 | changed to allow insertion of breakpoint opcodes. This allows the VM |
| 62 | to execute code more quickly, and does away with the hardcoded limit |
| 63 | of 20 breakpoints. Even with this change, however, the debug-enabled |
| 64 | interpreter is much slower than the regular interpreter (perhaps 5x). |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 65 | </p><p> |
| 66 | The JDWP protocol is stateless, so the VM handles individual debugger |
| 67 | requests as they arrive, and posts events to the debugger as they happen. |
| 68 | </p><p> |
| 69 | |
| 70 | |
| 71 | <h2>Debug Data</h2> |
| 72 | <p> Source code debug data, which includes mappings of source code to |
| 73 | bytecode and lists describing which registers are used to hold method |
| 74 | arguments and local variables, are optionally emitted by the Java compiler. |
| 75 | When <code>dx</code> converts Java bytecode to Dalvik bytecode, it must |
| 76 | also convert this debug data. |
| 77 | </p><p> |
| 78 | <code>dx</code> must also ensure that it doesn't perform operations |
| 79 | that confuse the debugger. For example, re-using registers that hold |
| 80 | method arguments and the "<code>this</code>" pointer is allowed in |
| 81 | Dalvik bytecode if the values are never used or no longer needed. |
| 82 | This can be very confusing for the debugger (and the programmer) |
| 83 | since the values have method scope and aren't expected to disappear. For |
| 84 | this reason, <code>dx</code> generates sub-optimal code in some situations |
| 85 | when debugging support is enabled. |
| 86 | </p><p> |
| 87 | Some of the debug data is used for other purposes; in particular, having |
| 88 | filename and line number data is necessary for generating useful exception |
| 89 | stack traces. This data can be omitted by <code>dx</code> to make the DEX |
| 90 | file smaller. |
| 91 | </p><p> |
| 92 | |
| 93 | |
| 94 | <h2>Usage</h2> |
| 95 | |
| 96 | <p> |
| 97 | The Dalvik VM supports many of the same command-line flags that other popular |
| 98 | desktop VMs do. To start a VM with debugging enabled, you add a command-line |
| 99 | flag with some basic options. The basic incantation looks something |
| 100 | like this: |
| 101 | |
| 102 | <pre>-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y</pre> |
| 103 | or |
| 104 | <pre>-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=y</pre> |
| 105 | |
| 106 | </p><p> |
| 107 | After the initial prefix, options are provided as name=value pairs. The |
| 108 | options currently supported by the Dalvik VM are: |
| 109 | <dl> |
| 110 | <dt>transport (no default)</dt> |
| 111 | <dd>Communication transport mechanism to use. Dalvik supports |
| 112 | TCP/IP sockets (<code>dt_socket</code>) and connection over USB |
| 113 | through ADB (<code>dt_android_adb</code>). |
| 114 | </dd> |
| 115 | |
| 116 | <dt>server (default='n')</dt> |
| 117 | <dd>Determines whether the VM acts as a client or a server. When |
| 118 | acting as a server, the VM waits for a debugger to connect to it. |
| 119 | When acting as a client, the VM attempts to connect to a waiting |
| 120 | debugger. |
| 121 | </dd> |
| 122 | |
| 123 | <dt>suspend (default='n')</dt> |
| 124 | <dd>If set to 'y', the VM will wait for a debugger connection |
| 125 | before executing application code. When the debugger connects (or |
| 126 | when the VM finishes connecting to the debugger), the VM tells the |
| 127 | debugger that it has suspended, and will not proceed until told |
| 128 | to resume. If set to 'n', the VM just plows ahead. |
| 129 | </dd> |
| 130 | |
| 131 | <dt>address (default="")</dt> |
| 132 | <dd>This must be <code>hostname:port</code> when <code>server=n</code>, |
| 133 | but can be just <code>port</code> when <code>server=y</code>. This |
| 134 | specifies the IP address and port number to connect or listen to. |
| 135 | <br> |
| 136 | Listening on port 0 has a special meaning: try to |
| 137 | listen on port 8000; if that fails, try 8001, 8002, and so on. (This |
| 138 | behavior is non-standard and may be removed from a future release.) |
| 139 | <br>This option has no meaning for <code>transport=dt_android_adb</code>. |
| 140 | </dd> |
| 141 | |
| 142 | <dt>help (no arguments)</dt> |
| 143 | <dd>If this is the only option, a brief usage message is displayed. |
| 144 | </dd> |
| 145 | |
| 146 | <dt>launch, onthrow, oncaught, timeout</dt> |
| 147 | <dd>These options are accepted but ignored. |
| 148 | </dd> |
| 149 | </dl> |
| 150 | |
| 151 | </p><p> |
| 152 | To debug a program on an Android device using DDMS over USB, you could |
| 153 | use a command like this: |
| 154 | <pre>% dalvikvm -agentlib:jdwp=transport=dt_android_adb,suspend=y,server=y -cp /data/foo.jar Foo</pre> |
| 155 | |
| 156 | This tells the Dalvik VM to run the program with debugging enabled, listening |
| 157 | for a connection from DDMS, and waiting for a debugger. The program will show |
| 158 | up with an app name of "?" in the process list, because it wasn't started |
| 159 | from the Android application framework. From here you would connect your |
| 160 | debugger to the appropriate DDMS listen port (e.g. |
| 161 | <code>jdb -attach localhost:8700</code> after selecting it in the app list). |
| 162 | |
| 163 | </p><p> |
| 164 | To debug a program on an Android device using TCP/IP bridged across ADB, |
| 165 | you would first need to set up forwarding: |
| 166 | <pre>% adb forward tcp:8000 tcp:8000 |
| 167 | % adb shell dalvikvm -agentlib:jdwp=transport=dt_socket,address=8000,suspend=y,server=y -cp /data/foo.jar Foo</pre> |
| 168 | and then <code>jdb -attach localhost:8000</code>. |
| 169 | </p><p> |
| 170 | (In the above examples, the VM will be suspended when you attach. In jdb, |
| 171 | type <code>cont</code> to continue.) |
| 172 | </p><p> |
| 173 | The DDMS integration makes the <code>dt_android_adb</code> transport much |
| 174 | more convenient when debugging on an Android device, but when working with |
| 175 | Dalvik on the desktop it makes sense to use the TCP/IP transport. |
| 176 | </p><p> |
| 177 | |
| 178 | |
| 179 | <h2>Known Issues and Limitations</h2> |
| 180 | |
| 181 | </p><p> |
| 182 | Most of the optional features JDWP allows are not implemented. These |
| 183 | include field access watchpoints and better tracking of monitors. |
| 184 | </p><p> |
| 185 | Not all JDWP requests are implemented. In particular, anything that |
| 186 | never gets emitted by the debuggers we've used is not supported and will |
| 187 | result in error messages being logged. Support will be added when a |
| 188 | use case is uncovered. |
| 189 | </p><p> |
| 190 | |
| 191 | </p><p> |
| 192 | The debugger and garbage collector are somewhat loosely |
| 193 | integrated at present. The VM currently guarantees that any object the |
| 194 | debugger is aware of will not be garbage collected until after the |
| 195 | debugger disconnects. This can result in a build-up over time while the |
Andy McFadden | e7307fa | 2009-07-06 13:56:24 -0700 | [diff] [blame] | 196 | debugger is connected. For example, if the debugger sees a running |
| 197 | thread, the associated Thread object will not be collected, even after |
| 198 | the thread terminates. |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 199 | </p><p> |
Andy McFadden | e7307fa | 2009-07-06 13:56:24 -0700 | [diff] [blame] | 200 | The only way to "unlock" the references is to detach and reattach the |
| 201 | debugger. |
| 202 | </p><p> |
Andy McFadden | 10d42fa | 2009-04-24 15:18:42 -0700 | [diff] [blame] | 203 | |
| 204 | </p><p> |
| 205 | The translation from Java bytecode to Dalvik bytecode may result in |
| 206 | identical sequences of instructions being combined. This can make it |
| 207 | look like the wrong bit of code is being executed. For example: |
| 208 | <pre> int test(int i) { |
| 209 | if (i == 1) { |
| 210 | return 0; |
| 211 | } |
| 212 | return 1; |
| 213 | }</pre> |
| 214 | The Dalvik bytecode uses a common <code>return</code> instruction for both |
| 215 | <code>return</code> statements, so when <code>i</code> is 1 the debugger |
| 216 | will single-step through <code>return 0</code> and then <code>return 1</code>. |
| 217 | </p><p> |
| 218 | |
| 219 | </p><p> |
| 220 | Dalvik handles synchronized methods differently from other VMs. |
| 221 | Instead of marking a method as <code>synchronized</code> and expecting |
| 222 | the VM to handle the locks, <code>dx</code> inserts a "lock" |
| 223 | instruction at the top of the method and an "unlock" instruction in a |
| 224 | synthetic <code>finally</code> block. As a result, when single-stepping |
| 225 | a <code>return</code> statement, the "current line" cursor may jump to |
| 226 | the last line in the method. |
| 227 | </p><p> |
| 228 | This can also affect the way the debugger processes exceptions. The |
| 229 | debugger may decide to break on an |
| 230 | exception based on whether that exception is "caught" or "uncaught". To |
| 231 | be considered uncaught, there must be no matching <code>catch</code> block |
| 232 | or <code>finally</code> clause between the current point of execution and |
| 233 | the top of the thread. An exception thrown within or below a synchronized |
| 234 | method will always be considered "caught", so the debugger won't stop |
| 235 | until the exception is re-thrown from the synthetic <code>finally</code> block. |
| 236 | </p><p> |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 237 | |
| 238 | |
| 239 | <address>Copyright © 2009 The Android Open Source Project</address> |
| 240 | </p> |
| 241 | |
| 242 | </body> |
| 243 | </html> |