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_MPRQ = type("MPRQ"); 33 public static final int CHUNK_FAIL = type("FAIL"); 34 35 private static final HandleProfiling mInst = new HandleProfiling(); 36 HandleProfiling()37 private HandleProfiling() {} 38 39 /** 40 * Register for the packets we expect to get from the client. 41 */ register(MonitorThread mt)42 public static void register(MonitorThread mt) { 43 mt.registerChunkHandler(CHUNK_MPRE, mInst); 44 mt.registerChunkHandler(CHUNK_MPRQ, mInst); 45 } 46 47 /** 48 * Client is ready. 49 */ 50 @Override clientReady(Client client)51 public void clientReady(Client client) throws IOException {} 52 53 /** 54 * Client went away. 55 */ 56 @Override clientDisconnected(Client client)57 public void clientDisconnected(Client client) {} 58 59 /** 60 * Chunk handler entry point. 61 */ 62 @Override handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId)63 public void handleChunk(Client client, int type, ByteBuffer data, 64 boolean isReply, int msgId) { 65 66 Log.d("ddm-prof", "handling " + ChunkHandler.name(type)); 67 68 if (type == CHUNK_MPRE) { 69 handleMPRE(client, data); 70 } else if (type == CHUNK_MPRQ) { 71 handleMPRQ(client, data); 72 } else if (type == CHUNK_FAIL) { 73 handleFAIL(client, data); 74 } else { 75 handleUnknownChunk(client, type, data, isReply, msgId); 76 } 77 } 78 79 /** 80 * Send a MPRS (Method PRofiling Start) request to the client. 81 * 82 * The arguments to this method will eventually be passed to 83 * android.os.Debug.startMethodTracing() on the device. 84 * 85 * @param fileName is the name of the file to which profiling data 86 * will be written (on the device); it will have ".trace" 87 * appended if necessary 88 * @param bufferSize is the desired buffer size in bytes (8MB is good) 89 * @param flags see startMethodTracing() docs; use 0 for default behavior 90 */ sendMPRS(Client client, String fileName, int bufferSize, int flags)91 public static void sendMPRS(Client client, String fileName, int bufferSize, 92 int flags) throws IOException { 93 94 ByteBuffer rawBuf = allocBuffer(3*4 + fileName.length() * 2); 95 JdwpPacket packet = new JdwpPacket(rawBuf); 96 ByteBuffer buf = getChunkDataBuf(rawBuf); 97 98 buf.putInt(bufferSize); 99 buf.putInt(flags); 100 buf.putInt(fileName.length()); 101 putString(buf, fileName); 102 103 finishChunkPacket(packet, CHUNK_MPRS, buf.position()); 104 Log.d("ddm-prof", "Sending " + name(CHUNK_MPRS) + " '" + fileName 105 + "', size=" + bufferSize + ", flags=" + flags); 106 client.sendAndConsume(packet, mInst); 107 108 // record the filename we asked for. 109 client.getClientData().setPendingMethodProfiling(fileName); 110 111 // send a status query. this ensure that the status is properly updated if for some 112 // reason starting the tracing failed. 113 sendMPRQ(client); 114 } 115 116 /** 117 * Send a MPRE (Method PRofiling End) request to the client. 118 */ sendMPRE(Client client)119 public static void sendMPRE(Client client) throws IOException { 120 ByteBuffer rawBuf = allocBuffer(0); 121 JdwpPacket packet = new JdwpPacket(rawBuf); 122 ByteBuffer buf = getChunkDataBuf(rawBuf); 123 124 // no data 125 126 finishChunkPacket(packet, CHUNK_MPRE, buf.position()); 127 Log.d("ddm-prof", "Sending " + name(CHUNK_MPRE)); 128 client.sendAndConsume(packet, mInst); 129 } 130 131 /** 132 * Handle notification that method profiling has finished writing 133 * data to disk. 134 */ handleMPRE(Client client, ByteBuffer data)135 private void handleMPRE(Client client, ByteBuffer data) { 136 byte result; 137 138 // get the filename and make the client not have pending HPROF dump anymore. 139 String filename = client.getClientData().getPendingMethodProfiling(); 140 client.getClientData().setPendingMethodProfiling(null); 141 142 result = data.get(); 143 144 // get the app-level handler for method tracing dump 145 IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler(); 146 if (handler != null) { 147 if (result == 0) { 148 handler.onSuccess(filename, client); 149 150 Log.d("ddm-prof", "Method profiling has finished"); 151 } else { 152 handler.onFailure(client); 153 154 Log.w("ddm-prof", "Method profiling has failed (check device log)"); 155 } 156 } 157 158 client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF); 159 client.update(Client.CHANGE_METHOD_PROFILING_STATUS); 160 } 161 162 /** 163 * Send a MPRQ (Method PRofiling Query) request to the client. 164 */ sendMPRQ(Client client)165 public static void sendMPRQ(Client client) throws IOException { 166 ByteBuffer rawBuf = allocBuffer(0); 167 JdwpPacket packet = new JdwpPacket(rawBuf); 168 ByteBuffer buf = getChunkDataBuf(rawBuf); 169 170 // no data 171 172 finishChunkPacket(packet, CHUNK_MPRQ, buf.position()); 173 Log.d("ddm-prof", "Sending " + name(CHUNK_MPRQ)); 174 client.sendAndConsume(packet, mInst); 175 } 176 177 /** 178 * Receive response to query. 179 */ handleMPRQ(Client client, ByteBuffer data)180 private void handleMPRQ(Client client, ByteBuffer data) { 181 byte result; 182 183 result = data.get(); 184 185 if (result == 0) { 186 client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF); 187 Log.d("ddm-prof", "Method profiling is not running"); 188 } else { 189 client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.ON); 190 Log.d("ddm-prof", "Method profiling is running"); 191 } 192 client.update(Client.CHANGE_METHOD_PROFILING_STATUS); 193 } 194 handleFAIL(Client client, ByteBuffer data)195 private void handleFAIL(Client client, ByteBuffer data) { 196 // this can be sent if MPRS failed (like wrong permission) 197 198 String filename = client.getClientData().getPendingMethodProfiling(); 199 if (filename != null) { 200 // reset the pending file. 201 client.getClientData().setPendingMethodProfiling(null); 202 203 // and notify of failure 204 IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler(); 205 if (handler != null) { 206 handler.onFailure(client); 207 } 208 209 } 210 211 // send a query to know the current status 212 try { 213 sendMPRQ(client); 214 } catch (IOException e) { 215 Log.e("HandleProfiling", e); 216 } 217 } 218 } 219 220