blob: f2ff9370715bd8342174b92f576a6c5fd36a18d8 [file] [log] [blame]
Elliott Hughes872d4ec2011-10-21 17:07:15 -07001/*
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
21#include "atomic.h"
22#include "debugger.h"
23#include "jdwp/jdwp_priv.h"
24#include "logging.h"
25
26#include <stdlib.h>
27#include <unistd.h>
28#include <sys/time.h>
29#include <time.h>
30#include <errno.h>
31
32namespace art {
33
34namespace JDWP {
35
36static void* jdwpThreadStart(void* arg);
37
38/*
39 * JdwpNetStateBase class implementation
40 */
41JdwpNetStateBase::JdwpNetStateBase() : socket_lock_("JdwpNetStateBase lock") {
42 clientSock = -1;
43}
44
45/*
46 * Write a packet. Grabs a mutex to assure atomicity.
47 */
48ssize_t JdwpNetStateBase::writePacket(ExpandBuf* pReply) {
49 MutexLock mu(socket_lock_);
50 return write(clientSock, expandBufGetBuffer(pReply), expandBufGetLength(pReply));
51}
52
53/*
54 * Write a buffered packet. Grabs a mutex to assure atomicity.
55 */
56ssize_t JdwpNetStateBase::writeBufferedPacket(const iovec* iov, int iovcnt) {
57 MutexLock mu(socket_lock_);
58 return writev(clientSock, iov, iovcnt);
59}
60
61bool NetStartup(JdwpState* state, const JdwpStartupParams* pParams) {
62 return (*state->transport->startup)(state, pParams);
63}
64
65bool AcceptConnection(JdwpState* state) {
66 return (*state->transport->accept)(state);
67}
68
69bool EstablishConnection(JdwpState* state) {
70 return (*state->transport->establish)(state);
71}
72
73void CloseConnection(JdwpState* state) {
74 (*state->transport->close)(state);
75}
76
77void NetShutdown(JdwpState* state) {
78 (*state->transport->shutdown)(state);
79}
80
81void NetFree(JdwpState* state) {
82 (*state->transport->free)(state);
83}
84
85bool IsTransportDefined(JdwpState* state) {
86 return state != NULL && state->transport != NULL;
87}
88
89bool JdwpIsConnected(JdwpState* state) {
90 return state != NULL && (*state->transport->isConnected)(state);
91}
92
93bool AwaitingHandshake(JdwpState* state) {
94 return (*state->transport->awaitingHandshake)(state);
95}
96
97bool ProcessIncoming(JdwpState* state) {
98 return (*state->transport->processIncoming)(state);
99}
100
101bool SendRequest(JdwpState* state, ExpandBuf* pReq) {
102 return (*state->transport->sendRequest)(state, pReq);
103}
104
105static void CreateJdwpThread(JdwpState* state) {
106 CHECK_PTHREAD_CALL(pthread_create, (&state->debugThreadHandle, NULL, jdwpThreadStart, state), "JDWP thread");
107}
108
109JdwpState::JdwpState()
110 : thread_start_lock_("JDWP thread start lock"),
111 thread_start_cond_("JDWP thread start condition variable"),
112 debug_thread_started_(false),
113 debugThreadId(0),
114 run(false),
115 transport(NULL),
116 netState(NULL),
117 attach_lock_("JDWP attach lock"),
118 attach_cond_("JDWP attach condition variable"),
119 lastActivityWhen(0),
120 requestSerial(0x10000000),
121 eventSerial(0x20000000),
122 serial_lock_("JDWP serial lock"),
123 numEvents(0),
124 eventList(NULL),
125 event_lock_("JDWP event lock"),
126 event_thread_lock_("JDWP event thread lock"),
127 event_thread_cond_("JDWP event thread condition variable"),
128 eventThreadId(0),
129 ddmActive(false) {
130}
131
132/*
133 * Initialize JDWP.
134 *
135 * Does not return until JDWP thread is running, but may return before
136 * the thread is accepting network connections.
137 */
138JdwpState* JdwpStartup(const JdwpStartupParams* pParams) {
139 /* comment this out when debugging JDWP itself */
140 //android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
141
142 JdwpState* state = new JdwpState;
143
144 state->params = *pParams;
145
146 switch (pParams->transport) {
147 case kJdwpTransportSocket:
148 // LOGD("prepping for JDWP over TCP");
149 state->transport = SocketTransport();
150 break;
151#ifdef HAVE_ANDROID_OS
152 case kJdwpTransportAndroidAdb:
153 // LOGD("prepping for JDWP over ADB");
154 state->transport = AndroidAdbTransport();
155 break;
156#endif
157 default:
158 LOG(FATAL) << "Unknown transport: " << pParams->transport;
159 }
160
161 if (!NetStartup(state, pParams)) {
162 goto fail;
163 }
164
165 /*
166 * Grab a mutex or two before starting the thread. This ensures they
167 * won't signal the cond var before we're waiting.
168 */
169 state->thread_start_lock_.Lock();
170 if (pParams->suspend) {
171 state->attach_lock_.Lock();
172 }
173
174 /*
175 * We have bound to a port, or are trying to connect outbound to a
176 * debugger. Create the JDWP thread and let it continue the mission.
177 */
178 CreateJdwpThread(state);
179
180 /*
181 * Wait until the thread finishes basic initialization.
182 * TODO: cond vars should be waited upon in a loop
183 */
184 state->thread_start_cond_.Wait(state->thread_start_lock_);
185 state->thread_start_lock_.Unlock();
186
187 /*
188 * For suspend=y, wait for the debugger to connect to us or for us to
189 * connect to the debugger.
190 *
191 * The JDWP thread will signal us when it connects successfully or
192 * times out (for timeout=xxx), so we have to check to see what happened
193 * when we wake up.
194 */
195 if (pParams->suspend) {
196 {
197 ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
198
199 state->attach_cond_.Wait(state->attach_lock_);
200 state->attach_lock_.Unlock();
201 }
202
203 if (!JdwpIsActive(state)) {
204 LOG(ERROR) << "JDWP connection failed";
205 goto fail;
206 }
207
208 LOG(INFO) << "JDWP connected";
209
210 /*
211 * Ordinarily we would pause briefly to allow the debugger to set
212 * breakpoints and so on, but for "suspend=y" the VM init code will
213 * pause the VM when it sends the VM_START message.
214 */
215 }
216
217 return state;
218
219fail:
220 JdwpShutdown(state); // frees state
221 return NULL;
222}
223
224/*
225 * Reset all session-related state. There should not be an active connection
226 * to the client at this point. The rest of the VM still thinks there is
227 * a debugger attached.
228 *
229 * This includes freeing up the debugger event list.
230 */
231void ResetState(JdwpState* state) {
232 /* could reset the serial numbers, but no need to */
233
234 UnregisterAll(state);
235 CHECK(state->eventList == NULL);
236
237 /*
238 * Should not have one of these in progress. If the debugger went away
239 * mid-request, though, we could see this.
240 */
241 if (state->eventThreadId != 0) {
242 LOG(WARNING) << "resetting state while event in progress";
243 DCHECK(false);
244 }
245}
246
247/*
248 * Tell the JDWP thread to shut down. Frees "state".
249 */
250void JdwpShutdown(JdwpState* state) {
251 void* threadReturn;
252
253 if (state == NULL) {
254 return;
255 }
256
257 if (IsTransportDefined(state)) {
258 if (JdwpIsConnected(state)) {
259 PostVMDeath(state);
260 }
261
262 /*
263 * Close down the network to inspire the thread to halt.
264 */
265 LOG(DEBUG) << "JDWP shutting down net...";
266 NetShutdown(state);
267
268 if (state->debug_thread_started_) {
269 state->run = false;
270 if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
271 LOG(WARNING) << "JDWP thread join failed";
272 }
273 }
274
275 LOG(DEBUG) << "JDWP freeing netstate...";
276 NetFree(state);
277 state->netState = NULL;
278 }
279 CHECK(state->netState == NULL);
280
281 ResetState(state);
282 free(state);
283}
284
285/*
286 * Are we talking to a debugger?
287 */
288bool JdwpIsActive(JdwpState* state) {
289 return JdwpIsConnected(state);
290}
291
292/*
293 * Entry point for JDWP thread. The thread was created through the VM
294 * mechanisms, so there is a java/lang/Thread associated with us.
295 */
296static void* jdwpThreadStart(void* arg) {
297 JdwpState* state = reinterpret_cast<JdwpState*>(arg);
298 CHECK(state != NULL);
299
300 Runtime* runtime = Runtime::Current();
301 runtime->AttachCurrentThread("JDWP", true);
302
303 LOG(VERBOSE) << "JDWP: thread running";
304
305 /*
306 * Finish initializing "state", then notify the creating thread that
307 * we're running.
308 */
309 state->debugThreadHandle = pthread_self();
310 state->run = true;
311 android_atomic_release_store(true, &state->debug_thread_started_);
312
313 state->thread_start_lock_.Lock();
314 state->thread_start_cond_.Wait(state->thread_start_lock_);
315 state->thread_start_lock_.Unlock();
316
317 /* set the thread state to VMWAIT so GCs don't wait for us */
318 Dbg::ThreadWaiting();
319
320 /*
321 * Loop forever if we're in server mode, processing connections. In
322 * non-server mode, we bail out of the thread when the debugger drops
323 * us.
324 *
325 * We broadcast a notification when a debugger attaches, after we
326 * successfully process the handshake.
327 */
328 while (state->run) {
329 bool first;
330
331 if (state->params.server) {
332 /*
333 * Block forever, waiting for a connection. To support the
334 * "timeout=xxx" option we'll need to tweak this.
335 */
336 if (!AcceptConnection(state)) {
337 break;
338 }
339 } else {
340 /*
341 * If we're not acting as a server, we need to connect out to the
342 * debugger. To support the "timeout=xxx" option we need to
343 * have a timeout if the handshake reply isn't received in a
344 * reasonable amount of time.
345 */
346 if (!EstablishConnection(state)) {
347 /* wake anybody who was waiting for us to succeed */
348 MutexLock mu(state->attach_lock_);
349 state->attach_cond_.Broadcast();
350 break;
351 }
352 }
353
354 /* prep debug code to handle the new connection */
355 Dbg::Connected();
356
357 /* process requests until the debugger drops */
358 first = true;
359 while (true) {
360 // sanity check -- shouldn't happen?
361 if (Thread::Current()->GetState() != Thread::kVmWait) {
362 LOG(ERROR) << "JDWP thread no longer in VMWAIT (now " << Thread::Current()->GetState() << "); resetting";
363 Dbg::ThreadWaiting();
364 }
365
366 if (!ProcessIncoming(state)) {
367 /* blocking read */
368 break;
369 }
370
371 if (first && !AwaitingHandshake(state)) {
372 /* handshake worked, tell the interpreter that we're active */
373 first = false;
374
375 /* set thread ID; requires object registry to be active */
376 state->debugThreadId = Dbg::GetThreadSelfId();
377
378 /* wake anybody who's waiting for us */
379 MutexLock mu(state->attach_lock_);
380 state->attach_cond_.Broadcast();
381 }
382 }
383
384 CloseConnection(state);
385
386 if (state->ddmActive) {
387 state->ddmActive = false;
388
389 /* broadcast the disconnect; must be in RUNNING state */
390 Dbg::ThreadRunning();
391 Dbg::DdmDisconnected();
392 Dbg::ThreadWaiting();
393 }
394
395 /* release session state, e.g. remove breakpoint instructions */
396 ResetState(state);
397
398 /* tell the interpreter that the debugger is no longer around */
399 Dbg::Disconnected();
400
401 /* if we had threads suspended, resume them now */
402 Dbg::UndoDebuggerSuspensions();
403
404 /* if we connected out, this was a one-shot deal */
405 if (!state->params.server) {
406 state->run = false;
407 }
408 }
409
410 /* back to running, for thread shutdown */
411 Dbg::ThreadRunning();
412
413 LOG(VERBOSE) << "JDWP: thread exiting";
414 return NULL;
415}
416
417
418/*
419 * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
420 */
421pthread_t GetDebugThread(JdwpState* state) {
422 if (state == NULL) {
423 return 0;
424 }
425 return state->debugThreadHandle;
426}
427
428/*
429 * Support routines for waitForDebugger().
430 *
431 * We can't have a trivial "waitForDebugger" function that returns the
432 * instant the debugger connects, because we run the risk of executing code
433 * before the debugger has had a chance to configure breakpoints or issue
434 * suspend calls. It would be nice to just sit in the suspended state, but
435 * most debuggers don't expect any threads to be suspended when they attach.
436 *
437 * There's no JDWP event we can post to tell the debugger, "we've stopped,
438 * and we like it that way". We could send a fake breakpoint, which should
439 * cause the debugger to immediately send a resume, but the debugger might
440 * send the resume immediately or might throw an exception of its own upon
441 * receiving a breakpoint event that it didn't ask for.
442 *
443 * What we really want is a "wait until the debugger is done configuring
444 * stuff" event. We can approximate this with a "wait until the debugger
445 * has been idle for a brief period".
446 */
447
448/*
449 * Get a notion of the current time, in milliseconds.
450 */
451int64_t GetNowMsec() {
452#ifdef HAVE_POSIX_CLOCKS
453 struct timespec now;
454 clock_gettime(CLOCK_MONOTONIC, &now);
455 return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
456#else
457 struct timeval now;
458 gettimeofday(&now, NULL);
459 return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
460#endif
461}
462
463/*
464 * Return the time, in milliseconds, since the last debugger activity.
465 *
466 * Returns -1 if no debugger is attached, or 0 if we're in the middle of
467 * processing a debugger request.
468 */
469int64_t LastDebuggerActivity(JdwpState* state) {
470 if (!Dbg::IsDebuggerConnected()) {
471 LOG(DEBUG) << "no active debugger";
472 return -1;
473 }
474
475 int64_t last = QuasiAtomicRead64(&state->lastActivityWhen);
476
477 /* initializing or in the middle of something? */
478 if (last == 0) {
479 LOG(VERBOSE) << "+++ last=busy";
480 return 0;
481 }
482
483 /* now get the current time */
484 int64_t now = GetNowMsec();
485 CHECK_GT(now, last);
486
487 LOG(VERBOSE) << "+++ debugger interval=" << (now - last);
488 return now - last;
489}
490
491static const char* kTransportNames[] = {
492 "Unknown",
493 "Socket",
494 "AndroidAdb",
495};
496std::ostream& operator<<(std::ostream& os, const JdwpTransportType& value) {
497 int32_t int_value = static_cast<int32_t>(value);
498 if (value >= kJdwpTransportUnknown && value <= kJdwpTransportAndroidAdb) {
499 os << kTransportNames[int_value];
500 } else {
501 os << "JdwpTransportType[" << int_value << "]";
502 }
503 return os;
504}
505
506} // namespace JDWP
507
508} // namespace art