blob: ef2461835e60a78fc06e6e10516d465b9714cf08 [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
Andy McFaddend8cc3322010-02-25 12:31:04 -0800151 * to the client at this point. The rest of the VM still thinks there is
152 * a debugger attached.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800153 *
154 * This includes freeing up the debugger event list.
155 */
156void dvmJdwpResetState(JdwpState* state)
157{
158 /* could reset the serial numbers, but no need to */
159
160 dvmJdwpUnregisterAll(state);
161 assert(state->eventList == NULL);
162
163 /*
164 * Should not have one of these in progress. If the debugger went away
165 * mid-request, though, we could see this.
166 */
167 if (state->eventThreadId != 0) {
168 LOGW("WARNING: resetting state while event in progress\n");
169 assert(false);
170 }
171}
172
173/*
174 * Tell the JDWP thread to shut down. Frees "state".
175 */
176void dvmJdwpShutdown(JdwpState* state)
177{
178 void* threadReturn;
179
180 if (state == NULL)
181 return;
182
183 if (dvmJdwpIsTransportDefined(state)) {
184 if (dvmJdwpIsConnected(state))
185 dvmJdwpPostVMDeath(state);
186
187 /*
188 * Close down the network to inspire the thread to halt.
189 */
Andy McFadden43eb5012010-02-01 16:56:53 -0800190 if (gDvm.verboseShutdown)
191 LOGD("JDWP shutting down net...\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800192 dvmJdwpNetShutdown(state);
193
194 if (state->debugThreadStarted) {
195 state->run = false;
196 if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
197 LOGW("JDWP thread join failed\n");
198 }
199 }
200
Andy McFadden43eb5012010-02-01 16:56:53 -0800201 if (gDvm.verboseShutdown)
202 LOGD("JDWP freeing netstate...\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800203 dvmJdwpNetFree(state);
204 state->netState = NULL;
205 }
206 assert(state->netState == NULL);
207
208 dvmJdwpResetState(state);
209 free(state);
210}
211
212/*
213 * Are we talking to a debugger?
214 */
215bool dvmJdwpIsActive(JdwpState* state)
216{
217 return dvmJdwpIsConnected(state);
218}
219
220/*
221 * Entry point for JDWP thread. The thread was created through the VM
222 * mechanisms, so there is a java/lang/Thread associated with us.
223 */
224static void* jdwpThreadStart(void* arg)
225{
226 JdwpState* state = (JdwpState*) arg;
227
228 LOGV("JDWP: thread running\n");
229
230 /*
231 * Finish initializing "state", then notify the creating thread that
232 * we're running.
233 */
234 state->debugThreadHandle = dvmThreadSelf()->handle;
235 state->run = true;
236 MEM_BARRIER();
237 state->debugThreadStarted = true; // touch this last
238
239 dvmDbgLockMutex(&state->threadStartLock);
240 dvmDbgCondBroadcast(&state->threadStartCond);
241 dvmDbgUnlockMutex(&state->threadStartLock);
242
243 /* set the thread state to VMWAIT so GCs don't wait for us */
244 dvmDbgThreadWaiting();
245
246 /*
247 * Loop forever if we're in server mode, processing connections. In
248 * non-server mode, we bail out of the thread when the debugger drops
249 * us.
250 *
251 * We broadcast a notification when a debugger attaches, after we
252 * successfully process the handshake.
253 */
254 while (state->run) {
255 bool first;
256 int cc;
257
258 if (state->params.server) {
259 /*
260 * Block forever, waiting for a connection. To support the
261 * "timeout=xxx" option we'll need to tweak this.
262 */
263 if (!dvmJdwpAcceptConnection(state))
264 break;
265 } else {
266 /*
267 * If we're not acting as a server, we need to connect out to the
268 * debugger. To support the "timeout=xxx" option we need to
269 * have a timeout if the handshake reply isn't received in a
270 * reasonable amount of time.
271 */
272 if (!dvmJdwpEstablishConnection(state)) {
273 /* wake anybody who was waiting for us to succeed */
274 dvmDbgLockMutex(&state->attachLock);
275 dvmDbgCondBroadcast(&state->attachCond);
276 dvmDbgUnlockMutex(&state->attachLock);
277 break;
278 }
279 }
280
281 /* prep debug code to handle the new connection */
282 dvmDbgConnected();
283
284 /* process requests until the debugger drops */
285 first = true;
286 while (true) {
287 // sanity check -- shouldn't happen?
288 if (dvmThreadSelf()->status != THREAD_VMWAIT) {
289 LOGE("JDWP thread no longer in VMWAIT (now %d); resetting\n",
290 dvmThreadSelf()->status);
291 dvmDbgThreadWaiting();
292 }
293
294 if (!dvmJdwpProcessIncoming(state)) /* blocking read */
295 break;
296
297 if (first && !dvmJdwpAwaitingHandshake(state)) {
298 /* handshake worked, tell the interpreter that we're active */
299 first = false;
300
301 /* set thread ID; requires object registry to be active */
302 state->debugThreadId = dvmDbgGetThreadSelfId();
303
304 /* wake anybody who's waiting for us */
305 dvmDbgLockMutex(&state->attachLock);
306 dvmDbgCondBroadcast(&state->attachCond);
307 dvmDbgUnlockMutex(&state->attachLock);
308 }
309 }
310
311 dvmJdwpCloseConnection(state);
312
313 if (state->ddmActive) {
314 state->ddmActive = false;
315
316 /* broadcast the disconnect; must be in RUNNING state */
317 dvmDbgThreadRunning();
318 dvmDbgDdmDisconnected();
319 dvmDbgThreadWaiting();
320 }
321
Andy McFaddend8cc3322010-02-25 12:31:04 -0800322 /* release session state, e.g. remove breakpoint instructions */
323 dvmJdwpResetState(state);
324
325 /* tell the interpreter that the debugger is no longer around */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800326 dvmDbgDisconnected();
327
Andy McFaddend8cc3322010-02-25 12:31:04 -0800328 /* if we had threads suspended, resume them now */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800329 dvmUndoDebuggerSuspensions();
330
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800331 /* if we connected out, this was a one-shot deal */
332 if (!state->params.server)
333 state->run = false;
334 }
335
336 /* back to running, for thread shutdown */
337 dvmDbgThreadRunning();
338
339 LOGV("JDWP: thread exiting\n");
340 return NULL;
341}
342
343
344/*
345 * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
346 */
347pthread_t dvmJdwpGetDebugThread(JdwpState* state)
348{
349 if (state == NULL)
350 return 0;
351
352 return state->debugThreadHandle;
353}
354
355#if 0
356/*
357 * Wait until the debugger attaches. Returns immediately if the debugger
358 * is already attached.
359 *
360 * If we return the instant the debugger connects, we run the risk of
361 * executing code before the debugger has had a chance to configure
362 * breakpoints or issue suspend calls. It would be nice to just sit in
363 * the suspended state, but most debuggers don't expect any threads to be
364 * suspended when they attach.
365 *
366 * There's no event we can post to tell the debugger "we've stopped, and
367 * we like it that way". We could send a fake breakpoint, which should
368 * cause the debugger to immediately send a resume, but the debugger might
369 * send the resume immediately or might throw an exception of its own upon
370 * receiving a breakpoint event that it didn't ask for.
371 *
372 * What we really want is a "wait until the debugger is done configuring
373 * stuff" event. We can get close with a "wait until the debugger has
374 * been idle for a brief period", and we can do a mild approximation with
375 * "just sleep for a second after it connects".
376 *
377 * We should be in THREAD_VMWAIT here, so we're not allowed to do anything
378 * with objects because a GC could be in progress.
379 *
380 * NOTE: this trips as soon as something connects to the socket. This
381 * is no longer appropriate -- we don't want to return when DDMS connects.
382 * We could fix this by polling for the first debugger packet, but we have
383 * to watch out for disconnects. If we're going to do polling, it's
384 * probably best to do it at a higher level.
385 */
386void dvmJdwpWaitForDebugger(JdwpState* state)
387{
388 // no more
389}
390#endif
391
392/*
393 * Get a notion of the current time, in milliseconds. We leave it in
394 * two 32-bit pieces.
395 */
396void dvmJdwpGetNowMsec(long* pSec, long* pMsec)
397{
398#ifdef HAVE_POSIX_CLOCKS
399 struct timespec now;
400 clock_gettime(CLOCK_MONOTONIC, &now);
401 *pSec = now.tv_sec;
402 *pMsec = now.tv_nsec / 1000000;
403#else
404 struct timeval now;
405 gettimeofday(&now, NULL);
406 *pSec = now.tv_sec;
407 *pMsec = now.tv_usec / 1000;
408#endif
409}
410
411/*
412 * Return the time, in milliseconds, since the last debugger activity.
413 *
414 * Returns -1 if no debugger is attached, or 0 if we're in the middle of
415 * processing a debugger request.
416 */
417s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
418{
419 long lastSec, lastMsec;
420 long nowSec, nowMsec;
421
422 /* these are volatile; lastSec becomes 0 during update */
423 lastSec = state->lastActivitySec;
424 lastMsec = state->lastActivityMsec;
425
426 /* initializing or in the middle of something? */
427 if (lastSec == 0 || state->lastActivitySec != lastSec) {
428 //LOGI("+++ last=busy\n");
429 return 0;
430 }
431
432 /* get the current time *after* latching the "last" time */
433 dvmJdwpGetNowMsec(&nowSec, &nowMsec);
434
435 s8 last = (s8)lastSec * 1000 + lastMsec;
436 s8 now = (s8)nowSec * 1000 + nowMsec;
437
438 //LOGI("last is %ld.%ld --> %lld\n", lastSec, lastMsec, last);
439 //LOGI("now is %ld.%ld --> %lld\n", nowSec, nowMsec, now);
440
441
442 //LOGI("+++ interval=%lld\n", now - last);
443 return now - last;
444}
445