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  * JdwpNetStateBase class implementation
     35  */
     36 JdwpNetStateBase::JdwpNetStateBase()
     37 {
     38     clientSock = -1;
     39     dvmDbgInitMutex(&socketLock);
     40 }
     41 
     42 /*
     43  * Write a packet. Grabs a mutex to assure atomicity.
     44  */
     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  */
     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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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