OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / sdk / ddms / libs / ddmlib / src / com / android / ddmlib / ChunkHandler.java
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.android.ddmlib;
18
19 import com.android.ddmlib.DebugPortManager.IDebugPortProvider;
20
21 import java.io.IOException;
22 import java.nio.ByteBuffer;
23 import java.nio.ByteOrder;
24
25 /**
26  * Subclass this with a class that handles one or more chunk types.
27  */
28 abstract class ChunkHandler {
29
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;
32
33     public static final int CHUNK_FAIL = type("FAIL");
34
35     ChunkHandler() {}
36
37     /**
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.)
41      *
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.
45      */
46     abstract void clientReady(Client client) throws IOException;
47
48     /**
49      * Client has gone away.  Can be used to clean up any resources
50      * associated with this client connection.
51      */
52     abstract void clientDisconnected(Client client);
53
54     /**
55      * Handle an incoming chunk.  The data, of chunk type "type", begins
56      * at the start of "data" and continues to data.limit().
57      *
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.
62      *
63      * The handler may not modify the contents of "data".
64      */
65     abstract void handleChunk(Client client, int type,
66         ByteBuffer data, boolean isReply, int msgId);
67
68     /**
69      * Handle chunks not recognized by handlers.  The handleChunk() method
70      * in sub-classes should call this if the chunk type isn't recognized.
71      */
72     protected void handleUnknownChunk(Client client, int type,
73         ByteBuffer data, boolean isReply, int msgId) {
74         if (type == CHUNK_FAIL) {
75             int errorCode, msgLen;
76             String msg;
77
78             errorCode = data.getInt();
79             msgLen = data.getInt();
80             msg = getString(data, msgLen);
81             Log.w("ddms", "WARNING: failure code=" + errorCode + " msg=" + msg);
82         } else {
83             Log.w("ddms", "WARNING: received unknown chunk " + name(type)
84                 + ": len=" + data.limit() + ", reply=" + isReply
85                 + ", msgId=0x" + Integer.toHexString(msgId));
86         }
87         Log.w("ddms", "         client " + client + ", handler " + this);
88     }
89
90
91     /**
92      * Utility function to copy a String out of a ByteBuffer.
93      *
94      * This is here because multiple chunk handlers can make use of it,
95      * and there's nowhere better to put it.
96      */
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);
102     }
103
104     /**
105      * Utility function to copy a String into a ByteBuffer.
106      */
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));
111     }
112
113     /**
114      * Convert a 4-character string to a 32-bit type.
115      */
116     static int type(String typeName) {
117         int val = 0;
118
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");
122         }
123
124         for (int i = 0; i < 4; i++) {
125             val <<= 8;
126             val |= (byte) typeName.charAt(i);
127         }
128
129         return val;
130     }
131
132     /**
133      * Convert an integer type to a 4-character string.
134      */
135     static String name(int type) {
136         char[] ascii = new char[4];
137
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);
142
143         return new String(ascii);
144     }
145
146     /**
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.
150      *
151      * "maxChunkLen" indicates the size of the chunk contents only.
152      */
153     static ByteBuffer allocBuffer(int maxChunkLen) {
154         ByteBuffer buf =
155             ByteBuffer.allocate(JdwpPacket.JDWP_HEADER_LEN + 8 +maxChunkLen);
156         buf.order(CHUNK_ORDER);
157         return buf;
158     }
159
160     /**
161      * Return the slice of the JDWP packet buffer that holds just the
162      * chunk data.
163      */
164     static ByteBuffer getChunkDataBuf(ByteBuffer jdwpBuf) {
165         ByteBuffer slice;
166
167         assert jdwpBuf.position() == 0;
168
169         jdwpBuf.position(JdwpPacket.JDWP_HEADER_LEN + CHUNK_HEADER_LEN);
170         slice = jdwpBuf.slice();
171         slice.order(CHUNK_ORDER);
172         jdwpBuf.position(0);
173
174         return slice;
175     }
176
177     /**
178      * Write the chunk header at the start of the chunk.
179      *
180      * Pass in the byte buffer returned by JdwpPacket.getPayload().
181      */
182     static void finishChunkPacket(JdwpPacket packet, int type, int chunkLen) {
183         ByteBuffer buf = packet.getPayload();
184
185         buf.putInt(0x00, type);
186         buf.putInt(0x04, chunkLen);
187
188         packet.finishPacket(CHUNK_HEADER_LEN + chunkLen);
189     }
190
191     /**
192      * Check that the client is opened with the proper debugger port for the
193      * specified application name, and if not, reopen it.
194      * @param client
195      * @param uiThread
196      * @param appName
197      * @return
198      */
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);
204
205             if (newPort != IDebugPortProvider.NO_STATIC_PORT &&
206                     newPort != client.getDebuggerListenPort()) {
207
208                 AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
209                 if (bridge != null) {
210                     DeviceMonitor deviceMonitor = bridge.getDeviceMonitor();
211                     if (deviceMonitor != null) {
212                         deviceMonitor.addClientToDropAndReopen(client, newPort);
213                         client = null;
214                     }
215                 }
216             }
217         }
218
219         return client;
220     }
221 }
222