JdwpMain.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
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
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
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");
66        state->transport = dvmJdwpSocketTransport();
67        break;
68    case kJdwpTransportAndroidAdb:
69        // LOGD("prepping for JDWP over ADB");
70        state->transport = dvmJdwpAndroidAdbTransport();
71        /* TODO */
72        break;
73    default:
74        LOGE("Unknown transport %d", 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");
128            goto fail;
129        }
130
131        LOGI("JDWP connected");
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
149 * to the client at this point.  The rest of the VM still thinks there is
150 * a debugger attached.
151 *
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");
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         */
188        if (gDvm.verboseShutdown)
189            LOGD("JDWP shutting down net...");
190        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");
196            }
197        }
198
199        if (gDvm.verboseShutdown)
200            LOGD("JDWP freeing netstate...");
201        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?
212 */
213bool 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");
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;
234    android_atomic_release_store(true, &state->debugThreadStarted);
235
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;
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",
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        /* release session state, e.g. remove breakpoint instructions */
319        dvmJdwpResetState(state);
320
321        /* tell the interpreter that the debugger is no longer around */
322        dvmDbgDisconnected();
323
324        /* if we had threads suspended, resume them now */
325        dvmUndoDebuggerSuspensions();
326
327        /* 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");
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
351
352/*
353 * Support routines for waitForDebugger().
354 *
355 * 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.
360 *
361 * 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
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 approximate this with a "wait until the debugger
369 * has been idle for a brief period".
370 */
371
372/*
373 * Get a notion of the current time, in milliseconds.
374 */
375s8 dvmJdwpGetNowMsec()
376{
377#ifdef HAVE_POSIX_CLOCKS
378    struct timespec now;
379    clock_gettime(CLOCK_MONOTONIC, &now);
380    return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
381#else
382    struct timeval now;
383    gettimeofday(&now, NULL);
384    return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
385#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{
396    if (!gDvm.debuggerActive) {
397        LOGD("dvmJdwpLastDebuggerActivity: no active debugger");
398        return -1;
399    }
400
401    s8 last = dvmQuasiAtomicRead64(&state->lastActivityWhen);
402
403    /* initializing or in the middle of something? */
404    if (last == 0) {
405        LOGV("+++ last=busy");
406        return 0;
407    }
408
409    /* now get the current time */
410    s8 now = dvmJdwpGetNowMsec();
411    assert(now > last);
412
413    LOGV("+++ debugger interval=%lld", now - last);
414    return now - last;
415}
416