• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
DdmHandleThread()42     private DdmHandleThread() {}
43 
44     /**
45      * Register for the messages we're interested in.
46      */
register()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      */
connected()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      */
disconnected()63     public void disconnected() {}
64 
65     /**
66      * Handle a chunk of data.
67      */
handleChunk(Chunk request)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      */
handleTHEN(Chunk request)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      */
handleTHST(Chunk request)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      */
handleSTKL(Chunk request)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      */
createStackChunk(StackTraceElement[] trace, int threadId)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