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 com.android.ddmlib; 18 19 import java.io.BufferedReader; 20 import java.io.ByteArrayInputStream; 21 import java.io.IOException; 22 import java.io.InputStreamReader; 23 import java.nio.ByteBuffer; 24 import java.nio.ByteOrder; 25 26 /** 27 * Handle thread status updates. 28 */ 29 final 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_GC); 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 = ((long)buffer.getInt()) & 0x00000000ffffffffL; 175 176 info.addStackCallAddress(addr);; 177 } 178 179 cd.addNativeAllocation(info); 180 } 181 } 182 183 private void handleNHSG(Client client, ByteBuffer data) { 184 byte dataCopy[] = new byte[data.limit()]; 185 data.rewind(); 186 data.get(dataCopy); 187 data = ByteBuffer.wrap(dataCopy); 188 client.getClientData().getNativeHeapData().addHeapData(data); 189 190 if (true) { 191 return; 192 } 193 194 // WORK IN PROGRESS 195 196 // Log.e("ddm-nativeheap", "NHSG: ----------------------------------"); 197 // Log.e("ddm-nativeheap", "NHSG: " + data.limit() + " bytes"); 198 199 byte[] copy = new byte[data.limit()]; 200 data.get(copy); 201 202 ByteBuffer buffer = ByteBuffer.wrap(copy); 203 buffer.order(ByteOrder.BIG_ENDIAN); 204 205 int id = buffer.getInt(); 206 int unitsize = (int) buffer.get(); 207 long startAddress = (long) buffer.getInt() & 0x00000000ffffffffL; 208 int offset = buffer.getInt(); 209 int allocationUnitCount = buffer.getInt(); 210 211 // Log.e("ddm-nativeheap", "id: " + id); 212 // Log.e("ddm-nativeheap", "unitsize: " + unitsize); 213 // Log.e("ddm-nativeheap", "startAddress: 0x" + Long.toHexString(startAddress)); 214 // Log.e("ddm-nativeheap", "offset: " + offset); 215 // Log.e("ddm-nativeheap", "allocationUnitCount: " + allocationUnitCount); 216 // Log.e("ddm-nativeheap", "end: 0x" + 217 // Long.toHexString(startAddress + unitsize * allocationUnitCount)); 218 219 // read the usage 220 while (buffer.position() < buffer.limit()) { 221 int eState = (int)buffer.get() & 0x000000ff; 222 int eLen = ((int)buffer.get() & 0x000000ff) + 1; 223 //Log.e("ddm-nativeheap", "solidity: " + (eState & 0x7) + " - kind: " 224 // + ((eState >> 3) & 0x7) + " - len: " + eLen); 225 } 226 227 228 // count += unitsize * allocationUnitCount; 229 // Log.e("ddm-nativeheap", "count = " + count); 230 231 } 232 233 private void parseMaps(ClientData cd, byte[] maps) { 234 InputStreamReader input = new InputStreamReader(new ByteArrayInputStream(maps)); 235 BufferedReader reader = new BufferedReader(input); 236 237 String line; 238 239 try { 240 241 // most libraries are defined on several lines, so we need to make sure we parse 242 // all the library lines and only add the library at the end 243 long startAddr = 0; 244 long endAddr = 0; 245 String library = null; 246 247 while ((line = reader.readLine()) != null) { 248 Log.d("ddms", "line: " + line); 249 if (line.length() < 16) { 250 continue; 251 } 252 253 try { 254 long tmpStart = Long.parseLong(line.substring(0, 8), 16); 255 long tmpEnd = Long.parseLong(line.substring(9, 17), 16); 256 257 /* 258 * only check for library addresses as defined in 259 * //device/config/prelink-linux-arm.map 260 */ 261 if (tmpStart >= 0x0000000080000000L && tmpStart <= 0x00000000BFFFFFFFL) { 262 263 int index = line.indexOf('/'); 264 265 if (index == -1) 266 continue; 267 268 String tmpLib = line.substring(index); 269 270 if (library == null || 271 (library != null && tmpLib.equals(library) == false)) { 272 273 if (library != null) { 274 cd.addNativeLibraryMapInfo(startAddr, endAddr, library); 275 Log.d("ddms", library + "(" + Long.toHexString(startAddr) + 276 " - " + Long.toHexString(endAddr) + ")"); 277 } 278 279 // now init the new library 280 library = tmpLib; 281 startAddr = tmpStart; 282 endAddr = tmpEnd; 283 } else { 284 // add the new end 285 endAddr = tmpEnd; 286 } 287 } 288 } catch (NumberFormatException e) { 289 e.printStackTrace(); 290 } 291 } 292 293 if (library != null) { 294 cd.addNativeLibraryMapInfo(startAddr, endAddr, library); 295 Log.d("ddms", library + "(" + Long.toHexString(startAddr) + 296 " - " + Long.toHexString(endAddr) + ")"); 297 } 298 } catch (IOException e) { 299 e.printStackTrace(); 300 } 301 } 302 303 304 } 305 306