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 android.ddm; 18 19 import org.apache.harmony.dalvik.ddmc.Chunk; 20 import org.apache.harmony.dalvik.ddmc.ChunkHandler; 21 import org.apache.harmony.dalvik.ddmc.DdmServer; 22 import org.apache.harmony.dalvik.ddmc.DdmVmInternal; 23 import android.os.Debug; 24 import android.util.Config; 25 import android.util.Log; 26 import java.io.IOException; 27 import java.nio.ByteBuffer; 28 29 /** 30 * Handle native and virtual heap requests. 31 */ 32 public class DdmHandleHeap extends ChunkHandler { 33 34 public static final int CHUNK_HPIF = type("HPIF"); 35 public static final int CHUNK_HPSG = type("HPSG"); 36 public static final int CHUNK_HPDU = type("HPDU"); 37 public static final int CHUNK_HPDS = type("HPDS"); 38 public static final int CHUNK_NHSG = type("NHSG"); 39 public static final int CHUNK_HPGC = type("HPGC"); 40 public static final int CHUNK_REAE = type("REAE"); 41 public static final int CHUNK_REAQ = type("REAQ"); 42 public static final int CHUNK_REAL = type("REAL"); 43 44 private static DdmHandleHeap mInstance = new DdmHandleHeap(); 45 46 47 /* singleton, do not instantiate */ 48 private DdmHandleHeap() {} 49 50 /** 51 * Register for the messages we're interested in. 52 */ 53 public static void register() { 54 DdmServer.registerHandler(CHUNK_HPIF, mInstance); 55 DdmServer.registerHandler(CHUNK_HPSG, mInstance); 56 DdmServer.registerHandler(CHUNK_HPDU, mInstance); 57 DdmServer.registerHandler(CHUNK_HPDS, mInstance); 58 DdmServer.registerHandler(CHUNK_NHSG, mInstance); 59 DdmServer.registerHandler(CHUNK_HPGC, mInstance); 60 DdmServer.registerHandler(CHUNK_REAE, mInstance); 61 DdmServer.registerHandler(CHUNK_REAQ, mInstance); 62 DdmServer.registerHandler(CHUNK_REAL, mInstance); 63 } 64 65 /** 66 * Called when the DDM server connects. The handler is allowed to 67 * send messages to the server. 68 */ 69 public void connected() {} 70 71 /** 72 * Called when the DDM server disconnects. Can be used to disable 73 * periodic transmissions or clean up saved state. 74 */ 75 public void disconnected() {} 76 77 /** 78 * Handle a chunk of data. 79 */ 80 public Chunk handleChunk(Chunk request) { 81 if (Config.LOGV) 82 Log.v("ddm-heap", "Handling " + name(request.type) + " chunk"); 83 int type = request.type; 84 85 if (type == CHUNK_HPIF) { 86 return handleHPIF(request); 87 } else if (type == CHUNK_HPSG) { 88 return handleHPSGNHSG(request, false); 89 } else if (type == CHUNK_HPDU) { 90 return handleHPDU(request); 91 } else if (type == CHUNK_HPDS) { 92 return handleHPDS(request); 93 } else if (type == CHUNK_NHSG) { 94 return handleHPSGNHSG(request, true); 95 } else if (type == CHUNK_HPGC) { 96 return handleHPGC(request); 97 } else if (type == CHUNK_REAE) { 98 return handleREAE(request); 99 } else if (type == CHUNK_REAQ) { 100 return handleREAQ(request); 101 } else if (type == CHUNK_REAL) { 102 return handleREAL(request); 103 } else { 104 throw new RuntimeException("Unknown packet " 105 + ChunkHandler.name(type)); 106 } 107 } 108 109 /* 110 * Handle a "HeaP InFo" request. 111 */ 112 private Chunk handleHPIF(Chunk request) { 113 ByteBuffer in = wrapChunk(request); 114 115 int when = in.get(); 116 if (Config.LOGV) 117 Log.v("ddm-heap", "Heap segment enable: when=" + when); 118 119 boolean ok = DdmVmInternal.heapInfoNotify(when); 120 if (!ok) { 121 return createFailChunk(1, "Unsupported HPIF what"); 122 } else { 123 return null; // empty response 124 } 125 } 126 127 /* 128 * Handle a "HeaP SeGment" or "Native Heap SeGment" request. 129 */ 130 private Chunk handleHPSGNHSG(Chunk request, boolean isNative) { 131 ByteBuffer in = wrapChunk(request); 132 133 int when = in.get(); 134 int what = in.get(); 135 if (Config.LOGV) 136 Log.v("ddm-heap", "Heap segment enable: when=" + when 137 + ", what=" + what + ", isNative=" + isNative); 138 139 boolean ok = DdmVmInternal.heapSegmentNotify(when, what, isNative); 140 if (!ok) { 141 return createFailChunk(1, "Unsupported HPSG what/when"); 142 } else { 143 // TODO: if "when" is non-zero and we want to see a dump 144 // right away, initiate a GC. 145 return null; // empty response 146 } 147 } 148 149 /* 150 * Handle a "HeaP DUmp" request. 151 * 152 * This currently just returns a result code. We could pull up 153 * the entire contents of the file and return them, but hprof dump 154 * files can be a few megabytes. 155 */ 156 private Chunk handleHPDU(Chunk request) { 157 ByteBuffer in = wrapChunk(request); 158 byte result; 159 160 /* get the filename for the output file */ 161 int len = in.getInt(); 162 String fileName = getString(in, len); 163 if (Config.LOGD) 164 Log.d("ddm-heap", "Heap dump: file='" + fileName + "'"); 165 166 try { 167 Debug.dumpHprofData(fileName); 168 result = 0; 169 } catch (UnsupportedOperationException uoe) { 170 Log.w("ddm-heap", "hprof dumps not supported in this VM"); 171 result = -1; 172 } catch (IOException ioe) { 173 result = -1; 174 } catch (RuntimeException re) { 175 result = -1; 176 } 177 178 /* create a non-empty reply so the handler fires on completion */ 179 byte[] reply = { result }; 180 return new Chunk(CHUNK_HPDU, reply, 0, reply.length); 181 } 182 183 /* 184 * Handle a "HeaP Dump Streaming" request. 185 * 186 * This tells the VM to create a heap dump and send it directly to 187 * DDMS. The dumps are large enough that we don't want to copy the 188 * data into a byte[] and send it from here. 189 */ 190 private Chunk handleHPDS(Chunk request) { 191 ByteBuffer in = wrapChunk(request); 192 byte result; 193 194 /* get the filename for the output file */ 195 if (Config.LOGD) 196 Log.d("ddm-heap", "Heap dump: [DDMS]"); 197 198 String failMsg = null; 199 try { 200 Debug.dumpHprofDataDdms(); 201 } catch (UnsupportedOperationException uoe) { 202 failMsg = "hprof dumps not supported in this VM"; 203 } catch (RuntimeException re) { 204 failMsg = "Exception: " + re.getMessage(); 205 } 206 207 if (failMsg != null) { 208 Log.w("ddm-heap", failMsg); 209 return createFailChunk(1, failMsg); 210 } else { 211 return null; 212 } 213 } 214 215 /* 216 * Handle a "HeaP Garbage Collection" request. 217 */ 218 private Chunk handleHPGC(Chunk request) { 219 //ByteBuffer in = wrapChunk(request); 220 221 if (Config.LOGD) 222 Log.d("ddm-heap", "Heap GC request"); 223 System.gc(); 224 225 return null; // empty response 226 } 227 228 /* 229 * Handle a "REcent Allocation Enable" request. 230 */ 231 private Chunk handleREAE(Chunk request) { 232 ByteBuffer in = wrapChunk(request); 233 boolean enable; 234 235 enable = (in.get() != 0); 236 237 if (Config.LOGD) 238 Log.d("ddm-heap", "Recent allocation enable request: " + enable); 239 240 DdmVmInternal.enableRecentAllocations(enable); 241 242 return null; // empty response 243 } 244 245 /* 246 * Handle a "REcent Allocation Query" request. 247 */ 248 private Chunk handleREAQ(Chunk request) { 249 //ByteBuffer in = wrapChunk(request); 250 251 byte[] reply = new byte[1]; 252 reply[0] = DdmVmInternal.getRecentAllocationStatus() ? (byte)1 :(byte)0; 253 return new Chunk(CHUNK_REAQ, reply, 0, reply.length); 254 } 255 256 /* 257 * Handle a "REcent ALlocations" request. 258 */ 259 private Chunk handleREAL(Chunk request) { 260 //ByteBuffer in = wrapChunk(request); 261 262 if (Config.LOGD) 263 Log.d("ddm-heap", "Recent allocations request"); 264 265 /* generate the reply in a ready-to-go format */ 266 byte[] reply = DdmVmInternal.getRecentAllocations(); 267 return new Chunk(CHUNK_REAL, reply, 0, reply.length); 268 } 269 } 270 271