2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.ddmlib;
19 import com.android.ddmlib.DebugPortManager.IDebugPortProvider;
21 import java.io.IOException;
22 import java.nio.ByteBuffer;
23 import java.nio.ByteOrder;
26 * Subclass this with a class that handles one or more chunk types.
28 abstract class ChunkHandler {
30 public static final int CHUNK_HEADER_LEN = 8; // 4-byte type, 4-byte len
31 public static final ByteOrder CHUNK_ORDER = ByteOrder.BIG_ENDIAN;
33 public static final int CHUNK_FAIL = type("FAIL");
38 * Client is ready. The monitor thread calls this method on all
39 * handlers when the client is determined to be DDM-aware (usually
40 * after receiving a HELO response.)
42 * The handler can use this opportunity to initialize client-side
43 * activity. Because there's a fair chance we'll want to send a
44 * message to the client, this method can throw an IOException.
46 abstract void clientReady(Client client) throws IOException;
49 * Client has gone away. Can be used to clean up any resources
50 * associated with this client connection.
52 abstract void clientDisconnected(Client client);
55 * Handle an incoming chunk. The data, of chunk type "type", begins
56 * at the start of "data" and continues to data.limit().
58 * If "isReply" is set, then "msgId" will be the ID of the request
59 * we sent to the client. Otherwise, it's the ID generated by the
60 * client for this event. Note that it's possible to receive chunks
61 * in reply packets for which we are not registered.
63 * The handler may not modify the contents of "data".
65 abstract void handleChunk(Client client, int type,
66 ByteBuffer data, boolean isReply, int msgId);
69 * Handle chunks not recognized by handlers. The handleChunk() method
70 * in sub-classes should call this if the chunk type isn't recognized.
72 protected void handleUnknownChunk(Client client, int type,
73 ByteBuffer data, boolean isReply, int msgId) {
74 if (type == CHUNK_FAIL) {
75 int errorCode, msgLen;
78 errorCode = data.getInt();
79 msgLen = data.getInt();
80 msg = getString(data, msgLen);
81 Log.w("ddms", "WARNING: failure code=" + errorCode + " msg=" + msg);
83 Log.w("ddms", "WARNING: received unknown chunk " + name(type)
84 + ": len=" + data.limit() + ", reply=" + isReply
85 + ", msgId=0x" + Integer.toHexString(msgId));
87 Log.w("ddms", " client " + client + ", handler " + this);
92 * Utility function to copy a String out of a ByteBuffer.
94 * This is here because multiple chunk handlers can make use of it,
95 * and there's nowhere better to put it.
97 static String getString(ByteBuffer buf, int len) {
98 char[] data = new char[len];
99 for (int i = 0; i < len; i++)
100 data[i] = buf.getChar();
101 return new String(data);
105 * Utility function to copy a String into a ByteBuffer.
107 static void putString(ByteBuffer buf, String str) {
108 int len = str.length();
109 for (int i = 0; i < len; i++)
110 buf.putChar(str.charAt(i));
114 * Convert a 4-character string to a 32-bit type.
116 static int type(String typeName) {
119 if (typeName.length() != 4) {
120 Log.e("ddms", "Type name must be 4 letter long");
121 throw new RuntimeException("Type name must be 4 letter long");
124 for (int i = 0; i < 4; i++) {
126 val |= (byte) typeName.charAt(i);
133 * Convert an integer type to a 4-character string.
135 static String name(int type) {
136 char[] ascii = new char[4];
138 ascii[0] = (char) ((type >> 24) & 0xff);
139 ascii[1] = (char) ((type >> 16) & 0xff);
140 ascii[2] = (char) ((type >> 8) & 0xff);
141 ascii[3] = (char) (type & 0xff);
143 return new String(ascii);
147 * Allocate a ByteBuffer with enough space to hold the JDWP packet
148 * header and one chunk header in addition to the demands of the
149 * chunk being created.
151 * "maxChunkLen" indicates the size of the chunk contents only.
153 static ByteBuffer allocBuffer(int maxChunkLen) {
155 ByteBuffer.allocate(JdwpPacket.JDWP_HEADER_LEN + 8 +maxChunkLen);
156 buf.order(CHUNK_ORDER);
161 * Return the slice of the JDWP packet buffer that holds just the
164 static ByteBuffer getChunkDataBuf(ByteBuffer jdwpBuf) {
167 assert jdwpBuf.position() == 0;
169 jdwpBuf.position(JdwpPacket.JDWP_HEADER_LEN + CHUNK_HEADER_LEN);
170 slice = jdwpBuf.slice();
171 slice.order(CHUNK_ORDER);
178 * Write the chunk header at the start of the chunk.
180 * Pass in the byte buffer returned by JdwpPacket.getPayload().
182 static void finishChunkPacket(JdwpPacket packet, int type, int chunkLen) {
183 ByteBuffer buf = packet.getPayload();
185 buf.putInt(0x00, type);
186 buf.putInt(0x04, chunkLen);
188 packet.finishPacket(CHUNK_HEADER_LEN + chunkLen);
192 * Check that the client is opened with the proper debugger port for the
193 * specified application name, and if not, reopen it.
199 protected static Client checkDebuggerPortForAppName(Client client, String appName) {
200 IDebugPortProvider provider = DebugPortManager.getProvider();
201 if (provider != null) {
202 Device device = client.getDeviceImpl();
203 int newPort = provider.getPort(device, appName);
205 if (newPort != IDebugPortProvider.NO_STATIC_PORT &&
206 newPort != client.getDebuggerListenPort()) {
208 AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
209 if (bridge != null) {
210 DeviceMonitor deviceMonitor = bridge.getDeviceMonitor();
211 if (deviceMonitor != null) {
212 deviceMonitor.addClientToDropAndReopen(client, newPort);