• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.ClientData.IMethodProfilingHandler;
20 import com.android.ddmlib.ClientData.MethodProfilingStatus;
21 
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 
25 /**
26  * Handle heap status updates.
27  */
28 final class HandleProfiling extends ChunkHandler {
29 
30     public static final int CHUNK_MPRS = type("MPRS");
31     public static final int CHUNK_MPRE = type("MPRE");
32     public static final int CHUNK_MPSS = type("MPSS");
33     public static final int CHUNK_MPSE = type("MPSE");
34     public static final int CHUNK_MPRQ = type("MPRQ");
35     public static final int CHUNK_FAIL = type("FAIL");
36 
37     private static final HandleProfiling mInst = new HandleProfiling();
38 
HandleProfiling()39     private HandleProfiling() {}
40 
41     /**
42      * Register for the packets we expect to get from the client.
43      */
register(MonitorThread mt)44     public static void register(MonitorThread mt) {
45         mt.registerChunkHandler(CHUNK_MPRE, mInst);
46         mt.registerChunkHandler(CHUNK_MPSE, mInst);
47         mt.registerChunkHandler(CHUNK_MPRQ, mInst);
48     }
49 
50     /**
51      * Client is ready.
52      */
53     @Override
clientReady(Client client)54     public void clientReady(Client client) throws IOException {}
55 
56     /**
57      * Client went away.
58      */
59     @Override
clientDisconnected(Client client)60     public void clientDisconnected(Client client) {}
61 
62     /**
63      * Chunk handler entry point.
64      */
65     @Override
handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId)66     public void handleChunk(Client client, int type, ByteBuffer data,
67         boolean isReply, int msgId) {
68 
69         Log.d("ddm-prof", "handling " + ChunkHandler.name(type));
70 
71         if (type == CHUNK_MPRE) {
72             handleMPRE(client, data);
73         } else if (type == CHUNK_MPSE) {
74             handleMPSE(client, data);
75         } else if (type == CHUNK_MPRQ) {
76             handleMPRQ(client, data);
77         } else if (type == CHUNK_FAIL) {
78             handleFAIL(client, data);
79         } else {
80             handleUnknownChunk(client, type, data, isReply, msgId);
81         }
82     }
83 
84     /**
85      * Send a MPRS (Method PRofiling Start) request to the client.
86      *
87      * The arguments to this method will eventually be passed to
88      * android.os.Debug.startMethodTracing() on the device.
89      *
90      * @param fileName is the name of the file to which profiling data
91      *          will be written (on the device); it will have {@link DdmConstants#DOT_TRACE}
92      *          appended if necessary
93      * @param bufferSize is the desired buffer size in bytes (8MB is good)
94      * @param flags see startMethodTracing() docs; use 0 for default behavior
95      */
sendMPRS(Client client, String fileName, int bufferSize, int flags)96     public static void sendMPRS(Client client, String fileName, int bufferSize,
97         int flags) throws IOException {
98 
99         ByteBuffer rawBuf = allocBuffer(3*4 + fileName.length() * 2);
100         JdwpPacket packet = new JdwpPacket(rawBuf);
101         ByteBuffer buf = getChunkDataBuf(rawBuf);
102 
103         buf.putInt(bufferSize);
104         buf.putInt(flags);
105         buf.putInt(fileName.length());
106         putString(buf, fileName);
107 
108         finishChunkPacket(packet, CHUNK_MPRS, buf.position());
109         Log.d("ddm-prof", "Sending " + name(CHUNK_MPRS) + " '" + fileName
110             + "', size=" + bufferSize + ", flags=" + flags);
111         client.sendAndConsume(packet, mInst);
112 
113         // record the filename we asked for.
114         client.getClientData().setPendingMethodProfiling(fileName);
115 
116         // send a status query. this ensure that the status is properly updated if for some
117         // reason starting the tracing failed.
118         sendMPRQ(client);
119     }
120 
121     /**
122      * Send a MPRE (Method PRofiling End) request to the client.
123      */
sendMPRE(Client client)124     public static void sendMPRE(Client client) throws IOException {
125         ByteBuffer rawBuf = allocBuffer(0);
126         JdwpPacket packet = new JdwpPacket(rawBuf);
127         ByteBuffer buf = getChunkDataBuf(rawBuf);
128 
129         // no data
130 
131         finishChunkPacket(packet, CHUNK_MPRE, buf.position());
132         Log.d("ddm-prof", "Sending " + name(CHUNK_MPRE));
133         client.sendAndConsume(packet, mInst);
134     }
135 
136     /**
137      * Handle notification that method profiling has finished writing
138      * data to disk.
139      */
handleMPRE(Client client, ByteBuffer data)140     private void handleMPRE(Client client, ByteBuffer data) {
141         byte result;
142 
143         // get the filename and make the client not have pending HPROF dump anymore.
144         String filename = client.getClientData().getPendingMethodProfiling();
145         client.getClientData().setPendingMethodProfiling(null);
146 
147         result = data.get();
148 
149         // get the app-level handler for method tracing dump
150         IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
151         if (handler != null) {
152             if (result == 0) {
153                 handler.onSuccess(filename, client);
154 
155                 Log.d("ddm-prof", "Method profiling has finished");
156             } else {
157                 handler.onEndFailure(client, null /*message*/);
158 
159                 Log.w("ddm-prof", "Method profiling has failed (check device log)");
160             }
161         }
162 
163         client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF);
164         client.update(Client.CHANGE_METHOD_PROFILING_STATUS);
165     }
166 
167     /**
168      * Send a MPSS (Method Profiling Streaming Start) request to the client.
169      *
170      * The arguments to this method will eventually be passed to
171      * android.os.Debug.startMethodTracing() on the device.
172      *
173      * @param bufferSize is the desired buffer size in bytes (8MB is good)
174      * @param flags see startMethodTracing() docs; use 0 for default behavior
175      */
sendMPSS(Client client, int bufferSize, int flags)176     public static void sendMPSS(Client client, int bufferSize,
177         int flags) throws IOException {
178 
179         ByteBuffer rawBuf = allocBuffer(2*4);
180         JdwpPacket packet = new JdwpPacket(rawBuf);
181         ByteBuffer buf = getChunkDataBuf(rawBuf);
182 
183         buf.putInt(bufferSize);
184         buf.putInt(flags);
185 
186         finishChunkPacket(packet, CHUNK_MPSS, buf.position());
187         Log.d("ddm-prof", "Sending " + name(CHUNK_MPSS)
188             + "', size=" + bufferSize + ", flags=" + flags);
189         client.sendAndConsume(packet, mInst);
190 
191         // send a status query. this ensure that the status is properly updated if for some
192         // reason starting the tracing failed.
193         sendMPRQ(client);
194     }
195 
196     /**
197      * Send a MPSE (Method Profiling Streaming End) request to the client.
198      */
sendMPSE(Client client)199     public static void sendMPSE(Client client) throws IOException {
200         ByteBuffer rawBuf = allocBuffer(0);
201         JdwpPacket packet = new JdwpPacket(rawBuf);
202         ByteBuffer buf = getChunkDataBuf(rawBuf);
203 
204         // no data
205 
206         finishChunkPacket(packet, CHUNK_MPSE, buf.position());
207         Log.d("ddm-prof", "Sending " + name(CHUNK_MPSE));
208         client.sendAndConsume(packet, mInst);
209     }
210 
211     /**
212      * Handle incoming profiling data.  The MPSE packet includes the
213      * complete .trace file.
214      */
handleMPSE(Client client, ByteBuffer data)215     private void handleMPSE(Client client, ByteBuffer data) {
216         IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
217         if (handler != null) {
218             byte[] stuff = new byte[data.capacity()];
219             data.get(stuff, 0, stuff.length);
220 
221             Log.d("ddm-prof", "got trace file, size: " + stuff.length + " bytes");
222 
223             handler.onSuccess(stuff, client);
224         }
225 
226         client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF);
227         client.update(Client.CHANGE_METHOD_PROFILING_STATUS);
228     }
229 
230     /**
231      * Send a MPRQ (Method PRofiling Query) request to the client.
232      */
sendMPRQ(Client client)233     public static void sendMPRQ(Client client) throws IOException {
234         ByteBuffer rawBuf = allocBuffer(0);
235         JdwpPacket packet = new JdwpPacket(rawBuf);
236         ByteBuffer buf = getChunkDataBuf(rawBuf);
237 
238         // no data
239 
240         finishChunkPacket(packet, CHUNK_MPRQ, buf.position());
241         Log.d("ddm-prof", "Sending " + name(CHUNK_MPRQ));
242         client.sendAndConsume(packet, mInst);
243     }
244 
245     /**
246      * Receive response to query.
247      */
handleMPRQ(Client client, ByteBuffer data)248     private void handleMPRQ(Client client, ByteBuffer data) {
249         byte result;
250 
251         result = data.get();
252 
253         if (result == 0) {
254             client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF);
255             Log.d("ddm-prof", "Method profiling is not running");
256         } else {
257             client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.ON);
258             Log.d("ddm-prof", "Method profiling is running");
259         }
260         client.update(Client.CHANGE_METHOD_PROFILING_STATUS);
261     }
262 
handleFAIL(Client client, ByteBuffer data)263     private void handleFAIL(Client client, ByteBuffer data) {
264         /*int errorCode =*/ data.getInt();
265         int length = data.getInt() * 2;
266         String message = null;
267         if (length > 0) {
268             byte[] messageBuffer = new byte[length];
269             data.get(messageBuffer, 0, length);
270             message = new String(messageBuffer);
271         }
272 
273         // this can be sent if
274         // - MPRS failed (like wrong permission)
275         // - MPSE failed for whatever reason
276 
277         String filename = client.getClientData().getPendingMethodProfiling();
278         if (filename != null) {
279             // reset the pending file.
280             client.getClientData().setPendingMethodProfiling(null);
281 
282             // and notify of failure
283             IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
284             if (handler != null) {
285                 handler.onStartFailure(client, message);
286             }
287         } else {
288             // this is MPRE
289             // notify of failure
290             IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
291             if (handler != null) {
292                 handler.onEndFailure(client, message);
293             }
294         }
295 
296         // send a query to know the current status
297         try {
298             sendMPRQ(client);
299         } catch (IOException e) {
300             Log.e("HandleProfiling", e);
301         }
302     }
303 }
304 
305