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