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