Home | History | Annotate | Download | only in ddm
      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 android.ddm;
     18 
     19 import org.apache.harmony.dalvik.ddmc.Chunk;
     20 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
     21 import org.apache.harmony.dalvik.ddmc.DdmServer;
     22 import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
     23 import android.util.Log;
     24 import java.nio.ByteBuffer;
     25 
     26 /**
     27  * Handle thread-related traffic.
     28  */
     29 public class DdmHandleThread extends ChunkHandler {
     30 
     31     public static final int CHUNK_THEN = type("THEN");
     32     public static final int CHUNK_THCR = type("THCR");
     33     public static final int CHUNK_THDE = type("THDE");
     34     public static final int CHUNK_THST = type("THST");
     35     public static final int CHUNK_STKL = type("STKL");
     36 
     37     private static DdmHandleThread mInstance = new DdmHandleThread();
     38 
     39 
     40     /* singleton, do not instantiate */
     41     private DdmHandleThread() {}
     42 
     43     /**
     44      * Register for the messages we're interested in.
     45      */
     46     public static void register() {
     47         DdmServer.registerHandler(CHUNK_THEN, mInstance);
     48         DdmServer.registerHandler(CHUNK_THST, mInstance);
     49         DdmServer.registerHandler(CHUNK_STKL, mInstance);
     50     }
     51 
     52     /**
     53      * Called when the DDM server connects.  The handler is allowed to
     54      * send messages to the server.
     55      */
     56     public void connected() {}
     57 
     58     /**
     59      * Called when the DDM server disconnects.  Can be used to disable
     60      * periodic transmissions or clean up saved state.
     61      */
     62     public void disconnected() {}
     63 
     64     /**
     65      * Handle a chunk of data.
     66      */
     67     public Chunk handleChunk(Chunk request) {
     68         if (false)
     69             Log.v("ddm-thread", "Handling " + name(request.type) + " chunk");
     70         int type = request.type;
     71 
     72         if (type == CHUNK_THEN) {
     73             return handleTHEN(request);
     74         } else if (type == CHUNK_THST) {
     75             return handleTHST(request);
     76         } else if (type == CHUNK_STKL) {
     77             return handleSTKL(request);
     78         } else {
     79             throw new RuntimeException("Unknown packet "
     80                 + ChunkHandler.name(type));
     81         }
     82     }
     83 
     84     /*
     85      * Handle a "THread notification ENable" request.
     86      */
     87     private Chunk handleTHEN(Chunk request) {
     88         ByteBuffer in = wrapChunk(request);
     89 
     90         boolean enable = (in.get() != 0);
     91         //Log.i("ddm-thread", "Thread notify enable: " + enable);
     92 
     93         DdmVmInternal.threadNotify(enable);
     94         return null;        // empty response
     95     }
     96 
     97     /*
     98      * Handle a "THread STatus" request.  This is constructed by the VM.
     99      */
    100     private Chunk handleTHST(Chunk request) {
    101         ByteBuffer in = wrapChunk(request);
    102         // currently nothing to read from "in"
    103 
    104         //Log.d("ddm-thread", "Thread status request");
    105 
    106         byte[] status = DdmVmInternal.getThreadStats();
    107         if (status != null)
    108             return new Chunk(CHUNK_THST, status, 0, status.length);
    109         else
    110             return createFailChunk(1, "Can't build THST chunk");
    111     }
    112 
    113     /*
    114      * Handle a STacK List request.
    115      *
    116      * This is done by threadId, which isn't great since those are
    117      * recycled.  We need a thread serial ID.  The Linux tid is an okay
    118      * answer as it's unlikely to recycle at the exact wrong moment.
    119      * However, we're using the short threadId in THST messages, so we
    120      * use them here for consistency.  (One thought is to keep the current
    121      * thread ID in the low 16 bits and somehow serialize the top 16 bits.)
    122      */
    123     private Chunk handleSTKL(Chunk request) {
    124         ByteBuffer in = wrapChunk(request);
    125         int threadId;
    126 
    127         threadId = in.getInt();
    128 
    129         //Log.d("ddm-thread", "Stack list request " + threadId);
    130 
    131         StackTraceElement[] trace = DdmVmInternal.getStackTraceById(threadId);
    132         if (trace == null) {
    133             return createFailChunk(1, "Stack trace unavailable");
    134         } else {
    135             return createStackChunk(trace, threadId);
    136         }
    137     }
    138 
    139     /*
    140      * Serialize a StackTraceElement[] into an STKL chunk.
    141      *
    142      * We include the threadId in the response so the other side doesn't have
    143      * to match up requests and responses as carefully.
    144      */
    145     private Chunk createStackChunk(StackTraceElement[] trace, int threadId) {
    146         int bufferSize = 0;
    147 
    148         bufferSize += 4;            // version, flags, whatever
    149         bufferSize += 4;            // thread ID
    150         bufferSize += 4;            // frame count
    151         for (StackTraceElement elem : trace) {
    152             bufferSize += 4 + elem.getClassName().length() * 2;
    153             bufferSize += 4 + elem.getMethodName().length() * 2;
    154             bufferSize += 4;
    155             if (elem.getFileName() != null)
    156                 bufferSize += elem.getFileName().length() * 2;
    157             bufferSize += 4;        // line number
    158         }
    159 
    160         ByteBuffer out = ByteBuffer.allocate(bufferSize);
    161         out.putInt(0);
    162         out.putInt(threadId);
    163         out.putInt(trace.length);
    164         for (StackTraceElement elem : trace) {
    165             out.putInt(elem.getClassName().length());
    166             putString(out, elem.getClassName());
    167             out.putInt(elem.getMethodName().length());
    168             putString(out, elem.getMethodName());
    169             if (elem.getFileName() != null) {
    170                 out.putInt(elem.getFileName().length());
    171                 putString(out, elem.getFileName());
    172             } else {
    173                 out.putInt(0);
    174             }
    175             out.putInt(elem.getLineNumber());
    176         }
    177 
    178         return new Chunk(CHUNK_STKL, out);
    179     }
    180 }
    181 
    182