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 = 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 = 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 // LOGD("prepping for JDWP over TCP"); 100 state->transport = dvmJdwpSocketTransport(); 101 break; 102 case kJdwpTransportAndroidAdb: 103 // LOGD("prepping for JDWP over ADB"); 104 state->transport = dvmJdwpAndroidAdbTransport(); 105 /* TODO */ 106 break; 107 default: 108 LOGE("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 LOGE("JDWP connection failed"); 162 goto fail; 163 } 164 165 LOGI("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 LOGW("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 LOGD("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 LOGW("JDWP thread join failed"); 230 } 231 } 232 233 if (gDvm.verboseShutdown) 234 LOGD("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 LOGV("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 LOGE("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 LOGV("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 LOGD("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 LOGV("+++ last=busy"); 440 return 0; 441 } 442 443 /* now get the current time */ 444 s8 now = dvmJdwpGetNowMsec(); 445 assert(now > last); 446 447 LOGV("+++ debugger interval=%lld", now - last); 448 return now - last; 449 } 450