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