FileDocCategorySizeDatePackage
HandleHeap.javaAPI DocAndroid 1.5 API17070Wed May 06 22:41:08 BST 2009com.android.ddmlib

HandleHeap

public final class HandleHeap extends ChunkHandler
Handle heap status updates.

Fields Summary
public static final int
CHUNK_HPIF
public static final int
CHUNK_HPST
public static final int
CHUNK_HPEN
public static final int
CHUNK_HPSG
public static final int
CHUNK_HPGC
public static final int
CHUNK_REAE
public static final int
CHUNK_REAQ
public static final int
CHUNK_REAL
public static final int
WHEN_DISABLE
public static final int
WHEN_GC
public static final int
WHAT_MERGE
public static final int
WHAT_OBJ
public static final int
HPIF_WHEN_NEVER
public static final int
HPIF_WHEN_NOW
public static final int
HPIF_WHEN_NEXT_GC
public static final int
HPIF_WHEN_EVERY_GC
private static final HandleHeap
mInst
Constructors Summary
private HandleHeap()


      
Methods Summary
public voidclientDisconnected(Client client)
Client went away.

public voidclientReady(Client client)
Client is ready.

        if (client.isHeapUpdateEnabled()) {
            //sendHPSG(client, WHEN_GC, WHAT_MERGE);
            sendHPIF(client, HPIF_WHEN_EVERY_GC);
        }
    
private java.lang.StringdescriptorToDot(java.lang.String str)
Converts a VM class descriptor string ("Landroid/os/Debug;") to a dot-notation class name ("android.os.Debug").

        // count the number of arrays.
        int array = 0;
        while (str.startsWith("[")) {
            str = str.substring(1);
            array++;
        }

        int len = str.length();

        /* strip off leading 'L' and trailing ';' if appropriate */
        if (len >= 2 && str.charAt(0) == 'L" && str.charAt(len - 1) == ';") {
            str = str.substring(1, len-1);
            str = str.replace('/", '.");
        } else {
            // convert the basic types
            if ("C".equals(str)) {
                str = "char";
            } else if ("B".equals(str)) {
                str = "byte";
            } else if ("Z".equals(str)) {
                str = "boolean";
            } else if ("S".equals(str)) {
                str = "short";
            } else if ("I".equals(str)) {
                str = "int";
            } else if ("J".equals(str)) {
                str = "long";
            } else if ("F".equals(str)) {
                str = "float";
            } else if ("D".equals(str)) {
                str = "double";
            }
        }
        
        // now add the array part
        for (int a = 0 ; a < array; a++) {
            str = str + "[]";
        }

        return str;
    
private static voiddumpRecords(AllocationInfo[] records)

        System.out.println("Found " + records.length + " records:");

        for (AllocationInfo rec: records) {
            System.out.println("tid=" + rec.getThreadId() + " "
                + rec.getAllocatedClass() + " (" + rec.getSize() + " bytes)");

            for (StackTraceElement ste: rec.getStackTrace()) {
                if (ste.isNativeMethod()) {
                    System.out.println("    " + ste.getClassName() 
                        + "." + ste.getMethodName()
                        + " (Native method)");
                } else {
                    System.out.println("    " + ste.getClassName() 
                        + "." + ste.getMethodName()
                        + " (" + ste.getFileName()
                        + ":" + ste.getLineNumber() + ")");
                }
            }
        }
    
public voidhandleChunk(Client client, int type, java.nio.ByteBuffer data, boolean isReply, int msgId)
Chunk handler entry point.

        Log.d("ddm-heap", "handling " + ChunkHandler.name(type));

        if (type == CHUNK_HPIF) {
            handleHPIF(client, data);
            client.update(Client.CHANGE_HEAP_DATA);
        } else if (type == CHUNK_HPST) {
            handleHPST(client, data);
        } else if (type == CHUNK_HPEN) {
            handleHPEN(client, data);
            client.update(Client.CHANGE_HEAP_DATA);
        } else if (type == CHUNK_HPSG) {
            handleHPSG(client, data);
        } else if (type == CHUNK_REAQ) {
            handleREAQ(client, data);
            client.update(Client.CHANGE_HEAP_ALLOCATION_STATUS);
        } else if (type == CHUNK_REAL) {
            handleREAL(client, data);
            client.update(Client.CHANGE_HEAP_ALLOCATIONS);
        } else {
            handleUnknownChunk(client, type, data, isReply, msgId);
        }
    
private voidhandleHPEN(Client client, java.nio.ByteBuffer data)

        /* Let the UI know that we've received all of the
         * data for this heap.
         */
//xxx todo: only seal data that belongs to the heap mentioned in <data>.
        client.getClientData().getVmHeapData().sealHeapData();
    
private voidhandleHPIF(Client client, java.nio.ByteBuffer data)

        Log.d("ddm-heap", "HPIF!");
        try {
            int numHeaps = data.getInt();

            for (int i = 0; i < numHeaps; i++) {
                int heapId = data.getInt();
                @SuppressWarnings("unused")
                long timeStamp = data.getLong();
                @SuppressWarnings("unused")
                byte reason = data.get();
                long maxHeapSize = (long)data.getInt() & 0x00ffffffff;
                long heapSize = (long)data.getInt() & 0x00ffffffff;
                long bytesAllocated = (long)data.getInt() & 0x00ffffffff;
                long objectsAllocated = (long)data.getInt() & 0x00ffffffff;

                client.getClientData().setHeapInfo(heapId, maxHeapSize,
                        heapSize, bytesAllocated, objectsAllocated);
            }
        } catch (BufferUnderflowException ex) {
            Log.w("ddm-heap", "malformed HPIF chunk from client");
        }
    
private voidhandleHPSG(Client client, java.nio.ByteBuffer data)

        byte dataCopy[] = new byte[data.limit()];
        data.rewind();
        data.get(dataCopy);
        data = ByteBuffer.wrap(dataCopy);
        client.getClientData().getVmHeapData().addHeapData(data);
//xxx todo: add to the heap mentioned in <data>
    
private voidhandleHPST(Client client, java.nio.ByteBuffer data)

        /* Clear out any data that's sitting around to
         * get ready for the chunks that are about to come.
         */
//xxx todo: only clear data that belongs to the heap mentioned in <data>.
        client.getClientData().getVmHeapData().clearHeapData();
    
private voidhandleREAL(Client client, java.nio.ByteBuffer data)

        Log.e("ddm-heap", "*** Received " + name(CHUNK_REAL));
        int messageHdrLen, entryHdrLen, stackFrameLen;
        int numEntries, offsetToStrings;
        int numClassNames, numMethodNames, numFileNames;

        /*
         * Read the header.
         */
        messageHdrLen = (data.get() & 0xff);
        entryHdrLen = (data.get() & 0xff);
        stackFrameLen = (data.get() & 0xff);
        numEntries = (data.getShort() & 0xffff);
        offsetToStrings = data.getInt();
        numClassNames = (data.getShort() & 0xffff);
        numMethodNames = (data.getShort() & 0xffff);
        numFileNames = (data.getShort() & 0xffff);


        /*
         * Skip forward to the strings and read them.
         */
        data.position(offsetToStrings);

        String[] classNames = new String[numClassNames];
        String[] methodNames = new String[numMethodNames];
        String[] fileNames = new String[numFileNames];

        readStringTable(data, classNames);
        readStringTable(data, methodNames);
        //System.out.println("METHODS: "
        //    + java.util.Arrays.deepToString(methodNames));
        readStringTable(data, fileNames);

        /*
         * Skip back to a point just past the header and start reading
         * entries.
         */
        data.position(messageHdrLen);

        ArrayList<AllocationInfo> list = new ArrayList<AllocationInfo>(numEntries);
        for (int i = 0; i < numEntries; i++) {
            int totalSize;
            int threadId, classNameIndex, stackDepth;

            totalSize = data.getInt();
            threadId = (data.getShort() & 0xffff);
            classNameIndex = (data.getShort() & 0xffff);
            stackDepth = (data.get() & 0xff);
            /* we've consumed 9 bytes; gobble up any extra */
            for (int skip = 9; skip < entryHdrLen; skip++)
                data.get();

            StackTraceElement[] steArray = new StackTraceElement[stackDepth];

            /*
             * Pull out the stack trace.
             */
            for (int sti = 0; sti < stackDepth; sti++) {
                int methodClassNameIndex, methodNameIndex;
                int methodSourceFileIndex;
                short lineNumber;
                String methodClassName, methodName, methodSourceFile;

                methodClassNameIndex = (data.getShort() & 0xffff);
                methodNameIndex = (data.getShort() & 0xffff);
                methodSourceFileIndex = (data.getShort() & 0xffff);
                lineNumber = data.getShort();

                methodClassName = classNames[methodClassNameIndex];
                methodName = methodNames[methodNameIndex];
                methodSourceFile = fileNames[methodSourceFileIndex];

                steArray[sti] = new StackTraceElement(methodClassName,
                    methodName, methodSourceFile, lineNumber);

                /* we've consumed 8 bytes; gobble up any extra */
                for (int skip = 9; skip < stackFrameLen; skip++)
                    data.get();
            }

            list.add(new AllocationInfo(classNames[classNameIndex],
                totalSize, (short) threadId, steArray));
        }
        
        // sort biggest allocations first.
        Collections.sort(list);
        
        client.getClientData().setAllocations(list.toArray(new AllocationInfo[numEntries]));
    
private voidhandleREAQ(Client client, java.nio.ByteBuffer data)

        boolean enabled;

        enabled = (data.get() != 0);
        Log.d("ddm-heap", "REAQ says: enabled=" + enabled);
        
        client.getClientData().setAllocationStatus(enabled);
    
private voidreadStringTable(java.nio.ByteBuffer data, java.lang.String[] strings)
Reads a string table out of "data". This is just a serial collection of strings, each of which is a four-byte length followed by UTF-16 data.

        int count = strings.length;
        int i;

        for (i = 0; i < count; i++) {
            int nameLen = data.getInt();
            String descriptor = getString(data, nameLen);
            strings[i] = descriptorToDot(descriptor);
        }
    
public static voidregister(MonitorThread mt)
Register for the packets we expect to get from the client.

        mt.registerChunkHandler(CHUNK_HPIF, mInst);
        mt.registerChunkHandler(CHUNK_HPST, mInst);
        mt.registerChunkHandler(CHUNK_HPEN, mInst);
        mt.registerChunkHandler(CHUNK_HPSG, mInst);
        mt.registerChunkHandler(CHUNK_REAQ, mInst);
        mt.registerChunkHandler(CHUNK_REAL, mInst);
    
public static voidsendHPGC(Client client)
Sends an HPGC request to the client.

        ByteBuffer rawBuf = allocBuffer(0);
        JdwpPacket packet = new JdwpPacket(rawBuf);
        ByteBuffer buf = getChunkDataBuf(rawBuf);

        // no data

        finishChunkPacket(packet, CHUNK_HPGC, buf.position());
        Log.d("ddm-heap", "Sending " + name(CHUNK_HPGC));
        client.sendAndConsume(packet, mInst);
    
public static voidsendHPIF(Client client, int when)
Send an HPIF (HeaP InFo) request to the client.

        ByteBuffer rawBuf = allocBuffer(1);
        JdwpPacket packet = new JdwpPacket(rawBuf);
        ByteBuffer buf = getChunkDataBuf(rawBuf);

        buf.put((byte)when);

        finishChunkPacket(packet, CHUNK_HPIF, buf.position());
        Log.d("ddm-heap", "Sending " + name(CHUNK_HPIF) + ": when=" + when);
        client.sendAndConsume(packet, mInst);
    
public static voidsendHPSG(Client client, int when, int what)
Sends an HPSG (HeaP SeGment) request to the client.


        ByteBuffer rawBuf = allocBuffer(2);
        JdwpPacket packet = new JdwpPacket(rawBuf);
        ByteBuffer buf = getChunkDataBuf(rawBuf);

        buf.put((byte)when);
        buf.put((byte)what);

        finishChunkPacket(packet, CHUNK_HPSG, buf.position());
        Log.d("ddm-heap", "Sending " + name(CHUNK_HPSG) + ": when="
            + when + ", what=" + what);
        client.sendAndConsume(packet, mInst);
    
public static voidsendREAE(Client client, boolean enable)
Sends a REAE (REcent Allocation Enable) request to the client.

        ByteBuffer rawBuf = allocBuffer(1);
        JdwpPacket packet = new JdwpPacket(rawBuf);
        ByteBuffer buf = getChunkDataBuf(rawBuf);

        buf.put((byte) (enable ? 1 : 0));

        finishChunkPacket(packet, CHUNK_REAE, buf.position());
        Log.d("ddm-heap", "Sending " + name(CHUNK_REAE) + ": " + enable);
        client.sendAndConsume(packet, mInst);
    
public static voidsendREAL(Client client)
Sends a REAL (REcent ALlocation) request to the client.

        ByteBuffer rawBuf = allocBuffer(0);
        JdwpPacket packet = new JdwpPacket(rawBuf);
        ByteBuffer buf = getChunkDataBuf(rawBuf);

        // no data

        finishChunkPacket(packet, CHUNK_REAL, buf.position());
        Log.d("ddm-heap", "Sending " + name(CHUNK_REAL));
        client.sendAndConsume(packet, mInst);
    
public static voidsendREAQ(Client client)
Sends a REAQ (REcent Allocation Query) request to the client.

        ByteBuffer rawBuf = allocBuffer(0);
        JdwpPacket packet = new JdwpPacket(rawBuf);
        ByteBuffer buf = getChunkDataBuf(rawBuf);

        // no data

        finishChunkPacket(packet, CHUNK_REAQ, buf.position());
        Log.d("ddm-heap", "Sending " + name(CHUNK_REAQ));
        client.sendAndConsume(packet, mInst);