blob: 613ab75f9c1b8e547412a492d91ed876e5a612da [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.ddm;
18
19import org.apache.harmony.dalvik.ddmc.Chunk;
20import org.apache.harmony.dalvik.ddmc.ChunkHandler;
21import org.apache.harmony.dalvik.ddmc.DdmServer;
22import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.util.Log;
24import java.nio.ByteBuffer;
25
26/**
27 * Handle thread-related traffic.
28 */
29public 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) {
Joe Onorato43a17652011-04-06 19:22:23 -070068 if (false)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 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