Bring across the JDWP implementation.

This compiles and links, but does nothing until we fill out the 100 or so
unimplemented methods in "debugger.cc". Note that I also need to add the
extra command-line handling for the JDWP agent stuff, and add calls from
the runtime to the various "something interesting is going on" hooks.

Change-Id: I477cf3caf9e248c384ce1d739cbfadb60e2008bc
diff --git a/src/jdwp/jdwp_main.cc b/src/jdwp/jdwp_main.cc
new file mode 100644
index 0000000..f2ff937
--- /dev/null
+++ b/src/jdwp/jdwp_main.cc
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * JDWP initialization.
+ */
+
+#include "atomic.h"
+#include "debugger.h"
+#include "jdwp/jdwp_priv.h"
+#include "logging.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+namespace art {
+
+namespace JDWP {
+
+static void* jdwpThreadStart(void* arg);
+
+/*
+ * JdwpNetStateBase class implementation
+ */
+JdwpNetStateBase::JdwpNetStateBase() : socket_lock_("JdwpNetStateBase lock") {
+  clientSock = -1;
+}
+
+/*
+ * Write a packet. Grabs a mutex to assure atomicity.
+ */
+ssize_t JdwpNetStateBase::writePacket(ExpandBuf* pReply) {
+  MutexLock mu(socket_lock_);
+  return write(clientSock, expandBufGetBuffer(pReply), expandBufGetLength(pReply));
+}
+
+/*
+ * Write a buffered packet. Grabs a mutex to assure atomicity.
+ */
+ssize_t JdwpNetStateBase::writeBufferedPacket(const iovec* iov, int iovcnt) {
+  MutexLock mu(socket_lock_);
+  return writev(clientSock, iov, iovcnt);
+}
+
+bool NetStartup(JdwpState* state, const JdwpStartupParams* pParams) {
+  return (*state->transport->startup)(state, pParams);
+}
+
+bool AcceptConnection(JdwpState* state) {
+  return (*state->transport->accept)(state);
+}
+
+bool EstablishConnection(JdwpState* state) {
+  return (*state->transport->establish)(state);
+}
+
+void CloseConnection(JdwpState* state) {
+  (*state->transport->close)(state);
+}
+
+void NetShutdown(JdwpState* state) {
+  (*state->transport->shutdown)(state);
+}
+
+void NetFree(JdwpState* state) {
+  (*state->transport->free)(state);
+}
+
+bool IsTransportDefined(JdwpState* state) {
+  return state != NULL && state->transport != NULL;
+}
+
+bool JdwpIsConnected(JdwpState* state) {
+  return state != NULL && (*state->transport->isConnected)(state);
+}
+
+bool AwaitingHandshake(JdwpState* state) {
+  return (*state->transport->awaitingHandshake)(state);
+}
+
+bool ProcessIncoming(JdwpState* state) {
+  return (*state->transport->processIncoming)(state);
+}
+
+bool SendRequest(JdwpState* state, ExpandBuf* pReq) {
+  return (*state->transport->sendRequest)(state, pReq);
+}
+
+static void CreateJdwpThread(JdwpState* state) {
+  CHECK_PTHREAD_CALL(pthread_create, (&state->debugThreadHandle, NULL, jdwpThreadStart, state), "JDWP thread");
+}
+
+JdwpState::JdwpState()
+    : thread_start_lock_("JDWP thread start lock"),
+      thread_start_cond_("JDWP thread start condition variable"),
+      debug_thread_started_(false),
+      debugThreadId(0),
+      run(false),
+      transport(NULL),
+      netState(NULL),
+      attach_lock_("JDWP attach lock"),
+      attach_cond_("JDWP attach condition variable"),
+      lastActivityWhen(0),
+      requestSerial(0x10000000),
+      eventSerial(0x20000000),
+      serial_lock_("JDWP serial lock"),
+      numEvents(0),
+      eventList(NULL),
+      event_lock_("JDWP event lock"),
+      event_thread_lock_("JDWP event thread lock"),
+      event_thread_cond_("JDWP event thread condition variable"),
+      eventThreadId(0),
+      ddmActive(false) {
+}
+
+/*
+ * Initialize JDWP.
+ *
+ * Does not return until JDWP thread is running, but may return before
+ * the thread is accepting network connections.
+ */
+JdwpState* JdwpStartup(const JdwpStartupParams* pParams) {
+  /* comment this out when debugging JDWP itself */
+  //android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
+
+  JdwpState* state = new JdwpState;
+
+  state->params = *pParams;
+
+  switch (pParams->transport) {
+  case kJdwpTransportSocket:
+    // LOGD("prepping for JDWP over TCP");
+    state->transport = SocketTransport();
+    break;
+#ifdef HAVE_ANDROID_OS
+  case kJdwpTransportAndroidAdb:
+    // LOGD("prepping for JDWP over ADB");
+    state->transport = AndroidAdbTransport();
+    break;
+#endif
+  default:
+    LOG(FATAL) << "Unknown transport: " << pParams->transport;
+  }
+
+  if (!NetStartup(state, pParams)) {
+    goto fail;
+  }
+
+  /*
+   * Grab a mutex or two before starting the thread.  This ensures they
+   * won't signal the cond var before we're waiting.
+   */
+  state->thread_start_lock_.Lock();
+  if (pParams->suspend) {
+    state->attach_lock_.Lock();
+  }
+
+  /*
+   * We have bound to a port, or are trying to connect outbound to a
+   * debugger.  Create the JDWP thread and let it continue the mission.
+   */
+  CreateJdwpThread(state);
+
+  /*
+   * Wait until the thread finishes basic initialization.
+   * TODO: cond vars should be waited upon in a loop
+   */
+  state->thread_start_cond_.Wait(state->thread_start_lock_);
+  state->thread_start_lock_.Unlock();
+
+  /*
+   * For suspend=y, wait for the debugger to connect to us or for us to
+   * connect to the debugger.
+   *
+   * The JDWP thread will signal us when it connects successfully or
+   * times out (for timeout=xxx), so we have to check to see what happened
+   * when we wake up.
+   */
+  if (pParams->suspend) {
+    {
+      ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
+
+      state->attach_cond_.Wait(state->attach_lock_);
+      state->attach_lock_.Unlock();
+    }
+
+    if (!JdwpIsActive(state)) {
+      LOG(ERROR) << "JDWP connection failed";
+      goto fail;
+    }
+
+    LOG(INFO) << "JDWP connected";
+
+    /*
+     * Ordinarily we would pause briefly to allow the debugger to set
+     * breakpoints and so on, but for "suspend=y" the VM init code will
+     * pause the VM when it sends the VM_START message.
+     */
+  }
+
+  return state;
+
+fail:
+  JdwpShutdown(state);     // frees state
+  return NULL;
+}
+
+/*
+ * Reset all session-related state.  There should not be an active connection
+ * to the client at this point.  The rest of the VM still thinks there is
+ * a debugger attached.
+ *
+ * This includes freeing up the debugger event list.
+ */
+void ResetState(JdwpState* state) {
+  /* could reset the serial numbers, but no need to */
+
+  UnregisterAll(state);
+  CHECK(state->eventList == NULL);
+
+  /*
+   * Should not have one of these in progress.  If the debugger went away
+   * mid-request, though, we could see this.
+   */
+  if (state->eventThreadId != 0) {
+    LOG(WARNING) << "resetting state while event in progress";
+    DCHECK(false);
+  }
+}
+
+/*
+ * Tell the JDWP thread to shut down.  Frees "state".
+ */
+void JdwpShutdown(JdwpState* state) {
+  void* threadReturn;
+
+  if (state == NULL) {
+    return;
+  }
+
+  if (IsTransportDefined(state)) {
+    if (JdwpIsConnected(state)) {
+      PostVMDeath(state);
+    }
+
+    /*
+     * Close down the network to inspire the thread to halt.
+     */
+    LOG(DEBUG) << "JDWP shutting down net...";
+    NetShutdown(state);
+
+    if (state->debug_thread_started_) {
+      state->run = false;
+      if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
+        LOG(WARNING) << "JDWP thread join failed";
+      }
+    }
+
+    LOG(DEBUG) << "JDWP freeing netstate...";
+    NetFree(state);
+    state->netState = NULL;
+  }
+  CHECK(state->netState == NULL);
+
+  ResetState(state);
+  free(state);
+}
+
+/*
+ * Are we talking to a debugger?
+ */
+bool JdwpIsActive(JdwpState* state) {
+  return JdwpIsConnected(state);
+}
+
+/*
+ * Entry point for JDWP thread.  The thread was created through the VM
+ * mechanisms, so there is a java/lang/Thread associated with us.
+ */
+static void* jdwpThreadStart(void* arg) {
+  JdwpState* state = reinterpret_cast<JdwpState*>(arg);
+  CHECK(state != NULL);
+
+  Runtime* runtime = Runtime::Current();
+  runtime->AttachCurrentThread("JDWP", true);
+
+  LOG(VERBOSE) << "JDWP: thread running";
+
+  /*
+   * Finish initializing "state", then notify the creating thread that
+   * we're running.
+   */
+  state->debugThreadHandle = pthread_self();
+  state->run = true;
+  android_atomic_release_store(true, &state->debug_thread_started_);
+
+  state->thread_start_lock_.Lock();
+  state->thread_start_cond_.Wait(state->thread_start_lock_);
+  state->thread_start_lock_.Unlock();
+
+  /* set the thread state to VMWAIT so GCs don't wait for us */
+  Dbg::ThreadWaiting();
+
+  /*
+   * Loop forever if we're in server mode, processing connections.  In
+   * non-server mode, we bail out of the thread when the debugger drops
+   * us.
+   *
+   * We broadcast a notification when a debugger attaches, after we
+   * successfully process the handshake.
+   */
+  while (state->run) {
+    bool first;
+
+    if (state->params.server) {
+      /*
+       * Block forever, waiting for a connection.  To support the
+       * "timeout=xxx" option we'll need to tweak this.
+       */
+      if (!AcceptConnection(state)) {
+        break;
+      }
+    } else {
+      /*
+       * If we're not acting as a server, we need to connect out to the
+       * debugger.  To support the "timeout=xxx" option we need to
+       * have a timeout if the handshake reply isn't received in a
+       * reasonable amount of time.
+       */
+      if (!EstablishConnection(state)) {
+        /* wake anybody who was waiting for us to succeed */
+        MutexLock mu(state->attach_lock_);
+        state->attach_cond_.Broadcast();
+        break;
+      }
+    }
+
+    /* prep debug code to handle the new connection */
+    Dbg::Connected();
+
+    /* process requests until the debugger drops */
+    first = true;
+    while (true) {
+      // sanity check -- shouldn't happen?
+      if (Thread::Current()->GetState() != Thread::kVmWait) {
+        LOG(ERROR) << "JDWP thread no longer in VMWAIT (now " << Thread::Current()->GetState() << "); resetting";
+        Dbg::ThreadWaiting();
+      }
+
+      if (!ProcessIncoming(state)) {
+        /* blocking read */
+        break;
+      }
+
+      if (first && !AwaitingHandshake(state)) {
+        /* handshake worked, tell the interpreter that we're active */
+        first = false;
+
+        /* set thread ID; requires object registry to be active */
+        state->debugThreadId = Dbg::GetThreadSelfId();
+
+        /* wake anybody who's waiting for us */
+        MutexLock mu(state->attach_lock_);
+        state->attach_cond_.Broadcast();
+      }
+    }
+
+    CloseConnection(state);
+
+    if (state->ddmActive) {
+      state->ddmActive = false;
+
+      /* broadcast the disconnect; must be in RUNNING state */
+      Dbg::ThreadRunning();
+      Dbg::DdmDisconnected();
+      Dbg::ThreadWaiting();
+    }
+
+    /* release session state, e.g. remove breakpoint instructions */
+    ResetState(state);
+
+    /* tell the interpreter that the debugger is no longer around */
+    Dbg::Disconnected();
+
+    /* if we had threads suspended, resume them now */
+    Dbg::UndoDebuggerSuspensions();
+
+    /* if we connected out, this was a one-shot deal */
+    if (!state->params.server) {
+      state->run = false;
+    }
+  }
+
+  /* back to running, for thread shutdown */
+  Dbg::ThreadRunning();
+
+  LOG(VERBOSE) << "JDWP: thread exiting";
+  return NULL;
+}
+
+
+/*
+ * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
+ */
+pthread_t GetDebugThread(JdwpState* state) {
+  if (state == NULL) {
+    return 0;
+  }
+  return state->debugThreadHandle;
+}
+
+/*
+ * Support routines for waitForDebugger().
+ *
+ * We can't have a trivial "waitForDebugger" function that returns the
+ * instant the debugger connects, because we run the risk of executing code
+ * before the debugger has had a chance to configure breakpoints or issue
+ * suspend calls.  It would be nice to just sit in the suspended state, but
+ * most debuggers don't expect any threads to be suspended when they attach.
+ *
+ * There's no JDWP event we can post to tell the debugger, "we've stopped,
+ * and we like it that way".  We could send a fake breakpoint, which should
+ * cause the debugger to immediately send a resume, but the debugger might
+ * send the resume immediately or might throw an exception of its own upon
+ * receiving a breakpoint event that it didn't ask for.
+ *
+ * What we really want is a "wait until the debugger is done configuring
+ * stuff" event.  We can approximate this with a "wait until the debugger
+ * has been idle for a brief period".
+ */
+
+/*
+ * Get a notion of the current time, in milliseconds.
+ */
+int64_t GetNowMsec() {
+#ifdef HAVE_POSIX_CLOCKS
+  struct timespec now;
+  clock_gettime(CLOCK_MONOTONIC, &now);
+  return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
+#else
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
+#endif
+}
+
+/*
+ * Return the time, in milliseconds, since the last debugger activity.
+ *
+ * Returns -1 if no debugger is attached, or 0 if we're in the middle of
+ * processing a debugger request.
+ */
+int64_t LastDebuggerActivity(JdwpState* state) {
+  if (!Dbg::IsDebuggerConnected()) {
+    LOG(DEBUG) << "no active debugger";
+    return -1;
+  }
+
+  int64_t last = QuasiAtomicRead64(&state->lastActivityWhen);
+
+  /* initializing or in the middle of something? */
+  if (last == 0) {
+    LOG(VERBOSE) << "+++ last=busy";
+    return 0;
+  }
+
+  /* now get the current time */
+  int64_t now = GetNowMsec();
+  CHECK_GT(now, last);
+
+  LOG(VERBOSE) << "+++ debugger interval=" << (now - last);
+  return now - last;
+}
+
+static const char* kTransportNames[] = {
+  "Unknown",
+  "Socket",
+  "AndroidAdb",
+};
+std::ostream& operator<<(std::ostream& os, const JdwpTransportType& value) {
+  int32_t int_value = static_cast<int32_t>(value);
+  if (value >= kJdwpTransportUnknown && value <= kJdwpTransportAndroidAdb) {
+    os << kTransportNames[int_value];
+  } else {
+    os << "JdwpTransportType[" << int_value << "]";
+  }
+  return os;
+}
+
+}  // namespace JDWP
+
+}  // namespace art