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

HandleThread

public final class HandleThread extends ChunkHandler
Handle thread status updates.

Fields Summary
public static final int
CHUNK_THEN
public static final int
CHUNK_THCR
public static final int
CHUNK_THDE
public static final int
CHUNK_THST
public static final int
CHUNK_THNM
public static final int
CHUNK_STKL
private static final HandleThread
mInst
private static volatile boolean
mThreadStatusReqRunning
private static volatile boolean
mThreadStackTraceReqRunning
Constructors Summary
private HandleThread()


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

public voidclientReady(Client client)
Client is ready.

        Log.d("ddm-thread", "Now ready: " + client);
        if (client.isThreadUpdateEnabled())
            sendTHEN(client, true);
    
public voidhandleChunk(Client client, int type, java.nio.ByteBuffer data, boolean isReply, int msgId)
Chunk handler entry point.


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

        if (type == CHUNK_THCR) {
            handleTHCR(client, data);
        } else if (type == CHUNK_THDE) {
            handleTHDE(client, data);
        } else if (type == CHUNK_THST) {
            handleTHST(client, data);
        } else if (type == CHUNK_THNM) {
            handleTHNM(client, data);
        } else if (type == CHUNK_STKL) {
            handleSTKL(client, data);
        } else {
            handleUnknownChunk(client, type, data, isReply, msgId);
        }
    
private voidhandleSTKL(Client client, java.nio.ByteBuffer data)
Parse an incoming STKL.

        StackTraceElement[] trace;
        int i, threadId, stackDepth;
        @SuppressWarnings("unused")
        int future;

        future = data.getInt();
        threadId = data.getInt();

        Log.v("ddms", "STKL: " + threadId);

        /* un-serialize the StackTraceElement[] */
        stackDepth = data.getInt();
        trace = new StackTraceElement[stackDepth];
        for (i = 0; i < stackDepth; i++) {
            String className, methodName, fileName;
            int len, lineNumber;

            len = data.getInt();
            className = getString(data, len);
            len = data.getInt();
            methodName = getString(data, len);
            len = data.getInt();
            if (len == 0) {
                fileName = null;
            } else {
                fileName = getString(data, len);
            }
            lineNumber = data.getInt();

            trace[i] = new StackTraceElement(className, methodName, fileName,
                        lineNumber);
        }

        ThreadInfo threadInfo = client.getClientData().getThread(threadId);
        if (threadInfo != null) {
            threadInfo.setStackCall(trace);
            client.update(Client.CHANGE_THREAD_STACKTRACE);
        } else {
            Log.d("STKL", String.format(
                    "Got stackcall for thread %1$d, which does not exists (anymore?).", //$NON-NLS-1$
                    threadId));
        }
    
private voidhandleTHCR(Client client, java.nio.ByteBuffer data)

        int threadId, nameLen;
        String name;

        threadId = data.getInt();
        nameLen = data.getInt();
        name = getString(data, nameLen);

        Log.v("ddm-thread", "THCR: " + threadId + " '" + name + "'");

        client.getClientData().addThread(threadId, name);
        client.update(Client.CHANGE_THREAD_DATA);
    
private voidhandleTHDE(Client client, java.nio.ByteBuffer data)

        int threadId;

        threadId = data.getInt();
        Log.v("ddm-thread", "THDE: " + threadId);

        client.getClientData().removeThread(threadId);
        client.update(Client.CHANGE_THREAD_DATA);
    
private voidhandleTHNM(Client client, java.nio.ByteBuffer data)

        int threadId, nameLen;
        String name;

        threadId = data.getInt();
        nameLen = data.getInt();
        name = getString(data, nameLen);

        Log.v("ddm-thread", "THNM: " + threadId + " '" + name + "'");

        ThreadInfo threadInfo = client.getClientData().getThread(threadId);
        if (threadInfo != null) {
            threadInfo.setThreadName(name);
            client.update(Client.CHANGE_THREAD_DATA);
        } else {
            Log.i("ddms", "Thread with id=" + threadId + " not found");
        }
    
private voidhandleTHST(Client client, java.nio.ByteBuffer data)

        int headerLen, bytesPerEntry, extraPerEntry;
        int threadCount;

        headerLen = (data.get() & 0xff);
        bytesPerEntry = (data.get() & 0xff);
        threadCount = data.getShort();

        headerLen -= 4;     // we've read 4 bytes
        while (headerLen-- > 0)
            data.get();

        extraPerEntry = bytesPerEntry - 18;     // we want 18 bytes

        Log.v("ddm-thread", "THST: threadCount=" + threadCount);

        /*
         * For each thread, extract the data, find the appropriate
         * client, and add it to the ClientData.
         */
        for (int i = 0; i < threadCount; i++) {
            int threadId, status, tid, utime, stime;
            boolean isDaemon = false;

            threadId = data.getInt();
            status = data.get();
            tid = data.getInt();
            utime = data.getInt();
            stime = data.getInt();
            if (bytesPerEntry >= 18)
                isDaemon = (data.get() != 0);

            Log.v("ddm-thread", "  id=" + threadId
                + ", status=" + status + ", tid=" + tid
                + ", utime=" + utime + ", stime=" + stime);

            ClientData cd = client.getClientData();
            ThreadInfo threadInfo = cd.getThread(threadId);
            if (threadInfo != null)
                threadInfo.updateThread(status, tid, utime, stime, isDaemon);
            else
                Log.i("ddms", "Thread with id=" + threadId + " not found");

            // slurp up any extra
            for (int slurp = extraPerEntry; slurp > 0; slurp--)
                data.get();
        }
        
        client.update(Client.CHANGE_THREAD_DATA);
    
public static voidregister(MonitorThread mt)
Register for the packets we expect to get from the client.

        mt.registerChunkHandler(CHUNK_THCR, mInst);
        mt.registerChunkHandler(CHUNK_THDE, mInst);
        mt.registerChunkHandler(CHUNK_THST, mInst);
        mt.registerChunkHandler(CHUNK_THNM, mInst);
        mt.registerChunkHandler(CHUNK_STKL, mInst);
    
static voidrequestThreadStackCallRefresh(Client client, int threadId)

        if (client.isDdmAware() && client.isThreadUpdateEnabled()) {
            if (mThreadStackTraceReqRunning ) {
                Log.w("ddms", "Waiting for previous thread stack call req to finish");
                return;
            }

            new Thread("Thread Status Req") {
                @Override
                public void run() {
                    mThreadStackTraceReqRunning = true;
                    try {
                        sendSTKL(client, threadId);
                    } catch (IOException ioe) {
                        Log.i("ddms", "Unable to request thread stack call updates from "
                                + client + ": " + ioe.getMessage());
                    } finally {
                        mThreadStackTraceReqRunning = false;
                    }
                }
            }.start();
        }
        
    
static voidrequestThreadUpdate(Client client)
This is called periodically from the UI thread. To avoid locking the UI while we request the updates, we create a new thread.

        if (client.isDdmAware() && client.isThreadUpdateEnabled()) {
            if (mThreadStatusReqRunning) {
                Log.w("ddms", "Waiting for previous thread update req to finish");
                return;
            }

            new Thread("Thread Status Req") {
                @Override
                public void run() {
                    mThreadStatusReqRunning = true;
                    try {
                        sendTHST(client);
                    } catch (IOException ioe) {
                        Log.i("ddms", "Unable to request thread updates from "
                                + client + ": " + ioe.getMessage());
                    } finally {
                        mThreadStatusReqRunning = false;
                    }
                }
            }.start();
        }
    
public static voidsendSTKL(Client client, int threadId)
Send a STKL (STacK List) request to the client. The VM will suspend the target thread, obtain its stack, and return it. If the thread is no longer running, a failure result will be returned.


        if (false) {
            Log.i("ddm-thread", "would send STKL " + threadId);
            return;
        }

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

        buf.putInt(threadId);

        finishChunkPacket(packet, CHUNK_STKL, buf.position());
        Log.d("ddm-thread", "Sending " + name(CHUNK_STKL) + ": " + threadId);
        client.sendAndConsume(packet, mInst);
    
public static voidsendTHEN(Client client, boolean enable)
Send a THEN (THread notification ENable) request to the client.


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

        if (enable)
            buf.put((byte)1);
        else
            buf.put((byte)0);

        finishChunkPacket(packet, CHUNK_THEN, buf.position());
        Log.d("ddm-thread", "Sending " + name(CHUNK_THEN) + ": " + enable);
        client.sendAndConsume(packet, mInst);
    
private static voidsendTHST(Client client)

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

        // nothing much to say

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