blob: 540259d437c13c6f34b9167dcce163f9cc37a2c9 [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;
43 int i, sleepIter;
44 u8 startWhen;
45
46 /* comment this out when debugging JDWP itself */
47 android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
48
49 state = (JdwpState*) calloc(1, sizeof(JdwpState));
50
51 state->params = *pParams;
52
53 state->requestSerial = 0x10000000;
54 state->eventSerial = 0x20000000;
55 dvmDbgInitMutex(&state->threadStartLock);
56 dvmDbgInitMutex(&state->attachLock);
57 dvmDbgInitMutex(&state->serialLock);
58 dvmDbgInitMutex(&state->eventLock);
59 state->eventThreadId = 0;
60 dvmDbgInitMutex(&state->eventThreadLock);
61 dvmDbgInitCond(&state->threadStartCond);
62 dvmDbgInitCond(&state->attachCond);
63 dvmDbgInitCond(&state->eventThreadCond);
64
65 switch (pParams->transport) {
66 case kJdwpTransportSocket:
67 // LOGD("prepping for JDWP over TCP\n");
68 state->transport = dvmJdwpSocketTransport();
69 break;
70 case kJdwpTransportAndroidAdb:
71 // LOGD("prepping for JDWP over ADB\n");
72 state->transport = dvmJdwpAndroidAdbTransport();
73 /* TODO */
74 break;
75 default:
76 LOGE("Unknown transport %d\n", pParams->transport);
77 assert(false);
78 goto fail;
79 }
80
81 if (!dvmJdwpNetStartup(state, pParams))
82 goto fail;
83
84 /*
85 * Grab a mutex or two before starting the thread. This ensures they
86 * won't signal the cond var before we're waiting.
87 */
88 dvmDbgLockMutex(&state->threadStartLock);
89 if (pParams->suspend)
90 dvmDbgLockMutex(&state->attachLock);
91
92 /*
93 * We have bound to a port, or are trying to connect outbound to a
94 * debugger. Create the JDWP thread and let it continue the mission.
95 */
96 if (!dvmCreateInternalThread(&state->debugThreadHandle, "JDWP",
97 jdwpThreadStart, state))
98 {
99 /* state is getting tossed, but unlock these anyway for cleanliness */
100 dvmDbgUnlockMutex(&state->threadStartLock);
101 if (pParams->suspend)
102 dvmDbgUnlockMutex(&state->attachLock);
103 goto fail;
104 }
105
106 /*
107 * Wait until the thread finishes basic initialization.
108 * TODO: cond vars should be waited upon in a loop
109 */
110 dvmDbgCondWait(&state->threadStartCond, &state->threadStartLock);
111 dvmDbgUnlockMutex(&state->threadStartLock);
112
113
114 /*
115 * For suspend=y, wait for the debugger to connect to us or for us to
116 * connect to the debugger.
117 *
118 * The JDWP thread will signal us when it connects successfully or
119 * times out (for timeout=xxx), so we have to check to see what happened
120 * when we wake up.
121 */
122 if (pParams->suspend) {
123 dvmChangeStatus(NULL, THREAD_VMWAIT);
124 dvmDbgCondWait(&state->attachCond, &state->attachLock);
125 dvmDbgUnlockMutex(&state->attachLock);
126 dvmChangeStatus(NULL, THREAD_RUNNING);
127
128 if (!dvmJdwpIsActive(state)) {
129 LOGE("JDWP connection failed\n");
130 goto fail;
131 }
132
133 LOGI("JDWP connected\n");
134
135 /*
136 * Ordinarily we would pause briefly to allow the debugger to set
137 * breakpoints and so on, but for "suspend=y" the VM init code will
138 * pause the VM when it sends the VM_START message.
139 */
140 }
141
142 return state;
143
144fail:
145 dvmJdwpShutdown(state); // frees state
146 return NULL;
147}
148
149/*
150 * Reset all session-related state. There should not be an active connection
151 * to the client at this point (we may be listening for a new one though).
152 *
153 * This includes freeing up the debugger event list.
154 */
155void dvmJdwpResetState(JdwpState* state)
156{
157 /* could reset the serial numbers, but no need to */
158
159 dvmJdwpUnregisterAll(state);
160 assert(state->eventList == NULL);
161
162 /*
163 * Should not have one of these in progress. If the debugger went away
164 * mid-request, though, we could see this.
165 */
166 if (state->eventThreadId != 0) {
167 LOGW("WARNING: resetting state while event in progress\n");
168 assert(false);
169 }
170}
171
172/*
173 * Tell the JDWP thread to shut down. Frees "state".
174 */
175void dvmJdwpShutdown(JdwpState* state)
176{
177 void* threadReturn;
178
179 if (state == NULL)
180 return;
181
182 if (dvmJdwpIsTransportDefined(state)) {
183 if (dvmJdwpIsConnected(state))
184 dvmJdwpPostVMDeath(state);
185
186 /*
187 * Close down the network to inspire the thread to halt.
188 */
Andy McFadden43eb5012010-02-01 16:56:53 -0800189 if (gDvm.verboseShutdown)
190 LOGD("JDWP shutting down net...\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800191 dvmJdwpNetShutdown(state);
192
193 if (state->debugThreadStarted) {
194 state->run = false;
195 if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
196 LOGW("JDWP thread join failed\n");
197 }
198 }
199
Andy McFadden43eb5012010-02-01 16:56:53 -0800200 if (gDvm.verboseShutdown)
201 LOGD("JDWP freeing netstate...\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800202 dvmJdwpNetFree(state);
203 state->netState = NULL;
204 }
205 assert(state->netState == NULL);
206
207 dvmJdwpResetState(state);
208 free(state);
209}
210
211/*
212 * Are we talking to a debugger?
213 */
214bool dvmJdwpIsActive(JdwpState* state)
215{
216 return dvmJdwpIsConnected(state);
217}
218
219/*
220 * Entry point for JDWP thread. The thread was created through the VM
221 * mechanisms, so there is a java/lang/Thread associated with us.
222 */
223static void* jdwpThreadStart(void* arg)
224{
225 JdwpState* state = (JdwpState*) arg;
226
227 LOGV("JDWP: thread running\n");
228
229 /*
230 * Finish initializing "state", then notify the creating thread that
231 * we're running.
232 */
233 state->debugThreadHandle = dvmThreadSelf()->handle;
234 state->run = true;
235 MEM_BARRIER();
236 state->debugThreadStarted = true; // touch this last
237
238 dvmDbgLockMutex(&state->threadStartLock);
239 dvmDbgCondBroadcast(&state->threadStartCond);
240 dvmDbgUnlockMutex(&state->threadStartLock);
241
242 /* set the thread state to VMWAIT so GCs don't wait for us */
243 dvmDbgThreadWaiting();
244
245 /*
246 * Loop forever if we're in server mode, processing connections. In
247 * non-server mode, we bail out of the thread when the debugger drops
248 * us.
249 *
250 * We broadcast a notification when a debugger attaches, after we
251 * successfully process the handshake.
252 */
253 while (state->run) {
254 bool first;
255 int cc;
256
257 if (state->params.server) {
258 /*
259 * Block forever, waiting for a connection. To support the
260 * "timeout=xxx" option we'll need to tweak this.
261 */
262 if (!dvmJdwpAcceptConnection(state))
263 break;
264 } else {
265 /*
266 * If we're not acting as a server, we need to connect out to the
267 * debugger. To support the "timeout=xxx" option we need to
268 * have a timeout if the handshake reply isn't received in a
269 * reasonable amount of time.
270 */
271 if (!dvmJdwpEstablishConnection(state)) {
272 /* wake anybody who was waiting for us to succeed */
273 dvmDbgLockMutex(&state->attachLock);
274 dvmDbgCondBroadcast(&state->attachCond);
275 dvmDbgUnlockMutex(&state->attachLock);
276 break;
277 }
278 }
279
280 /* prep debug code to handle the new connection */
281 dvmDbgConnected();
282
283 /* process requests until the debugger drops */
284 first = true;
285 while (true) {
286 // sanity check -- shouldn't happen?
287 if (dvmThreadSelf()->status != THREAD_VMWAIT) {
288 LOGE("JDWP thread no longer in VMWAIT (now %d); resetting\n",
289 dvmThreadSelf()->status);
290 dvmDbgThreadWaiting();
291 }
292
293 if (!dvmJdwpProcessIncoming(state)) /* blocking read */
294 break;
295
296 if (first && !dvmJdwpAwaitingHandshake(state)) {
297 /* handshake worked, tell the interpreter that we're active */
298 first = false;
299
300 /* set thread ID; requires object registry to be active */
301 state->debugThreadId = dvmDbgGetThreadSelfId();
302
303 /* wake anybody who's waiting for us */
304 dvmDbgLockMutex(&state->attachLock);
305 dvmDbgCondBroadcast(&state->attachCond);
306 dvmDbgUnlockMutex(&state->attachLock);
307 }
308 }
309
310 dvmJdwpCloseConnection(state);
311
312 if (state->ddmActive) {
313 state->ddmActive = false;
314
315 /* broadcast the disconnect; must be in RUNNING state */
316 dvmDbgThreadRunning();
317 dvmDbgDdmDisconnected();
318 dvmDbgThreadWaiting();
319 }
320
321 /* interpreter can ignore breakpoints */
322 dvmDbgDisconnected();
323
324 /* if we had stuff suspended, resume it now */
325 dvmUndoDebuggerSuspensions();
326
327 dvmJdwpResetState(state);
328
329 /* if we connected out, this was a one-shot deal */
330 if (!state->params.server)
331 state->run = false;
332 }
333
334 /* back to running, for thread shutdown */
335 dvmDbgThreadRunning();
336
337 LOGV("JDWP: thread exiting\n");
338 return NULL;
339}
340
341
342/*
343 * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
344 */
345pthread_t dvmJdwpGetDebugThread(JdwpState* state)
346{
347 if (state == NULL)
348 return 0;
349
350 return state->debugThreadHandle;
351}
352
353#if 0
354/*
355 * Wait until the debugger attaches. Returns immediately if the debugger
356 * is already attached.
357 *
358 * If we return the instant the debugger connects, we run the risk of
359 * executing code before the debugger has had a chance to configure
360 * breakpoints or issue suspend calls. It would be nice to just sit in
361 * the suspended state, but most debuggers don't expect any threads to be
362 * suspended when they attach.
363 *
364 * There's no event we can post to tell the debugger "we've stopped, and
365 * we like it that way". We could send a fake breakpoint, which should
366 * cause the debugger to immediately send a resume, but the debugger might
367 * send the resume immediately or might throw an exception of its own upon
368 * receiving a breakpoint event that it didn't ask for.
369 *
370 * What we really want is a "wait until the debugger is done configuring
371 * stuff" event. We can get close with a "wait until the debugger has
372 * been idle for a brief period", and we can do a mild approximation with
373 * "just sleep for a second after it connects".
374 *
375 * We should be in THREAD_VMWAIT here, so we're not allowed to do anything
376 * with objects because a GC could be in progress.
377 *
378 * NOTE: this trips as soon as something connects to the socket. This
379 * is no longer appropriate -- we don't want to return when DDMS connects.
380 * We could fix this by polling for the first debugger packet, but we have
381 * to watch out for disconnects. If we're going to do polling, it's
382 * probably best to do it at a higher level.
383 */
384void dvmJdwpWaitForDebugger(JdwpState* state)
385{
386 // no more
387}
388#endif
389
390/*
391 * Get a notion of the current time, in milliseconds. We leave it in
392 * two 32-bit pieces.
393 */
394void dvmJdwpGetNowMsec(long* pSec, long* pMsec)
395{
396#ifdef HAVE_POSIX_CLOCKS
397 struct timespec now;
398 clock_gettime(CLOCK_MONOTONIC, &now);
399 *pSec = now.tv_sec;
400 *pMsec = now.tv_nsec / 1000000;
401#else
402 struct timeval now;
403 gettimeofday(&now, NULL);
404 *pSec = now.tv_sec;
405 *pMsec = now.tv_usec / 1000;
406#endif
407}
408
409/*
410 * Return the time, in milliseconds, since the last debugger activity.
411 *
412 * Returns -1 if no debugger is attached, or 0 if we're in the middle of
413 * processing a debugger request.
414 */
415s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
416{
417 long lastSec, lastMsec;
418 long nowSec, nowMsec;
419
420 /* these are volatile; lastSec becomes 0 during update */
421 lastSec = state->lastActivitySec;
422 lastMsec = state->lastActivityMsec;
423
424 /* initializing or in the middle of something? */
425 if (lastSec == 0 || state->lastActivitySec != lastSec) {
426 //LOGI("+++ last=busy\n");
427 return 0;
428 }
429
430 /* get the current time *after* latching the "last" time */
431 dvmJdwpGetNowMsec(&nowSec, &nowMsec);
432
433 s8 last = (s8)lastSec * 1000 + lastMsec;
434 s8 now = (s8)nowSec * 1000 + nowMsec;
435
436 //LOGI("last is %ld.%ld --> %lld\n", lastSec, lastMsec, last);
437 //LOGI("now is %ld.%ld --> %lld\n", nowSec, nowMsec, now);
438
439
440 //LOGI("+++ interval=%lld\n", now - last);
441 return now - last;
442}
443