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"> 11function 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 43updates 44whenever the file is modified. --> 45<i>Modified:</i> 46 <!-- this script automatically sets the modified date,you don't need to modify 47it --> 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 62VM. For Android, we need to monitor multiple VMs running on a device 63connected through USB or a wireless network connection. This document 64describes a debug monitor server that interacts with multiple VMs, and 65an API that VMs and applications can use to provide information 66to 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 76that is a secondary goal. Examples include "logcat" log extraction 77and 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 80the information presented through the device UI. However, the initial goal 81is to provide a display tool that takes advantage of desktop tools and 82screen real estate. 83 84<p>This work is necessary because we are unable to use standard JVMTI-based 85tools with Dalvik. JVMTI relies on bytecode insertion, which is not 86currently possible because Dalvik doesn't support Java bytecode. 87 88<p>The DDM server is written in the Java programming language 89for portability. It uses a desktop 90UI 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 96DDM protocol on top of JDWP (the Java Debug Wire Protocol, normally spoken 97between a VM and a debugger). To a 98non-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 140have the VMs contact the server. The former is less "precise" than the 141latter, because you have to scan for the clients, but it has some 142advantages. 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 154case #1. If the DDM server scans for VMs when it starts, we only handle 155case #2. Neither handles case #3, which is probably the most important 156of 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". 159The former causes the DDM server to search for VMs on "localhost", the 160latter causes it to search for VMs on the other side of an ADB connection. 161The DDM server will scan for VMs every few seconds, either checking a 162range of known VM ports (e.g. 8000-8040) or interacting with some sort 163of process database on the device. Changing modes causes all existing 164connections to be dropped. 165<p>When the DDM server first starts, it will try to execute "adb usb" 166to ensure that the ADB server is running. (Note it will be necessary 167to launch the DDM server from a shell with "adb" in the path.) If this 168fails, talking to the device will still be possible so long as the ADB 169daemon 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 174necessary to connect the debugger through the DDM server. Each VM being 175debugged will have a separate port being listened to by the DDM server, 176allowing 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 179a single VM. One port (say 8700) will be listened to by the DDM server, 180and anything connecting to it will be connected to the "current VM" 181(selected in the UI). This should allow developers to focus on a 182single application, which may otherwise shift around in the ordering, without 183having to adjust their IDE settings to a different port every time they 184restart the device. 185 186 187<h3>Packet Format</h3> 188 189<p>Information is sent in chunks. Each chunk starts with: 190<pre> 191u4 type 192u4 length 193</pre> 194and contains a variable amount of type-specific data. 195Unrecognized types cause an empty response from the client and 196are quietly ignored by the server. [Should probably return an error; 197need 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 200directions. For example, the same type may be used for both a query and 201a response to the query. The same type must always be used in 202related transactions. 203 204<p>This is somewhat redundant with the JDWP framing, which includes a 2054-byte length and a two-byte type code ("command set" and "command"; a 206range of command set values is designated for "vendor-defined commands 207and extensions"). Using the chunk format allows us to remain independent 208of the underlying transport, avoids intrusive integration 209with JDWP client code, and provides a way to send multiple chunks in a 210single transmission unit. [I'm taking the multi-chunk packets into 211account in the design, but do not plan to implement them unless the need 212arises.] 213 214<p>Because we may be sending data over a slow USB link, the chunks may be 215compressed. Compressed chunks are written as a chunk type that 216indicates the compression, followed by the compressed length, followed 217by the original chunk type and the uncompressed length. For zlib's deflate 218algorithm, the chunk type is "ZLIB". 219 220<p>Following the JDWP model, packets sent from the server to the client 221are always acknowledged, but packets sent from client to server never are. 222The JDWP error code field is always set to "no error"; failure responses 223from 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 226unsigned 8-bit value. Values are written in big-endian order to match 227JDWP. 228 229 230<h3>Initial Handshake</h3> 231 232<p>After the JDWP handshake, the server sends a HELO chunk to the client. 233If the client's JDWP layer rejects it, the server assumes that the client 234is 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 236is attached and prepare accordingly. The VM should not assume that a 237debugger is attached until a non-DDM packet arrives. 238 239<h4>Chunk HELO (server --> client)</h4> 240<p>Basic "hello" message. 241<pre> 242u4 DDM server protocol version 243</pre> 244 245 246<h4>Chunk HELO (client --> server, reply only)</h4> 247Information about the client. Must be sent in response to the HELO message. 248<pre> 249u4 DDM client protocol version 250u4 pid 251u4 VM ident string len (in 16-bit units) 252u4 application name len (in 16-bit units) 253var VM ident string (UTF-16) 254var application name (UTF-16) 255</pre> 256 257<p>If the client does not wish to speak to the DDM server, it should respond 258with a JDWP error packet. This is the same behavior you'd get from a VM 259that doesn't support DDM. 260 261 262<h3>Debugger Management</h3> 263<p>VMs usually prepare for debugging when a JDWP connection is established, 264and release debugger-related resources when the connection drops. We want 265to open the JDWP connection early and hold it open after the debugger 266disconnects. 267<p>The VM can tell when a debugger attaches, because it will start seeing 268non-DDM JDWP traffic, but it can't identify the disconnect. For this reason, 269we 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 271necessary 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 276receipt. 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 285of the "pre-initialized" app processes -- it must send up one of these. 286<pre> 287u4 application name len (in 16-bit chars) 288var 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 294event. The simplest use is to tell DDMS that the VM is waiting for a 295debugger to attach. 296<pre> 297u1 reason (0 = wait for debugger) 298</pre> 299If DDMS is attached, the client VM sends this up when waitForDebugger() 300is called. If waitForDebugger() is called before DDMS attaches, the WAIT 301chunk 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 307send thread state info, e.g. 2x per 308second 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> 314u1 boolean (true=enable, false=disable) 315</pre> 316<p>The response is empty. The client generates THCR packets for all 317known threads. (Note the THCR packets may arrive before the THEN 318response.) 319 320<h4>Chunk THCR (client --> server)</h4> 321<p>Thread Creation notification. 322<pre> 323u4 VM-local thread ID (usually a small int) 324u4 thread name len (in 16-bit chars) 325var thread name (UTF-16) 326</pre> 327 328<h4>Chunk THDE (client --> server)</h4> 329<p>Thread Death notification. 330<pre> 331u4 VM-local thread ID 332</pre> 333 334<h4>Chunk THST (server --> client)</h4> 335 336<p>Enable periodic thread activity updates. 337Threads in THCR messages are assumed to be in the "initializing" state. A 338THST message should follow closely on the heels of THCR. 339<pre> 340u4 interval, in msec 341</pre> 342<p>An interval of 0 disables the updates. This is done periodically, 343rather than every time the thread state changes, to reduce the amount 344of 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 348most useful when creation/death notifications are enabled first. The 349overall layout is: 350<pre> 351u4 count 352var thread data 353</pre> 354Then, for every thread: 355<pre> 356u4 VM-local thread ID 357u1 thread state 358u1 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"? 373Do 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 375little risky in a running VM, and increases the size of the messages 376considerably, 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, 382indicating which stretches of memory are free and which are in use. For 383compactness 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 387detailed object data, so enough information is provided to associate the 388bitmap data with virtual addresses. 389 390<p>Heaps may be broken into segments within the VM, and due to memory 391constraints it may be desirable to send the bitmap in smaller pieces, 392so the protocol allows the heap data to be sent in several chunks. 393To avoid ambiguity, the client is required 394to send explicit "start" and "end" messages during an update. 395 396<p>All messages include a "heap ID" that can be used to differentiate 397between multiple independent virtual heaps or perhaps a native heap. The 398client is allowed to send information about different heaps simultaneously, 399so 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> 404u1 when to send 405</pre> 406<p>The "when" values are: 407<pre> 4080: never 4091: immediately 4102: at the next GC 4113: 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 416display. 417<pre> 418u4 number of heaps 419</pre> 420For each heap: 421<pre> 422u4 heap ID 423u8 timestamp in ms since Unix epoch 424u1 capture reason (same as 'when' value from server) 425u4 max heap size in bytes (-Xmx) 426u4 current heap size in bytes 427u4 current number of bytes allocated 428u4 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 432waste? 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> 437u1 when to send 438u1 what to send 439</pre> 440<p>The "when" to send will be zero to disable transmission, 1 to send 441during a GC. Other values are currently undefined. (Could use to pick 442which 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> 449u1 when to send 450u1 what to send 451</pre> 452<p>The "when" to send will be zero to disable transmission, 1 to send 453during 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 459existing notion of what the client's heap looks like, and prepare for 460new information. HPST indicates a virtual heap dump and must be followed 461by zero or more HPSG/HPSO messages and an HPEN. NHST indicates a native 462heap dump and must be followed by zero or more NHSG messages and an NHEN. 463 464<p>The only data item is: 465<pre> 466u4 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. 471A 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> 475u4 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 480stretch of heap memory. 481<pre> 482u4 heap ID 483u1 size of allocation unit, in bytes (e.g. 8 bytes) 484u4 virtual address of segment start 485u4 offset of this piece (relative to the virtual address) 486u4 length of piece, in allocation units 487var usage data 488</pre> 489<p>The "usage data" indicates the status of each allocation unit. The data 490is a stream of pairs of bytes, where the first byte indicates the state 491of the allocation unit, and the second byte indicates the number of 492consecutive 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 526sent. The current plan is to send it either immediately after a GC, 527or between the "mark" and "sweep" phases of the GC. For a fancy generational 528collector, 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 531length of 255 means there are 256 consecutive units with this state. In 532some cases, e.g. arrays of bytes, the actual size of the data is rounded 533up the nearest allocation unit. 534<p>For HPSG, the runs do not end at object boundaries. It is not possible 535to 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 538or dedicate the 'U' flag to indicate that we have a 16-bit length instead 539of 8-bit. We can also use a variable-width integer scheme for the length, 540encoding 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, 542array 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 545accounted for. (If these two things don't happen at the same time, the 546chunk 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). 549The client could send one chunk (allocSize=8, virtAddr=0x10000, offset=0, 550length=0x0400) or two (allocSize=8, virtAddr=0x10000, offset=0, length=0x300; 551then allocSize=8, virtAddr=0x10000, offset=0x300, length=0x100). 552<p>The client must encode the entire heap, including all free space at 553the end, or the server will not have an accurate impression of the amount 554of memory in the heap. This refers to the current heap size, not the 555maximum heap size. 556 557<h4>Chunk HPSO (client --> server)</h4> 558<p>This is essentially identical to HPSG, but the runs are terminated at 559object 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 562information can be used to gain insights into heap layout. 563<p>[Do we want to have a separate message for this? Maybe just include 564a "variant" flag in the HPST packet. Another possible form of output 565would be one that indicates the age, in generations, of each block of 566memory. That would provide a quick visual indication of "permanent vs. 567transient 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 571contiguous stretch of native heap memory. The format is the same as 572for HPSG, except that only solidity values 0 (= free) and 1 (= hard 573reference) are used, and the kind value is always 0 for free chunks 574and 7 for allocated chunks, indicating a non-VM object. 575<pre> 576u4 heap ID 577u1 size of allocation unit, in bytes (e.g. 8 bytes) 578u4 virtual address of segment start 579u4 offset of this piece (relative to the virtual address) 580u4 length of piece, in allocation units 581var usage data 582</pre> 583 584<h3>Generic Replies</h3> 585 586The client-side chunk handlers need a common way to report simple success 587or 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 591human-readable error message. Server code can associate the failure 592with the original request by comparing the JDWP packet ID. 593<p>This allows a standard way of, for example, rejecting badly-formed 594request packets. 595<pre> 596u4 error code 597u4 error message len (in 16-bit chars) 598var 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(). 605Useful for certain kinds of testing. 606<pre> 607u4 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 612size reasons we probably need "sending", "data", "key", "finished" as 6134 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 619for 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 624specific chunk types. When a DDM chunk with that type arrives, the 625appropriate handler is invoked. The handler's return value provides the 626response to the server. 627 628<p>There are two packages. android.ddm lives in the "framework" library, 629and has all of the chunk handlers and registration code. It can freely 630use Android classes. org.apache.harmony.dalvik.ddmc lives in the "core" 631library, and has 632some base classes and features that interact with the VM. Nothing should 633need 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> 638class 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> 647public Chunk handleChunk(Chunk request) 648</pre> 649<p>The code is free to parse the chunk and generate a response in any 650way 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, 652so that they can perform setup and cleanup operations: 653<pre class=prettyprint> 654public void connected() 655public void disconnected() 656</pre> 657 658<p>The method processes the request, formulates a response, and returns it. 659If the method returns null, an empty JDWP success message will be returned. 660<p>The request/response interaction is essentially asynchronous in the 661protocol. 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 663us much. Wrapping a ByteBuffer around an array is easy. We don't want 664to pass the full packet in because we could have multiple chunks in one 665request packet. The DDM code needs to collect and aggregate the responses 666to all chunks into a single JDWP response packet. Parties wanting to 667write multiple chunks in response to a single chunk should send a null 668response 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 673arbitrary time, it may do so with a method provided by 674org.apache.harmony.dalvik.DdmServer: 675 676<pre class=prettyprint> 677public 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 686use of ByteBuffer in a perhaps misguided attempt to use java.nio.channels 687and 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, 696the message must be paired with a callback method. The response might be 697delayed for a while -- or might never arrive -- so the server can't block 698waiting for responses from the client. 699<p>The chunk handlers look like this: 700<pre class=prettyprint> 701public 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 719error message and return. If the handler doesn't recognize the packet at 720all, it can call the superclass' handleUnknownChunk() method. 721 722<p>As with the client, the server code can be notified when clients 723connect or disconnect. This allows the handler to send initialization 724code immediately after a connect, or clean up after a disconnect. 725<p>Data associated with a client can be stored in a ClientData object, 726which 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> 737