blob: 24e5c6c3c9e9ffa71569355db1401c214c9eda3f [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 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 */
Andy McFadden43eb5012010-02-01 16:56:53 -080016
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080017/*
18 * JDWP initialization.
19 */
20#include "jdwp/JdwpPriv.h"
21#include "Dalvik.h"
22#include "Atomic.h"
23
24#include <stdlib.h>
25#include <unistd.h>
26#include <sys/time.h>
27#include <time.h>
28#include <errno.h>
29
30
31static void* jdwpThreadStart(void* arg);
32
33
34/*
35 * Initialize JDWP.
36 *
37 * Does not return until JDWP thread is running, but may return before
38 * the thread is accepting network connections.
39 */
40JdwpState* dvmJdwpStartup(const JdwpStartupParams* pParams)
41{
42 JdwpState* state = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080043
44 /* comment this out when debugging JDWP itself */
45 android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
46
47 state = (JdwpState*) calloc(1, sizeof(JdwpState));
48
49 state->params = *pParams;
50
51 state->requestSerial = 0x10000000;
52 state->eventSerial = 0x20000000;
53 dvmDbgInitMutex(&state->threadStartLock);
54 dvmDbgInitMutex(&state->attachLock);
55 dvmDbgInitMutex(&state->serialLock);
56 dvmDbgInitMutex(&state->eventLock);
57 state->eventThreadId = 0;
58 dvmDbgInitMutex(&state->eventThreadLock);
59 dvmDbgInitCond(&state->threadStartCond);
60 dvmDbgInitCond(&state->attachCond);
61 dvmDbgInitCond(&state->eventThreadCond);
62
63 switch (pParams->transport) {
64 case kJdwpTransportSocket:
65 // LOGD("prepping for JDWP over TCP\n");
66 state->transport = dvmJdwpSocketTransport();
67 break;
68 case kJdwpTransportAndroidAdb:
69 // LOGD("prepping for JDWP over ADB\n");
70 state->transport = dvmJdwpAndroidAdbTransport();
71 /* TODO */
72 break;
73 default:
74 LOGE("Unknown transport %d\n", pParams->transport);
75 assert(false);
76 goto fail;
77 }
78
79 if (!dvmJdwpNetStartup(state, pParams))
80 goto fail;
81
82 /*
83 * Grab a mutex or two before starting the thread. This ensures they
84 * won't signal the cond var before we're waiting.
85 */
86 dvmDbgLockMutex(&state->threadStartLock);
87 if (pParams->suspend)
88 dvmDbgLockMutex(&state->attachLock);
89
90 /*
91 * We have bound to a port, or are trying to connect outbound to a
92 * debugger. Create the JDWP thread and let it continue the mission.
93 */
94 if (!dvmCreateInternalThread(&state->debugThreadHandle, "JDWP",
95 jdwpThreadStart, state))
96 {
97 /* state is getting tossed, but unlock these anyway for cleanliness */
98 dvmDbgUnlockMutex(&state->threadStartLock);
99 if (pParams->suspend)
100 dvmDbgUnlockMutex(&state->attachLock);
101 goto fail;
102 }
103
104 /*
105 * Wait until the thread finishes basic initialization.
106 * TODO: cond vars should be waited upon in a loop
107 */
108 dvmDbgCondWait(&state->threadStartCond, &state->threadStartLock);
109 dvmDbgUnlockMutex(&state->threadStartLock);
110
111
112 /*
113 * For suspend=y, wait for the debugger to connect to us or for us to
114 * connect to the debugger.
115 *
116 * The JDWP thread will signal us when it connects successfully or
117 * times out (for timeout=xxx), so we have to check to see what happened
118 * when we wake up.
119 */
120 if (pParams->suspend) {
121 dvmChangeStatus(NULL, THREAD_VMWAIT);
122 dvmDbgCondWait(&state->attachCond, &state->attachLock);
123 dvmDbgUnlockMutex(&state->attachLock);
124 dvmChangeStatus(NULL, THREAD_RUNNING);
125
126 if (!dvmJdwpIsActive(state)) {
127 LOGE("JDWP connection failed\n");
128 goto fail;
129 }
130
131 LOGI("JDWP connected\n");
132
133 /*
134 * Ordinarily we would pause briefly to allow the debugger to set
135 * breakpoints and so on, but for "suspend=y" the VM init code will
136 * pause the VM when it sends the VM_START message.
137 */
138 }
139
140 return state;
141
142fail:
143 dvmJdwpShutdown(state); // frees state
144 return NULL;
145}
146
147/*
148 * Reset all session-related state. There should not be an active connection
Andy McFaddend8cc3322010-02-25 12:31:04 -0800149 * to the client at this point. The rest of the VM still thinks there is
150 * a debugger attached.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800151 *
152 * This includes freeing up the debugger event list.
153 */
154void dvmJdwpResetState(JdwpState* state)
155{
156 /* could reset the serial numbers, but no need to */
157
158 dvmJdwpUnregisterAll(state);
159 assert(state->eventList == NULL);
160
161 /*
162 * Should not have one of these in progress. If the debugger went away
163 * mid-request, though, we could see this.
164 */
165 if (state->eventThreadId != 0) {
166 LOGW("WARNING: resetting state while event in progress\n");
167 assert(false);
168 }
169}
170
171/*
172 * Tell the JDWP thread to shut down. Frees "state".
173 */
174void dvmJdwpShutdown(JdwpState* state)
175{
176 void* threadReturn;
177
178 if (state == NULL)
179 return;
180
181 if (dvmJdwpIsTransportDefined(state)) {
182 if (dvmJdwpIsConnected(state))
183 dvmJdwpPostVMDeath(state);
184
185 /*
186 * Close down the network to inspire the thread to halt.
187 */
Andy McFadden43eb5012010-02-01 16:56:53 -0800188 if (gDvm.verboseShutdown)
189 LOGD("JDWP shutting down net...\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800190 dvmJdwpNetShutdown(state);
191
192 if (state->debugThreadStarted) {
193 state->run = false;
194 if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
195 LOGW("JDWP thread join failed\n");
196 }
197 }
198
Andy McFadden43eb5012010-02-01 16:56:53 -0800199 if (gDvm.verboseShutdown)
200 LOGD("JDWP freeing netstate...\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800201 dvmJdwpNetFree(state);
202 state->netState = NULL;
203 }
204 assert(state->netState == NULL);
205
206 dvmJdwpResetState(state);
207 free(state);
208}
209
210/*
211 * Are we talking to a debugger?
Carl Shapirode750892010-06-08 16:37:12 -0700212 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800213bool dvmJdwpIsActive(JdwpState* state)
214{
215 return dvmJdwpIsConnected(state);
216}
217
218/*
219 * Entry point for JDWP thread. The thread was created through the VM
220 * mechanisms, so there is a java/lang/Thread associated with us.
221 */
222static void* jdwpThreadStart(void* arg)
223{
224 JdwpState* state = (JdwpState*) arg;
225
226 LOGV("JDWP: thread running\n");
227
228 /*
229 * Finish initializing "state", then notify the creating thread that
230 * we're running.
231 */
232 state->debugThreadHandle = dvmThreadSelf()->handle;
233 state->run = true;
Andy McFaddenfc3d3162010-08-05 14:34:26 -0700234 android_atomic_release_store(true, &state->debugThreadStarted);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235
236 dvmDbgLockMutex(&state->threadStartLock);
237 dvmDbgCondBroadcast(&state->threadStartCond);
238 dvmDbgUnlockMutex(&state->threadStartLock);
239
240 /* set the thread state to VMWAIT so GCs don't wait for us */
241 dvmDbgThreadWaiting();
242
243 /*
244 * Loop forever if we're in server mode, processing connections. In
245 * non-server mode, we bail out of the thread when the debugger drops
246 * us.
247 *
248 * We broadcast a notification when a debugger attaches, after we
249 * successfully process the handshake.
250 */
251 while (state->run) {
252 bool first;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800253
254 if (state->params.server) {
255 /*
256 * Block forever, waiting for a connection. To support the
257 * "timeout=xxx" option we'll need to tweak this.
258 */
259 if (!dvmJdwpAcceptConnection(state))
260 break;
261 } else {
262 /*
263 * If we're not acting as a server, we need to connect out to the
264 * debugger. To support the "timeout=xxx" option we need to
265 * have a timeout if the handshake reply isn't received in a
266 * reasonable amount of time.
267 */
268 if (!dvmJdwpEstablishConnection(state)) {
269 /* wake anybody who was waiting for us to succeed */
270 dvmDbgLockMutex(&state->attachLock);
271 dvmDbgCondBroadcast(&state->attachCond);
272 dvmDbgUnlockMutex(&state->attachLock);
273 break;
274 }
275 }
276
277 /* prep debug code to handle the new connection */
278 dvmDbgConnected();
279
280 /* process requests until the debugger drops */
281 first = true;
282 while (true) {
283 // sanity check -- shouldn't happen?
284 if (dvmThreadSelf()->status != THREAD_VMWAIT) {
285 LOGE("JDWP thread no longer in VMWAIT (now %d); resetting\n",
286 dvmThreadSelf()->status);
287 dvmDbgThreadWaiting();
288 }
289
290 if (!dvmJdwpProcessIncoming(state)) /* blocking read */
291 break;
292
293 if (first && !dvmJdwpAwaitingHandshake(state)) {
294 /* handshake worked, tell the interpreter that we're active */
295 first = false;
296
297 /* set thread ID; requires object registry to be active */
298 state->debugThreadId = dvmDbgGetThreadSelfId();
299
300 /* wake anybody who's waiting for us */
301 dvmDbgLockMutex(&state->attachLock);
302 dvmDbgCondBroadcast(&state->attachCond);
303 dvmDbgUnlockMutex(&state->attachLock);
304 }
305 }
306
307 dvmJdwpCloseConnection(state);
308
309 if (state->ddmActive) {
310 state->ddmActive = false;
311
312 /* broadcast the disconnect; must be in RUNNING state */
313 dvmDbgThreadRunning();
314 dvmDbgDdmDisconnected();
315 dvmDbgThreadWaiting();
316 }
317
Andy McFaddend8cc3322010-02-25 12:31:04 -0800318 /* release session state, e.g. remove breakpoint instructions */
319 dvmJdwpResetState(state);
320
321 /* tell the interpreter that the debugger is no longer around */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800322 dvmDbgDisconnected();
323
Andy McFaddend8cc3322010-02-25 12:31:04 -0800324 /* if we had threads suspended, resume them now */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800325 dvmUndoDebuggerSuspensions();
326
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800327 /* if we connected out, this was a one-shot deal */
328 if (!state->params.server)
329 state->run = false;
330 }
331
332 /* back to running, for thread shutdown */
333 dvmDbgThreadRunning();
334
335 LOGV("JDWP: thread exiting\n");
336 return NULL;
337}
338
339
340/*
341 * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
342 */
343pthread_t dvmJdwpGetDebugThread(JdwpState* state)
344{
345 if (state == NULL)
346 return 0;
347
348 return state->debugThreadHandle;
349}
350
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700351
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800352/*
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700353 * Support routines for waitForDebugger().
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800354 *
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700355 * We can't have a trivial "waitForDebugger" function that returns the
356 * instant the debugger connects, because we run the risk of executing code
357 * before the debugger has had a chance to configure breakpoints or issue
358 * suspend calls. It would be nice to just sit in the suspended state, but
359 * most debuggers don't expect any threads to be suspended when they attach.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800360 *
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700361 * There's no JDWP event we can post to tell the debugger, "we've stopped,
362 * and we like it that way". We could send a fake breakpoint, which should
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800363 * cause the debugger to immediately send a resume, but the debugger might
364 * send the resume immediately or might throw an exception of its own upon
365 * receiving a breakpoint event that it didn't ask for.
366 *
367 * What we really want is a "wait until the debugger is done configuring
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700368 * stuff" event. We can approximate this with a "wait until the debugger
369 * has been idle for a brief period".
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800370 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800371
372/*
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700373 * Get a notion of the current time, in milliseconds.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800374 */
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700375s8 dvmJdwpGetNowMsec(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800376{
377#ifdef HAVE_POSIX_CLOCKS
378 struct timespec now;
379 clock_gettime(CLOCK_MONOTONIC, &now);
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700380 return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800381#else
382 struct timeval now;
383 gettimeofday(&now, NULL);
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700384 return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800385#endif
386}
387
388/*
389 * Return the time, in milliseconds, since the last debugger activity.
390 *
391 * Returns -1 if no debugger is attached, or 0 if we're in the middle of
392 * processing a debugger request.
393 */
394s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
395{
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700396 if (!gDvm.debuggerActive) {
397 LOGD("dvmJdwpLastDebuggerActivity: no active debugger\n");
398 return -1;
399 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800400
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700401 s8 last = dvmQuasiAtomicRead64(&state->lastActivityWhen);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800402
403 /* initializing or in the middle of something? */
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700404 if (last == 0) {
405 LOGV("+++ last=busy\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800406 return 0;
407 }
408
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700409 /* now get the current time */
410 s8 now = dvmJdwpGetNowMsec();
411 assert(now > last);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800412
Andy McFaddendeeeeb22010-06-16 08:32:04 -0700413 LOGV("+++ debugger interval=%lld\n", now - last);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800414 return now - last;
415}