1 /*
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 */
16 /*
17 * JDWP initialization.
18 */
19 #include "jdwp/JdwpPriv.h"
20 #include "Dalvik.h"
21 #include "Atomic.h"
22
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/time.h>
26 #include <time.h>
27 #include <errno.h>
28
29
30 static void* jdwpThreadStart(void* arg);
31
32
33 /*
34 * Initialize JDWP.
35 *
36 * Does not return until JDWP thread is running, but may return before
37 * the thread is accepting network connections.
38 */
dvmJdwpStartup(const JdwpStartupParams * pParams)39 JdwpState* dvmJdwpStartup(const JdwpStartupParams* pParams)
40 {
41 JdwpState* state = NULL;
42 int i, sleepIter;
43 u8 startWhen;
44
45 /* comment this out when debugging JDWP itself */
46 android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
47
48 state = (JdwpState*) calloc(1, sizeof(JdwpState));
49
50 state->params = *pParams;
51
52 state->requestSerial = 0x10000000;
53 state->eventSerial = 0x20000000;
54 dvmDbgInitMutex(&state->threadStartLock);
55 dvmDbgInitMutex(&state->attachLock);
56 dvmDbgInitMutex(&state->serialLock);
57 dvmDbgInitMutex(&state->eventLock);
58 state->eventThreadId = 0;
59 dvmDbgInitMutex(&state->eventThreadLock);
60 dvmDbgInitCond(&state->threadStartCond);
61 dvmDbgInitCond(&state->attachCond);
62 dvmDbgInitCond(&state->eventThreadCond);
63
64 switch (pParams->transport) {
65 case kJdwpTransportSocket:
66 // LOGD("prepping for JDWP over TCP\n");
67 state->transport = dvmJdwpSocketTransport();
68 break;
69 case kJdwpTransportAndroidAdb:
70 // LOGD("prepping for JDWP over ADB\n");
71 state->transport = dvmJdwpAndroidAdbTransport();
72 /* TODO */
73 break;
74 default:
75 LOGE("Unknown transport %d\n", pParams->transport);
76 assert(false);
77 goto fail;
78 }
79
80 if (!dvmJdwpNetStartup(state, pParams))
81 goto fail;
82
83 /*
84 * Grab a mutex or two before starting the thread. This ensures they
85 * won't signal the cond var before we're waiting.
86 */
87 dvmDbgLockMutex(&state->threadStartLock);
88 if (pParams->suspend)
89 dvmDbgLockMutex(&state->attachLock);
90
91 /*
92 * We have bound to a port, or are trying to connect outbound to a
93 * debugger. Create the JDWP thread and let it continue the mission.
94 */
95 if (!dvmCreateInternalThread(&state->debugThreadHandle, "JDWP",
96 jdwpThreadStart, state))
97 {
98 /* state is getting tossed, but unlock these anyway for cleanliness */
99 dvmDbgUnlockMutex(&state->threadStartLock);
100 if (pParams->suspend)
101 dvmDbgUnlockMutex(&state->attachLock);
102 goto fail;
103 }
104
105 /*
106 * Wait until the thread finishes basic initialization.
107 * TODO: cond vars should be waited upon in a loop
108 */
109 dvmDbgCondWait(&state->threadStartCond, &state->threadStartLock);
110 dvmDbgUnlockMutex(&state->threadStartLock);
111
112
113 /*
114 * For suspend=y, wait for the debugger to connect to us or for us to
115 * connect to the debugger.
116 *
117 * The JDWP thread will signal us when it connects successfully or
118 * times out (for timeout=xxx), so we have to check to see what happened
119 * when we wake up.
120 */
121 if (pParams->suspend) {
122 dvmChangeStatus(NULL, THREAD_VMWAIT);
123 dvmDbgCondWait(&state->attachCond, &state->attachLock);
124 dvmDbgUnlockMutex(&state->attachLock);
125 dvmChangeStatus(NULL, THREAD_RUNNING);
126
127 if (!dvmJdwpIsActive(state)) {
128 LOGE("JDWP connection failed\n");
129 goto fail;
130 }
131
132 LOGI("JDWP connected\n");
133
134 /*
135 * Ordinarily we would pause briefly to allow the debugger to set
136 * breakpoints and so on, but for "suspend=y" the VM init code will
137 * pause the VM when it sends the VM_START message.
138 */
139 }
140
141 return state;
142
143 fail:
144 dvmJdwpShutdown(state); // frees state
145 return NULL;
146 }
147
148 /*
149 * Reset all session-related state. There should not be an active connection
150 * to the client at this point (we may be listening for a new one though).
151 *
152 * This includes freeing up the debugger event list.
153 */
dvmJdwpResetState(JdwpState * state)154 void 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 */
dvmJdwpShutdown(JdwpState * state)174 void 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 */
188 LOGD("JDWP shutting down net...\n");
189 dvmJdwpNetShutdown(state);
190
191 if (state->debugThreadStarted) {
192 state->run = false;
193 if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
194 LOGW("JDWP thread join failed\n");
195 }
196 }
197
198 LOGV("JDWP freeing netstate...\n");
199 dvmJdwpNetFree(state);
200 state->netState = NULL;
201 }
202 assert(state->netState == NULL);
203
204 dvmJdwpResetState(state);
205 free(state);
206 }
207
208 /*
209 * Are we talking to a debugger?
210 */
dvmJdwpIsActive(JdwpState * state)211 bool dvmJdwpIsActive(JdwpState* state)
212 {
213 return dvmJdwpIsConnected(state);
214 }
215
216 /*
217 * Entry point for JDWP thread. The thread was created through the VM
218 * mechanisms, so there is a java/lang/Thread associated with us.
219 */
jdwpThreadStart(void * arg)220 static void* jdwpThreadStart(void* arg)
221 {
222 JdwpState* state = (JdwpState*) arg;
223
224 LOGV("JDWP: thread running\n");
225
226 /*
227 * Finish initializing "state", then notify the creating thread that
228 * we're running.
229 */
230 state->debugThreadHandle = dvmThreadSelf()->handle;
231 state->run = true;
232 MEM_BARRIER();
233 state->debugThreadStarted = true; // touch this last
234
235 dvmDbgLockMutex(&state->threadStartLock);
236 dvmDbgCondBroadcast(&state->threadStartCond);
237 dvmDbgUnlockMutex(&state->threadStartLock);
238
239 /* set the thread state to VMWAIT so GCs don't wait for us */
240 dvmDbgThreadWaiting();
241
242 /*
243 * Loop forever if we're in server mode, processing connections. In
244 * non-server mode, we bail out of the thread when the debugger drops
245 * us.
246 *
247 * We broadcast a notification when a debugger attaches, after we
248 * successfully process the handshake.
249 */
250 while (state->run) {
251 bool first;
252 int cc;
253
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
318 /* interpreter can ignore breakpoints */
319 dvmDbgDisconnected();
320
321 /* if we had stuff suspended, resume it now */
322 dvmUndoDebuggerSuspensions();
323
324 dvmJdwpResetState(state);
325
326 /* if we connected out, this was a one-shot deal */
327 if (!state->params.server)
328 state->run = false;
329 }
330
331 /* back to running, for thread shutdown */
332 dvmDbgThreadRunning();
333
334 LOGV("JDWP: thread exiting\n");
335 return NULL;
336 }
337
338
339 /*
340 * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
341 */
dvmJdwpGetDebugThread(JdwpState * state)342 pthread_t dvmJdwpGetDebugThread(JdwpState* state)
343 {
344 if (state == NULL)
345 return 0;
346
347 return state->debugThreadHandle;
348 }
349
350 #if 0
351 /*
352 * Wait until the debugger attaches. Returns immediately if the debugger
353 * is already attached.
354 *
355 * If we return the instant the debugger connects, we run the risk of
356 * executing code before the debugger has had a chance to configure
357 * breakpoints or issue suspend calls. It would be nice to just sit in
358 * the suspended state, but most debuggers don't expect any threads to be
359 * suspended when they attach.
360 *
361 * There's no event we can post to tell the debugger "we've stopped, and
362 * we like it that way". We could send a fake breakpoint, which should
363 * 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
368 * stuff" event. We can get close with a "wait until the debugger has
369 * been idle for a brief period", and we can do a mild approximation with
370 * "just sleep for a second after it connects".
371 *
372 * We should be in THREAD_VMWAIT here, so we're not allowed to do anything
373 * with objects because a GC could be in progress.
374 *
375 * NOTE: this trips as soon as something connects to the socket. This
376 * is no longer appropriate -- we don't want to return when DDMS connects.
377 * We could fix this by polling for the first debugger packet, but we have
378 * to watch out for disconnects. If we're going to do polling, it's
379 * probably best to do it at a higher level.
380 */
381 void dvmJdwpWaitForDebugger(JdwpState* state)
382 {
383 // no more
384 }
385 #endif
386
387 /*
388 * Get a notion of the current time, in milliseconds. We leave it in
389 * two 32-bit pieces.
390 */
dvmJdwpGetNowMsec(long * pSec,long * pMsec)391 void dvmJdwpGetNowMsec(long* pSec, long* pMsec)
392 {
393 #ifdef HAVE_POSIX_CLOCKS
394 struct timespec now;
395 clock_gettime(CLOCK_MONOTONIC, &now);
396 *pSec = now.tv_sec;
397 *pMsec = now.tv_nsec / 1000000;
398 #else
399 struct timeval now;
400 gettimeofday(&now, NULL);
401 *pSec = now.tv_sec;
402 *pMsec = now.tv_usec / 1000;
403 #endif
404 }
405
406 /*
407 * Return the time, in milliseconds, since the last debugger activity.
408 *
409 * Returns -1 if no debugger is attached, or 0 if we're in the middle of
410 * processing a debugger request.
411 */
dvmJdwpLastDebuggerActivity(JdwpState * state)412 s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
413 {
414 long lastSec, lastMsec;
415 long nowSec, nowMsec;
416
417 /* these are volatile; lastSec becomes 0 during update */
418 lastSec = state->lastActivitySec;
419 lastMsec = state->lastActivityMsec;
420
421 /* initializing or in the middle of something? */
422 if (lastSec == 0 || state->lastActivitySec != lastSec) {
423 //LOGI("+++ last=busy\n");
424 return 0;
425 }
426
427 /* get the current time *after* latching the "last" time */
428 dvmJdwpGetNowMsec(&nowSec, &nowMsec);
429
430 s8 last = (s8)lastSec * 1000 + lastMsec;
431 s8 now = (s8)nowSec * 1000 + nowMsec;
432
433 //LOGI("last is %ld.%ld --> %lld\n", lastSec, lastMsec, last);
434 //LOGI("now is %ld.%ld --> %lld\n", nowSec, nowMsec, now);
435
436
437 //LOGI("+++ interval=%lld\n", now - last);
438 return now - last;
439 }
440
441