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_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