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 17package com.android.ddmlib; 18 19import java.io.BufferedReader; 20import java.io.ByteArrayInputStream; 21import java.io.IOException; 22import java.io.InputStreamReader; 23import java.nio.ByteBuffer; 24import java.nio.ByteOrder; 25 26/** 27 * Handle thread status updates. 28 */ 29final class HandleNativeHeap extends ChunkHandler { 30 31 public static final int CHUNK_NHGT = type("NHGT"); //$NON-NLS-1$ 32 public static final int CHUNK_NHSG = type("NHSG"); //$NON-NLS-1$ 33 public static final int CHUNK_NHST = type("NHST"); //$NON-NLS-1$ 34 public static final int CHUNK_NHEN = type("NHEN"); //$NON-NLS-1$ 35 36 private static final HandleNativeHeap mInst = new HandleNativeHeap(); 37 38 private HandleNativeHeap() { 39 } 40 41 42 /** 43 * Register for the packets we expect to get from the client. 44 */ 45 public static void register(MonitorThread mt) { 46 mt.registerChunkHandler(CHUNK_NHGT, mInst); 47 mt.registerChunkHandler(CHUNK_NHSG, mInst); 48 mt.registerChunkHandler(CHUNK_NHST, mInst); 49 mt.registerChunkHandler(CHUNK_NHEN, mInst); 50 } 51 52 /** 53 * Client is ready. 54 */ 55 @Override 56 public void clientReady(Client client) throws IOException {} 57 58 /** 59 * Client went away. 60 */ 61 @Override 62 public void clientDisconnected(Client client) {} 63 64 /** 65 * Chunk handler entry point. 66 */ 67 @Override 68 public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) { 69 70 Log.d("ddm-nativeheap", "handling " + ChunkHandler.name(type)); 71 72 if (type == CHUNK_NHGT) { 73 handleNHGT(client, data); 74 } else if (type == CHUNK_NHST) { 75 // start chunk before any NHSG chunk(s) 76 client.getClientData().getNativeHeapData().clearHeapData(); 77 } else if (type == CHUNK_NHEN) { 78 // end chunk after NHSG chunk(s) 79 client.getClientData().getNativeHeapData().sealHeapData(); 80 } else if (type == CHUNK_NHSG) { 81 handleNHSG(client, data); 82 } else { 83 handleUnknownChunk(client, type, data, isReply, msgId); 84 } 85 86 client.update(Client.CHANGE_NATIVE_HEAP_DATA); 87 } 88 89 /** 90 * Send an NHGT (Native Thread GeT) request to the client. 91 */ 92 public static void sendNHGT(Client client) throws IOException { 93 94 ByteBuffer rawBuf = allocBuffer(0); 95 JdwpPacket packet = new JdwpPacket(rawBuf); 96 ByteBuffer buf = getChunkDataBuf(rawBuf); 97 98 // no data in request message 99 100 finishChunkPacket(packet, CHUNK_NHGT, buf.position()); 101 Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHGT)); 102 client.sendAndConsume(packet, mInst); 103 104 rawBuf = allocBuffer(2); 105 packet = new JdwpPacket(rawBuf); 106 buf = getChunkDataBuf(rawBuf); 107 108 buf.put((byte)HandleHeap.WHEN_DISABLE); 109 buf.put((byte)HandleHeap.WHAT_OBJ); 110 111 finishChunkPacket(packet, CHUNK_NHSG, buf.position()); 112 Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHSG)); 113 client.sendAndConsume(packet, mInst); 114 } 115 116 /* 117 * Handle our native heap data. 118 */ 119 private void handleNHGT(Client client, ByteBuffer data) { 120 ClientData cd = client.getClientData(); 121 122 Log.d("ddm-nativeheap", "NHGT: " + data.limit() + " bytes"); 123 124 // TODO - process incoming data and save in "cd" 125 byte[] copy = new byte[data.limit()]; 126 data.get(copy); 127 128 // clear the previous run 129 cd.clearNativeAllocationInfo(); 130 131 ByteBuffer buffer = ByteBuffer.wrap(copy); 132 buffer.order(ByteOrder.LITTLE_ENDIAN); 133 134// read the header 135// typedef struct Header { 136// uint32_t mapSize; 137// uint32_t allocSize; 138// uint32_t allocInfoSize; 139// uint32_t totalMemory; 140// uint32_t backtraceSize; 141// }; 142 143 int mapSize = buffer.getInt(); 144 int allocSize = buffer.getInt(); 145 int allocInfoSize = buffer.getInt(); 146 int totalMemory = buffer.getInt(); 147 int backtraceSize = buffer.getInt(); 148 149 Log.d("ddms", "mapSize: " + mapSize); 150 Log.d("ddms", "allocSize: " + allocSize); 151 Log.d("ddms", "allocInfoSize: " + allocInfoSize); 152 Log.d("ddms", "totalMemory: " + totalMemory); 153 154 cd.setTotalNativeMemory(totalMemory); 155 156 // this means that updates aren't turned on. 157 if (allocInfoSize == 0) 158 return; 159 160 if (mapSize > 0) { 161 byte[] maps = new byte[mapSize]; 162 buffer.get(maps, 0, mapSize); 163 parseMaps(cd, maps); 164 } 165 166 int iterations = allocSize / allocInfoSize; 167 168 for (int i = 0 ; i < iterations ; i++) { 169 NativeAllocationInfo info = new NativeAllocationInfo( 170 buffer.getInt() /* size */, 171 buffer.getInt() /* allocations */); 172 173 for (int j = 0 ; j < backtraceSize ; j++) { 174 long addr = (buffer.getInt()) & 0x00000000ffffffffL; 175 176 if (addr == 0x0) { 177 // skip past null addresses 178 continue; 179 } 180 181 info.addStackCallAddress(addr);; 182 } 183 184 cd.addNativeAllocation(info); 185 } 186 } 187 188 private void handleNHSG(Client client, ByteBuffer data) { 189 byte dataCopy[] = new byte[data.limit()]; 190 data.rewind(); 191 data.get(dataCopy); 192 data = ByteBuffer.wrap(dataCopy); 193 client.getClientData().getNativeHeapData().addHeapData(data); 194 195 if (true) { 196 return; 197 } 198 199 // WORK IN PROGRESS 200 201// Log.e("ddm-nativeheap", "NHSG: ----------------------------------"); 202// Log.e("ddm-nativeheap", "NHSG: " + data.limit() + " bytes"); 203 204 byte[] copy = new byte[data.limit()]; 205 data.get(copy); 206 207 ByteBuffer buffer = ByteBuffer.wrap(copy); 208 buffer.order(ByteOrder.BIG_ENDIAN); 209 210 int id = buffer.getInt(); 211 int unitsize = buffer.get(); 212 long startAddress = buffer.getInt() & 0x00000000ffffffffL; 213 int offset = buffer.getInt(); 214 int allocationUnitCount = buffer.getInt(); 215 216// Log.e("ddm-nativeheap", "id: " + id); 217// Log.e("ddm-nativeheap", "unitsize: " + unitsize); 218// Log.e("ddm-nativeheap", "startAddress: 0x" + Long.toHexString(startAddress)); 219// Log.e("ddm-nativeheap", "offset: " + offset); 220// Log.e("ddm-nativeheap", "allocationUnitCount: " + allocationUnitCount); 221// Log.e("ddm-nativeheap", "end: 0x" + 222// Long.toHexString(startAddress + unitsize * allocationUnitCount)); 223 224 // read the usage 225 while (buffer.position() < buffer.limit()) { 226 int eState = buffer.get() & 0x000000ff; 227 int eLen = (buffer.get() & 0x000000ff) + 1; 228 //Log.e("ddm-nativeheap", "solidity: " + (eState & 0x7) + " - kind: " 229 // + ((eState >> 3) & 0x7) + " - len: " + eLen); 230 } 231 232 233// count += unitsize * allocationUnitCount; 234// Log.e("ddm-nativeheap", "count = " + count); 235 236 } 237 238 private void parseMaps(ClientData cd, byte[] maps) { 239 InputStreamReader input = new InputStreamReader(new ByteArrayInputStream(maps)); 240 BufferedReader reader = new BufferedReader(input); 241 242 String line; 243 244 try { 245 246 // most libraries are defined on several lines, so we need to make sure we parse 247 // all the library lines and only add the library at the end 248 long startAddr = 0; 249 long endAddr = 0; 250 String library = null; 251 252 while ((line = reader.readLine()) != null) { 253 Log.d("ddms", "line: " + line); 254 if (line.length() < 16) { 255 continue; 256 } 257 258 try { 259 long tmpStart = Long.parseLong(line.substring(0, 8), 16); 260 long tmpEnd = Long.parseLong(line.substring(9, 17), 16); 261 262 int index = line.indexOf('/'); 263 264 if (index == -1) 265 continue; 266 267 String tmpLib = line.substring(index); 268 269 if (library == null || 270 (library != null && tmpLib.equals(library) == false)) { 271 272 if (library != null) { 273 cd.addNativeLibraryMapInfo(startAddr, endAddr, library); 274 Log.d("ddms", library + "(" + Long.toHexString(startAddr) + 275 " - " + Long.toHexString(endAddr) + ")"); 276 } 277 278 // now init the new library 279 library = tmpLib; 280 startAddr = tmpStart; 281 endAddr = tmpEnd; 282 } else { 283 // add the new end 284 endAddr = tmpEnd; 285 } 286 } catch (NumberFormatException e) { 287 e.printStackTrace(); 288 } 289 } 290 291 if (library != null) { 292 cd.addNativeLibraryMapInfo(startAddr, endAddr, library); 293 Log.d("ddms", library + "(" + Long.toHexString(startAddr) + 294 " - " + Long.toHexString(endAddr) + ")"); 295 } 296 } catch (IOException e) { 297 e.printStackTrace(); 298 } 299 } 300 301 302} 303 304