Home | History | Annotate | Download | only in ddmlib
      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_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