The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | <HTML> |
| 2 | |
| 3 | |
| 4 | <head> |
| 5 | <title>Dalvik VM Debug Monitor</title> |
| 6 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
| 7 | <link href="http://www.google.com/favicon.ico" type="image/x-icon" |
| 8 | rel="shortcut icon"> |
| 9 | <link href="../android.css" type="text/css" rel="stylesheet"> |
| 10 | <script language="JavaScript1.2" type="text/javascript"> |
| 11 | function highlight(name) { |
| 12 | if (document.getElementById) { |
| 13 | tags = [ 'span', 'div', 'tr', 'td' ]; |
| 14 | for (i in tags) { |
| 15 | elements = document.getElementsByTagName(tags[i]); |
| 16 | if (elements) { |
| 17 | for (j = 0; j < elements.length; j++) { |
| 18 | elementName = elements[j].getAttribute("id"); |
| 19 | if (elementName == name) { |
| 20 | elements[j].style.backgroundColor = "#C0F0C0"; |
| 21 | } else if (elementName && elementName.indexOf("rev") == 0) { |
| 22 | elements[j].style.backgroundColor = "#FFFFFF"; |
| 23 | } |
| 24 | } |
| 25 | } |
| 26 | } |
| 27 | } |
| 28 | } |
| 29 | </script> |
| 30 | </head> |
| 31 | <body onload="prettyPrint()"> |
| 32 | |
| 33 | <h1><a name="My_Project_"></a>Dalvik VM<br>Debug Monitor</h1> |
| 34 | |
| 35 | <!-- Status is one of: Draft, Current, Needs Update, Obsolete --> |
| 36 | <p style="text-align:center"><strong>Status:</strong><em>Draft</em> |
| 37 | <small>(as of March 6, 2007)</small></p> |
| 38 | <address> |
| 39 | [authors] |
| 40 | <address> |
| 41 | |
| 42 | <!-- last modified date can be different to the "Status date." It automatically |
| 43 | updates |
| 44 | whenever the file is modified. --> |
| 45 | <i>Modified:</i> |
| 46 | <!-- this script automatically sets the modified date,you don't need to modify |
| 47 | it --> |
| 48 | <script type=text/javascript> |
| 49 | <!-- |
| 50 | var lm = new Date(document.lastModified); |
| 51 | document.write(lm.toDateString()); |
| 52 | //--> |
| 53 | </script> |
| 54 | </address> |
| 55 | |
| 56 | <p><br> |
| 57 | <HR> |
| 58 | |
| 59 | <h2>Introduction</h2> |
| 60 | |
| 61 | <p>It's extremely useful to be able to monitor the live state of the |
| 62 | VM. For Android, we need to monitor multiple VMs running on a device |
| 63 | connected through USB or a wireless network connection. This document |
| 64 | describes a debug monitor server that interacts with multiple VMs, and |
| 65 | an API that VMs and applications can use to provide information |
| 66 | to the monitor. |
| 67 | |
| 68 | <p>Some things we can monitor with the Dalvik Debug Monitor ("DDM"): |
| 69 | <ul> |
| 70 | <li> Thread states. Track thread creation/exit, busy/idle status. |
| 71 | <li> Overall heap status, useful for a heap bitmap display or |
| 72 | fragmentation analysis. |
| 73 | </ul> |
| 74 | |
| 75 | <p>It is possible for something other than a VM to act as a DDM client, but |
| 76 | that is a secondary goal. Examples include "logcat" log extraction |
| 77 | and system monitors for virtual memory usage and load average. |
| 78 | |
| 79 | <p>It's also possible for the DDM server to be run on the device, with |
| 80 | the information presented through the device UI. However, the initial goal |
| 81 | is to provide a display tool that takes advantage of desktop tools and |
| 82 | screen real estate. |
| 83 | |
| 84 | <p>This work is necessary because we are unable to use standard JVMTI-based |
| 85 | tools with Dalvik. JVMTI relies on bytecode insertion, which is not |
| 86 | currently possible because Dalvik doesn't support Java bytecode. |
| 87 | |
| 88 | <p>The DDM server is written in the Java programming language |
| 89 | for portability. It uses a desktop |
| 90 | UI toolkit (SWT) for its interface. |
| 91 | |
| 92 | |
| 93 | <h2>Protocol</h2> |
| 94 | |
| 95 | <p>To take advantage of existing infrastructure we are piggy-backing the |
| 96 | DDM protocol on top of JDWP (the Java Debug Wire Protocol, normally spoken |
| 97 | between a VM and a debugger). To a |
| 98 | non-DDM client, the DDM server just looks like a debugger. |
| 99 | |
| 100 | <p>The JDWP protocol is very close to what we want to use. In particular: |
| 101 | <ul> |
| 102 | <li>It explicitly allows for vendor-defined packets, so there is no |
| 103 | need to "bend" the JDWP spec. |
| 104 | <li>Events may be posted from the VM at arbitrary points. Such |
| 105 | events do not elicit a response from the debugger, meaning the client |
| 106 | can post data and immediately resume work without worrying about the |
| 107 | eventual response. |
| 108 | <li>The basic protocol is stateless and asynchronous. Request packets |
| 109 | from the debugger side include a serial number, which the VM includes |
| 110 | in the response packet. This allows multiple simultaneous |
| 111 | conversations, which means the DDM traffic can be interleaved with |
| 112 | debugger traffic. |
| 113 | </ul> |
| 114 | |
| 115 | <p>There are a few issues with using JDWP for our purposes: |
| 116 | <ul> |
| 117 | <li>The VM only expects one connection from a debugger, so you couldn't |
| 118 | attach the monitor and a debugger at the same time. This will be |
| 119 | worked around by connecting the debugger to the monitor and passing the |
| 120 | traffic through. (We're already doing the pass-through with "jdwpspy"; |
| 121 | requires some management of our request IDs though.) This should |
| 122 | be more convenient than the current "guess the port |
| 123 | number" system when we're attached to a device. |
| 124 | <li>The VM behaves differently when a debugger is attached. It will |
| 125 | run more slowly, and any objects passed to the monitor or debugger are |
| 126 | immune to GC. We can work around this by not enabling the slow path |
| 127 | until non-DDM traffic is observed. We also want to have a "debugger |
| 128 | has connected/disconnected" message that allows the VM to release |
| 129 | debugger-related resources without dropping the net connection. |
| 130 | <li>Non-DDM VMs should not freak out when DDM connects. There are |
| 131 | no guarantees here for 3rd-party VMs (e.g. a certain mainstream VM, |
| 132 | which crashes instantly), but our older JamVM can be |
| 133 | configured to reject the "hello" packet. |
| 134 | </ul> |
| 135 | |
| 136 | |
| 137 | <h3>Connection Establishment</h3> |
| 138 | |
| 139 | <p>There are two basic approaches: have the server contact the VMs, and |
| 140 | have the VMs contact the server. The former is less "precise" than the |
| 141 | latter, because you have to scan for the clients, but it has some |
| 142 | advantages. |
| 143 | |
| 144 | <p>There are three interesting scenarios: |
| 145 | <ol> |
| 146 | <li>The DDM server is started, then the USB-attached device is booted |
| 147 | or the simulator is launched. |
| 148 | <li>The device or simulator is already running when the DDM server |
| 149 | is started. |
| 150 | <li>The DDM server is running when an already-started device is |
| 151 | attached to USB. |
| 152 | </ol> |
| 153 | <p>If we have the VMs connect to the DDM server on startup, we only handle |
| 154 | case #1. If the DDM server scans for VMs when it starts, we only handle |
| 155 | case #2. Neither handles case #3, which is probably the most important |
| 156 | of the bunch as the device matures. |
| 157 | <p>The plan is to have a drop-down menu with two entries, |
| 158 | "scan workstation" and "scan device". |
| 159 | The former causes the DDM server to search for VMs on "localhost", the |
| 160 | latter causes it to search for VMs on the other side of an ADB connection. |
| 161 | The DDM server will scan for VMs every few seconds, either checking a |
| 162 | range of known VM ports (e.g. 8000-8040) or interacting with some sort |
| 163 | of process database on the device. Changing modes causes all existing |
| 164 | connections to be dropped. |
| 165 | <p>When the DDM server first starts, it will try to execute "adb usb" |
| 166 | to ensure that the ADB server is running. (Note it will be necessary |
| 167 | to launch the DDM server from a shell with "adb" in the path.) If this |
| 168 | fails, talking to the device will still be possible so long as the ADB |
| 169 | daemon is already running. |
| 170 | |
| 171 | <h4>Connecting a Debugger</h4> |
| 172 | |
| 173 | <p>With the DDM server sitting on the JDWP port of all VMs, it will be |
| 174 | necessary to connect the debugger through the DDM server. Each VM being |
| 175 | debugged will have a separate port being listened to by the DDM server, |
| 176 | allowing you to connect a debugger to one or more VMs simultaneously. |
| 177 | |
| 178 | <p>In the common case, however, the developer will only want to debug |
| 179 | a single VM. One port (say 8700) will be listened to by the DDM server, |
| 180 | and anything connecting to it will be connected to the "current VM" |
| 181 | (selected in the UI). This should allow developers to focus on a |
| 182 | single application, which may otherwise shift around in the ordering, without |
| 183 | having to adjust their IDE settings to a different port every time they |
| 184 | restart the device. |
| 185 | |
| 186 | |
| 187 | <h3>Packet Format</h3> |
| 188 | |
| 189 | <p>Information is sent in chunks. Each chunk starts with: |
| 190 | <pre> |
| 191 | u4 type |
| 192 | u4 length |
| 193 | </pre> |
| 194 | and contains a variable amount of type-specific data. |
| 195 | Unrecognized types cause an empty response from the client and |
| 196 | are quietly ignored by the server. [Should probably return an error; |
| 197 | need an "error" chunk type and a handler on the server side.] |
| 198 | |
| 199 | <p>The same chunk type may have different meanings when sent in different |
| 200 | directions. For example, the same type may be used for both a query and |
| 201 | a response to the query. For sanity the type must always be used in |
| 202 | related transactions. |
| 203 | |
| 204 | <p>This is somewhat redundant with the JDWP framing, which includes a |
| 205 | 4-byte length and a two-byte type code ("command set" and "command"; a |
| 206 | range of command set values is designated for "vendor-defined commands |
| 207 | and extensions"). Using the chunk format allows us to remain independent |
| 208 | of the underlying transport, avoids intrusive integration |
| 209 | with JDWP client code, and provides a way to send multiple chunks in a |
| 210 | single transmission unit. [I'm taking the multi-chunk packets into |
| 211 | account in the design, but do not plan to implement them unless the need |
| 212 | arises.] |
| 213 | |
| 214 | <p>Because we may be sending data over a slow USB link, the chunks may be |
| 215 | compressed. Compressed chunks are written as a chunk type that |
| 216 | indicates the compression, followed by the compressed length, followed |
| 217 | by the original chunk type and the uncompressed length. For zlib's deflate |
| 218 | algorithm, the chunk type is "ZLIB". |
| 219 | |
| 220 | <p>Following the JDWP model, packets sent from the server to the client |
| 221 | are always acknowledged, but packets sent from client to server never are. |
| 222 | The JDWP error code field is always set to "no error"; failure responses |
| 223 | from specific requests must be encoded into the DDM messages. |
| 224 | |
| 225 | <p>In what follows "u4" is an unsigned 32-bit value and "u1" is an |
| 226 | unsigned 8-bit value. Values are written in big-endian order to match |
| 227 | JDWP. |
| 228 | |
| 229 | |
| 230 | <h3>Initial Handshake</h3> |
| 231 | |
| 232 | <p>After the JDWP handshake, the server sends a HELO chunk to the client. |
| 233 | If the client's JDWP layer rejects it, the server assumes that the client |
| 234 | is not a DDM-aware VM, and does not send it any further DDM queries. |
| 235 | <p>On the client side, upon seeing a HELO it can know that a DDM server |
| 236 | is attached and prepare accordingly. The VM should not assume that a |
| 237 | debugger is attached until a non-DDM packet arrives. |
| 238 | |
| 239 | <h4>Chunk HELO (server --> client)</h4> |
| 240 | <p>Basic "hello" message. |
| 241 | <pre> |
| 242 | u4 DDM server protocol version |
| 243 | </pre> |
| 244 | |
| 245 | |
| 246 | <h4>Chunk HELO (client --> server, reply only)</h4> |
| 247 | Information about the client. Must be sent in response to the HELO message. |
| 248 | <pre> |
| 249 | u4 DDM client protocol version |
| 250 | u4 pid |
| 251 | u4 VM ident string len (in 16-bit units) |
| 252 | u4 application name len (in 16-bit units) |
| 253 | var VM ident string (UTF-16) |
| 254 | var application name (UTF-16) |
| 255 | </pre> |
| 256 | |
| 257 | <p>If the client does not wish to speak to the DDM server, it should respond |
| 258 | with a JDWP error packet. This is the same behavior you'd get from a VM |
| 259 | that doesn't support DDM. |
| 260 | |
| 261 | |
| 262 | <h3>Debugger Management</h3> |
| 263 | <p>VMs usually prepare for debugging when a JDWP connection is established, |
| 264 | and release debugger-related resources when the connection drops. We want |
| 265 | to open the JDWP connection early and hold it open after the debugger |
| 266 | disconnects. |
| 267 | <p>The VM can tell when a debugger attaches, because it will start seeing |
| 268 | non-DDM JDWP traffic, but it can't identify the disconnect. For this reason, |
| 269 | we need to send a packet to the client when the debugger disconnects. |
| 270 | <p>If the DDM server is talking to a non-DDM-aware client, it will be |
| 271 | necessary to drop and re-establish the connection when the debugger goes away. |
| 272 | (This also works with DDM-aware clients; this packet is an optimization.) |
| 273 | |
| 274 | <h4>Chunk DBGD (server --> client)</h4> |
| 275 | <p>Debugger has disconnected. The client responds with a DBGD to acknowledge |
| 276 | receipt. No data in request, no response required. |
| 277 | |
| 278 | |
| 279 | <h3>VM Info</h3> |
| 280 | <p>Update the server's info about the client. |
| 281 | |
| 282 | <h4>Chunk APNM (client --> server)</h4> |
| 283 | |
| 284 | <p>If a VM's application name changes -- possible in our environment because |
| 285 | of the "pre-initialized" app processes -- it must send up one of these. |
| 286 | <pre> |
| 287 | u4 application name len (in 16-bit chars) |
| 288 | var application name (UTF-16) |
| 289 | </pre> |
| 290 | |
| 291 | <h4>Chunk WAIT (client --> server)</h4> |
| 292 | |
| 293 | <p>This tells DDMS that one or more threads are waiting on an external |
| 294 | event. The simplest use is to tell DDMS that the VM is waiting for a |
| 295 | debugger to attach. |
| 296 | <pre> |
| 297 | u1 reason (0 = wait for debugger) |
| 298 | </pre> |
| 299 | If DDMS is attached, the client VM sends this up when waitForDebugger() |
| 300 | is called. If waitForDebugger() is called before DDMS attaches, the WAIT |
| 301 | chunk will be sent up at about the same time as the HELO response. |
| 302 | |
| 303 | |
| 304 | <h3>Thread Status</h3> |
| 305 | |
| 306 | <p>The client can send updates when their status changes, or periodically |
| 307 | send thread state info, e.g. 2x per |
| 308 | second to allow a "blinkenlights" display of thread activity. |
| 309 | |
| 310 | <h4>Chunk THEN (server --> client)</h4> |
| 311 | |
| 312 | <p>Enable thread creation/death notification. |
| 313 | <pre> |
| 314 | u1 boolean (true=enable, false=disable) |
| 315 | </pre> |
| 316 | <p>The response is empty. The client generates THCR packets for all |
| 317 | known threads. (Note the THCR packets may arrive before the THEN |
| 318 | response.) |
| 319 | |
| 320 | <h4>Chunk THCR (client --> server)</h4> |
| 321 | <p>Thread Creation notification. |
| 322 | <pre> |
| 323 | u4 VM-local thread ID (usually a small int) |
| 324 | u4 thread name len (in 16-bit chars) |
| 325 | var thread name (UTF-16) |
| 326 | </pre> |
| 327 | |
| 328 | <h4>Chunk THDE (client --> server)</h4> |
| 329 | <p>Thread Death notification. |
| 330 | <pre> |
| 331 | u4 VM-local thread ID |
| 332 | </pre> |
| 333 | |
| 334 | <h4>Chunk THST (server --> client)</h4> |
| 335 | |
| 336 | <p>Enable periodic thread activity updates. |
| 337 | Threads in THCR messages are assumed to be in the "initializing" state. A |
| 338 | THST message should follow closely on the heels of THCR. |
| 339 | <pre> |
| 340 | u4 interval, in msec |
| 341 | </pre> |
| 342 | <p>An interval of 0 disables the updates. This is done periodically, |
| 343 | rather than every time the thread state changes, to reduce the amount |
| 344 | of data that must be sent for an actively running VM. |
| 345 | |
| 346 | <h4>Chunk THST (client --> server)</h4> |
| 347 | <p>Thread Status, describing the state of one or more threads. This is |
| 348 | most useful when creation/death notifications are enabled first. The |
| 349 | overall layout is: |
| 350 | <pre> |
| 351 | u4 count |
| 352 | var thread data |
| 353 | </pre> |
| 354 | Then, for every thread: |
| 355 | <pre> |
| 356 | u4 VM-local thread ID |
| 357 | u1 thread state |
| 358 | u1 suspended |
| 359 | </pre> |
| 360 | <p>"thread state" must be one of: |
| 361 | <ul> <!-- don't use ol, we may need (-1) or sparse --> |
| 362 | <li> 1 - running (now executing or ready to do so) |
| 363 | <li> 2 - sleeping (in Thread.sleep()) |
| 364 | <li> 3 - monitor (blocked on a monitor lock) |
| 365 | <li> 4 - waiting (in Object.wait()) |
| 366 | <li> 5 - initializing |
| 367 | <li> 6 - starting |
| 368 | <li> 7 - native (executing native code) |
| 369 | <li> 8 - vmwait (waiting on a VM resource) |
| 370 | </ul> |
| 371 | <p>"suspended" will be 0 if the thread is running, 1 if not. |
| 372 | <p>[Any reason not to make "suspended" be the high bit of "thread state"? |
| 373 | Do we need to differentiate suspend-by-GC from suspend-by-debugger?] |
| 374 | <p>[We might be able to send the currently-executing method. This is a |
| 375 | little risky in a running VM, and increases the size of the messages |
| 376 | considerably, but might be handy.] |
| 377 | |
| 378 | |
| 379 | <h3>Heap Status</h3> |
| 380 | |
| 381 | <p>The client sends what amounts to a color-coded bitmap to the server, |
| 382 | indicating which stretches of memory are free and which are in use. For |
| 383 | compactness the bitmap is run-length encoded, and based on multi-byte |
| 384 | "allocation units" rather than byte counts. |
| 385 | |
| 386 | <p>In the future the server will be able to correlate the bitmap with more |
| 387 | detailed object data, so enough information is provided to associate the |
| 388 | bitmap data with virtual addresses. |
| 389 | |
| 390 | <p>Heaps may be broken into segments within the VM, and due to memory |
| 391 | constraints it may be desirable to send the bitmap in smaller pieces, |
| 392 | so the protocol allows the heap data to be sent in several chunks. |
| 393 | To avoid ambiguity, the client is required |
| 394 | to send explicit "start" and "end" messages during an update. |
| 395 | |
| 396 | <p>All messages include a "heap ID" that can be used to differentiate |
| 397 | between multiple independent virtual heaps or perhaps a native heap. The |
| 398 | client is allowed to send information about different heaps simultaneously, |
| 399 | so all heap-specific information is tagged with a "heap ID". |
| 400 | |
| 401 | <h4>Chunk HPIF (server --> client)</h4> |
| 402 | <p>Request heap info. |
| 403 | <pre> |
| 404 | u1 when to send |
| 405 | </pre> |
| 406 | <p>The "when" values are: |
| 407 | <pre> |
| 408 | 0: never |
| 409 | 1: immediately |
| 410 | 2: at the next GC |
| 411 | 3: at every GC |
| 412 | </pre> |
| 413 | |
| 414 | <h4>Chunk HPIF (client --> server, reply only)</h4> |
| 415 | <p>Heap Info. General information about the heap, suitable for a summary |
| 416 | display. |
| 417 | <pre> |
| 418 | u4 number of heaps |
| 419 | </pre> |
| 420 | For each heap: |
| 421 | <pre> |
| 422 | u4 heap ID |
| 423 | u8 timestamp in ms since Unix epoch |
| 424 | u1 capture reason (same as 'when' value from server) |
| 425 | u4 max heap size in bytes (-Xmx) |
| 426 | u4 current heap size in bytes |
| 427 | u4 current number of bytes allocated |
| 428 | u4 current number of objects allocated |
| 429 | </pre> |
| 430 | <p>[We can get some of this from HPSG, more from HPSO.] |
| 431 | <p>[Do we need a "heap overhead" stat here, indicating how much goes to |
| 432 | waste? e.g. (8 bytes per object * number of objects)] |
| 433 | |
| 434 | <h4>Chunk HPSG (server --> client)</h4> |
| 435 | <p>Request transmission of heap segment data. |
| 436 | <pre> |
| 437 | u1 when to send |
| 438 | u1 what to send |
| 439 | </pre> |
| 440 | <p>The "when" to send will be zero to disable transmission, 1 to send |
| 441 | during a GC. Other values are currently undefined. (Could use to pick |
| 442 | which part of the GC to send it, or cause periodic transmissions.) |
| 443 | <p>The "what" field is currently 0 for HPSG and 1 for HPSO. |
| 444 | <p>No reply is expected. |
| 445 | |
| 446 | <h4>Chunk NHSG (server --> client)</h4> |
| 447 | <p>Request transmission of native heap segment data. |
| 448 | <pre> |
| 449 | u1 when to send |
| 450 | u1 what to send |
| 451 | </pre> |
| 452 | <p>The "when" to send will be zero to disable transmission, 1 to send |
| 453 | during a GC. Other values are currently undefined. |
| 454 | <p>The "what" field is currently ignored. |
| 455 | <p>No reply is expected. |
| 456 | |
| 457 | <h4>Chunk HPST/NHST (client --> server)</h4> |
| 458 | <p>This is a Heap Start message. It tells the server to discard any |
| 459 | existing notion of what the client's heap looks like, and prepare for |
| 460 | new information. HPST indicates a virtual heap dump and must be followed |
| 461 | by zero or more HPSG/HPSO messages and an HPEN. NHST indicates a native |
| 462 | heap dump and must be followed by zero or more NHSG messages and an NHEN. |
| 463 | |
| 464 | <p>The only data item is: |
| 465 | <pre> |
| 466 | u4 heap ID |
| 467 | </pre> |
| 468 | |
| 469 | <h4>Chunk HPEN/NHEN (client --> server)</h4> |
| 470 | <p>Heap End, indicating that all information about the heap has been sent. |
| 471 | A HPST will be paired with an HPEN and an NHST will be paired with an NHEN. |
| 472 | |
| 473 | <p>The only data item is: |
| 474 | <pre> |
| 475 | u4 heap ID |
| 476 | </pre> |
| 477 | |
| 478 | <h4>Chunk HPSG (client --> server)</h4> |
| 479 | <p>Heap segment data. Each chunk describes all or part of a contiguous |
| 480 | stretch of heap memory. |
| 481 | <pre> |
| 482 | u4 heap ID |
| 483 | u1 size of allocation unit, in bytes (e.g. 8 bytes) |
| 484 | u4 virtual address of segment start |
| 485 | u4 offset of this piece (relative to the virtual address) |
| 486 | u4 length of piece, in allocation units |
| 487 | var usage data |
| 488 | </pre> |
| 489 | <p>The "usage data" indicates the status of each allocation unit. The data |
| 490 | is a stream of pairs of bytes, where the first byte indicates the state |
| 491 | of the allocation unit, and the second byte indicates the number of |
| 492 | consecutive allocation units with the same state. |
| 493 | <p>The bits in the "state" byte have the following meaning: |
| 494 | <pre> |
| 495 | +---------------------------------------+ |
| 496 | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| 497 | +---------------------------------------+ |
| 498 | | P | U0 | K2 | K1 | K0 | S2 | S1 | S0 | |
| 499 | +---------------------------------------+ |
| 500 | </pre> |
| 501 | <ul> |
| 502 | <li>'S': solidity |
| 503 | <ul> |
| 504 | <li>0=free |
| 505 | <li>1=has hard reference |
| 506 | <li>2=has soft reference |
| 507 | <li>3=has weak reference |
| 508 | <li>4=has phantom reference |
| 509 | <li>5=pending finalization |
| 510 | <li>6=marked, about to be swept |
| 511 | </ul> |
| 512 | <li>'K': kind |
| 513 | <ul> |
| 514 | <li>0=object |
| 515 | <li>1=class object |
| 516 | <li>2=array of byte/boolean |
| 517 | <li>3=array of char/short |
| 518 | <li>4=array of Object/int/float |
| 519 | <li>5=array of long/double |
| 520 | </ul> |
| 521 | <li>'P': partial flag (not used for HPSG) |
| 522 | <li>'U': unused, must be zero |
| 523 | </ul> |
| 524 | |
| 525 | <p>The use of the various 'S' types depends on when the information is |
| 526 | sent. The current plan is to send it either immediately after a GC, |
| 527 | or between the "mark" and "sweep" phases of the GC. For a fancy generational |
| 528 | collector, we may just want to send it up periodically. |
| 529 | |
| 530 | <p>The run-length byte indicates the number of allocation units minus one, so a |
| 531 | length of 255 means there are 256 consecutive units with this state. In |
| 532 | some cases, e.g. arrays of bytes, the actual size of the data is rounded |
| 533 | up the nearest allocation unit. |
| 534 | <p>For HPSG, the runs do not end at object boundaries. It is not possible |
| 535 | to tell from this bitmap whether a run contains one or several objects. |
| 536 | (But see HPSO, below.) |
| 537 | <p>[If we find that we have many long runs, we can overload the 'P' flag |
| 538 | or dedicate the 'U' flag to indicate that we have a 16-bit length instead |
| 539 | of 8-bit. We can also use a variable-width integer scheme for the length, |
| 540 | encoding 1-128 in one byte, 1-16384 in two bytes, etc.] |
| 541 | <p>[Alternate plan for 'K': array of byte, array of char, array of Object, |
| 542 | array of miscellaneous primitive type] |
| 543 | <p>To parse the data, the server runs through the usage data until either |
| 544 | (a) the end of the chunk is reached, or (b) all allocation units have been |
| 545 | accounted for. (If these two things don't happen at the same time, the |
| 546 | chunk is rejected.) |
| 547 | <p>Example: suppose a VM has a heap at 0x10000 that is 0x2000 bytes long |
| 548 | (with an 8-byte allocation unit size, that's 0x0400 units long). |
| 549 | The client could send one chunk (allocSize=8, virtAddr=0x10000, offset=0, |
| 550 | length=0x0400) or two (allocSize=8, virtAddr=0x10000, offset=0, length=0x300; |
| 551 | then allocSize=8, virtAddr=0x10000, offset=0x300, length=0x100). |
| 552 | <p>The client must encode the entire heap, including all free space at |
| 553 | the end, or the server will not have an accurate impression of the amount |
| 554 | of memory in the heap. This refers to the current heap size, not the |
| 555 | maximum heap size. |
| 556 | |
| 557 | <h4>Chunk HPSO (client --> server)</h4> |
| 558 | <p>This is essentially identical to HPSG, but the runs are terminated at |
| 559 | object boundaries. If an object is larger than 256 allocation units, the |
| 560 | "partial" flag is set in all runs except the last. |
| 561 | <p>The resulting unpacked bitmap is identical, but the object boundary |
| 562 | information can be used to gain insights into heap layout. |
| 563 | <p>[Do we want to have a separate message for this? Maybe just include |
| 564 | a "variant" flag in the HPST packet. Another possible form of output |
| 565 | would be one that indicates the age, in generations, of each block of |
| 566 | memory. That would provide a quick visual indication of "permanent vs. |
| 567 | transient residents", perhaps with a 16-level grey scale.] |
| 568 | |
| 569 | <h4>Chunk NHSG (client --> server)</h4> |
| 570 | <p>Native heap segment data. Each chunk describes all or part of a |
| 571 | contiguous stretch of native heap memory. The format is the same as |
| 572 | for HPSG, except that only solidity values 0 (= free) and 1 (= hard |
| 573 | reference) are used, and the kind value is always 0 for free chunks |
| 574 | and 7 for allocated chunks, indicating a non-VM object. |
| 575 | <pre> |
| 576 | u4 heap ID |
| 577 | u1 size of allocation unit, in bytes (e.g. 8 bytes) |
| 578 | u4 virtual address of segment start |
| 579 | u4 offset of this piece (relative to the virtual address) |
| 580 | u4 length of piece, in allocation units |
| 581 | var usage data |
| 582 | </pre> |
| 583 | |
| 584 | <h3>Generic Replies</h3> |
| 585 | |
| 586 | The client-side chunk handlers need a common way to report simple success |
| 587 | or failure. By convention, an empty reply packet indicates success. |
| 588 | |
| 589 | <h4>Chunk FAIL (client --> server, reply only)</h4> |
| 590 | <p>The chunk includes a machine-readable error code and a |
| 591 | human-readable error message. Server code can associate the failure |
| 592 | with the original request by comparing the JDWP packet ID. |
| 593 | <p>This allows a standard way of, for example, rejecting badly-formed |
| 594 | request packets. |
| 595 | <pre> |
| 596 | u4 error code |
| 597 | u4 error message len (in 16-bit chars) |
| 598 | var error message (UTF-16) |
| 599 | </pre> |
| 600 | |
| 601 | <h3>Miscellaneous</h3> |
| 602 | |
| 603 | <h4>Chunk EXIT (server --> client)</h4> |
| 604 | <p>Cause the client to exit with the specified status, using System.exit(). |
| 605 | Useful for certain kinds of testing. |
| 606 | <pre> |
| 607 | u4 exit status |
| 608 | </pre> |
| 609 | |
| 610 | <h4>Chunk DTRC (server --> client)</h4> |
| 611 | <p>[TBD] start/stop dmtrace; can send the results back over the wire. For |
| 612 | size reasons we probably need "sending", "data", "key", "finished" as |
| 613 | 4 separate chunks/packets rather than one glob. |
| 614 | |
| 615 | |
| 616 | <h2>Client API</h2> |
| 617 | |
| 618 | <p>The API is written in the Java programming language |
| 619 | for convenience. The code is free to call native methods if appropriate. |
| 620 | |
| 621 | <h3>Chunk Handler API</h3> |
| 622 | |
| 623 | <p>The basic idea is that arbitrary code can register handlers for |
| 624 | specific chunk types. When a DDM chunk with that type arrives, the |
| 625 | appropriate handler is invoked. The handler's return value provides the |
| 626 | response to the server. |
| 627 | |
| 628 | <p>There are two packages. android.ddm lives in the "framework" library, |
| 629 | and has all of the chunk handlers and registration code. It can freely |
| 630 | use Android classes. org.apache.harmony.dalvik.ddmc lives in the "core" |
| 631 | library, and has |
| 632 | some base classes and features that interact with the VM. Nothing should |
| 633 | need to modify the org.apache.harmony.dalvik.ddmc classes. |
| 634 | |
| 635 | <p>The DDM classes pass chunks of data around with a simple class: |
| 636 | |
| 637 | <pre class=prettyprint> |
| 638 | class Chunk { |
| 639 | int type; |
| 640 | byte[] data; |
| 641 | int offset, length; |
| 642 | }; |
| 643 | </pre> |
| 644 | |
| 645 | <p>The chunk handlers accept and return them: |
| 646 | <pre class=prettyprint> |
| 647 | public Chunk handleChunk(Chunk request) |
| 648 | </pre> |
| 649 | <p>The code is free to parse the chunk and generate a response in any |
| 650 | way it chooses. Big-endian byte ordering is recommended but not mandatory. |
| 651 | <p>Chunk handlers will be notified when a DDM server connects or disconnects, |
| 652 | so that they can perform setup and cleanup operations: |
| 653 | <pre class=prettyprint> |
| 654 | public void connected() |
| 655 | public void disconnected() |
| 656 | </pre> |
| 657 | |
| 658 | <p>The method processes the request, formulates a response, and returns it. |
| 659 | If the method returns null, an empty JDWP success message will be returned. |
| 660 | <p>The request/response interaction is essentially asynchronous in the |
| 661 | protocol. The packets are linked together with the JDWP message ID. |
| 662 | <p>[We could use ByteBuffer here instead of byte[], but it doesn't gain |
| 663 | us much. Wrapping a ByteBuffer around an array is easy. We don't want |
| 664 | to pass the full packet in because we could have multiple chunks in one |
| 665 | request packet. The DDM code needs to collect and aggregate the responses |
| 666 | to all chunks into a single JDWP response packet. Parties wanting to |
| 667 | write multiple chunks in response to a single chunk should send a null |
| 668 | response back and use "sendChunk()" to send the data independently.] |
| 669 | |
| 670 | <h3>Unsolicited event API</h3> |
| 671 | |
| 672 | <p>If a piece of code wants to send a chunk of data to the server at some |
| 673 | arbitrary time, it may do so with a method provided by |
| 674 | org.apache.harmony.dalvik.DdmServer: |
| 675 | |
| 676 | <pre class=prettyprint> |
| 677 | public static void sendChunk(Chunk chunk) |
| 678 | </pre> |
| 679 | |
| 680 | <p>There is no response or status code. No exceptions are thrown. |
| 681 | |
| 682 | |
| 683 | <h2>Server API</h2> |
| 684 | |
| 685 | <p>This is similar to the client side in many ways, but makes extensive |
| 686 | use of ByteBuffer in a perhaps misguided attempt to use java.nio.channels |
| 687 | and avoid excessive thread creation and unnecessary data copying. |
| 688 | |
| 689 | <p>Upon receipt of a packet, the server will identify it as one of: |
| 690 | <ol> |
| 691 | <li>Message to be passed through to the debugger |
| 692 | <li>Response to an earlier request |
| 693 | <li>Unsolicited event packet |
| 694 | </ol> |
| 695 | <p>To handle (2), when messages are sent from the server to the client, |
| 696 | the message must be paired with a callback method. The response might be |
| 697 | delayed for a while -- or might never arrive -- so the server can't block |
| 698 | waiting for responses from the client. |
| 699 | <p>The chunk handlers look like this: |
| 700 | <pre class=prettyprint> |
| 701 | public void handleChunk(Client client, int type, |
| 702 | ByteBuffer data, boolean isReply, int msgId) |
| 703 | </pre> |
| 704 | <p>The arguments are: |
| 705 | <dl> |
| 706 | <dt>client |
| 707 | <dd>An object representing the client VM that send us the packet. |
| 708 | <dt>type |
| 709 | <dd>The 32-bit chunk type. |
| 710 | <dt>data |
| 711 | <dd>The data. The data's length can be determined by calling data.limit(). |
| 712 | <dt>isReply |
| 713 | <dd>Set to "true" if this was a reply to a message we sent earlier, |
| 714 | "false" if the client sent this unsolicited. |
| 715 | <dt>msgId |
| 716 | <dd>The JDWP message ID. Useful for connecting replies with requests. |
| 717 | </dl> |
| 718 | <p>If a handler doesn't like the contents of a packet, it should log an |
| 719 | error message and return. If the handler doesn't recognize the packet at |
| 720 | all, it can call the superclass' handleUnknownChunk() method. |
| 721 | |
| 722 | <p>As with the client, the server code can be notified when clients |
| 723 | connect or disconnect. This allows the handler to send initialization |
| 724 | code immediately after a connect, or clean up after a disconnect. |
| 725 | <p>Data associated with a client can be stored in a ClientData object, |
| 726 | which acts as a general per-client dumping around for VM and UI state. |
| 727 | |
| 728 | |
| 729 | <P><BR> |
| 730 | |
| 731 | <HR> |
| 732 | |
| 733 | <address>Copyright © 2007 The Android Open Source Project</address> |
| 734 | |
| 735 | </body> |
| 736 | </HTML> |