Home | History | Annotate | Download | only in jdwp
      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 /*
     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  */
     40 JdwpState* 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\n");
     66         state->transport = dvmJdwpSocketTransport();
     67         break;
     68     case kJdwpTransportAndroidAdb:
     69         // LOGD("prepping for JDWP over ADB\n");
     70         state->transport = dvmJdwpAndroidAdbTransport();
     71         /* TODO */
     72         break;
     73     default:
     74         LOGE("Unknown transport %d\n", 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\n");
    128             goto fail;
    129         }
    130 
    131         LOGI("JDWP connected\n");
    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 
    142 fail:
    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  */
    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  */
    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         if (gDvm.verboseShutdown)
    189             LOGD("JDWP shutting down net...\n");
    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\n");
    196             }
    197         }
    198 
    199         if (gDvm.verboseShutdown)
    200             LOGD("JDWP freeing netstate...\n");
    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  */
    213 bool 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  */
    222 static void* jdwpThreadStart(void* arg)
    223 {
    224     JdwpState* state = (JdwpState*) arg;
    225 
    226     LOGV("JDWP: thread running\n");
    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\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         /* 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\n");
    336     return NULL;
    337 }
    338 
    339 
    340 /*
    341  * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
    342  */
    343 pthread_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  */
    375 s8 dvmJdwpGetNowMsec(void)
    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  */
    394 s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
    395 {
    396     if (!gDvm.debuggerActive) {
    397         LOGD("dvmJdwpLastDebuggerActivity: no active debugger\n");
    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\n");
    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\n", now - last);
    414     return now - last;
    415 }
    416