Add the missing link between compiled code and the debugger.

When a debugger connects and disconnects, we now let compiled code know that we
need to be kept informed about what's going on.

Also fix a threading bug when threads exit with a debugger attached.

Also some minor tidying, mostly involving naming.

Change-Id: Iba0e8b9d192ac76ba1cd29a8b1e6d94f6f20dea8
diff --git a/src/debugger.cc b/src/debugger.cc
index 71776ae..569ea81 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -149,10 +149,10 @@
 // JDWP is allowed unless the Zygote forbids it.
 static bool gJdwpAllowed = true;
 
-// Was there a -Xrunjdwp or -agent argument on the command-line?
+// Was there a -Xrunjdwp or -agentlib:jdwp= argument on the command line?
 static bool gJdwpConfigured = false;
 
-// Broken-down JDWP options. (Only valid if gJdwpConfigured is true.)
+// Broken-down JDWP options. (Only valid if IsJdwpConfigured() is true.)
 static JDWP::JdwpOptions gJdwpOptions;
 
 // Runtime JDWP state.
@@ -396,7 +396,7 @@
 }
 
 void Dbg::StartJdwp() {
-  if (!gJdwpAllowed || !gJdwpConfigured) {
+  if (!gJdwpAllowed || !IsJdwpConfigured()) {
     // No JDWP for you!
     return;
   }
@@ -477,6 +477,16 @@
   return gDisposed;
 }
 
+static void SetDebuggerUpdatesEnabledCallback(Thread* t, void* user_data) {
+  t->SetDebuggerUpdatesEnabled(*reinterpret_cast<bool*>(user_data));
+}
+
+static void SetDebuggerUpdatesEnabled(bool enabled) {
+  Runtime* runtime = Runtime::Current();
+  ScopedThreadListLock thread_list_lock;
+  runtime->GetThreadList()->ForEach(SetDebuggerUpdatesEnabledCallback, &enabled);
+}
+
 void Dbg::GoActive() {
   // Enable all debugging features, including scans for breakpoints.
   // This is a no-op if we're already active.
@@ -487,29 +497,33 @@
 
   LOG(INFO) << "Debugger is active";
 
-  // TODO: CHECK we don't have any outstanding breakpoints.
+  {
+    // TODO: dalvik only warned if there were breakpoints left over. clear in Dbg::Disconnected?
+    MutexLock mu(gBreakpointsLock);
+    CHECK_EQ(gBreakpoints.size(), 0U);
+  }
 
   gDebuggerActive = true;
-
-  //dvmEnableAllSubMode(kSubModeDebuggerActive);
+  SetDebuggerUpdatesEnabled(true);
 }
 
 void Dbg::Disconnected() {
   CHECK(gDebuggerConnected);
 
-  gDebuggerActive = false;
+  LOG(INFO) << "Debugger is no longer active";
 
-  //dvmDisableAllSubMode(kSubModeDebuggerActive);
+  gDebuggerActive = false;
+  SetDebuggerUpdatesEnabled(false);
 
   gRegistry->Clear();
   gDebuggerConnected = false;
 }
 
-bool Dbg::IsDebuggerConnected() {
+bool Dbg::IsDebuggerActive() {
   return gDebuggerActive;
 }
 
-bool Dbg::IsDebuggingEnabled() {
+bool Dbg::IsJdwpConfigured() {
   return gJdwpConfigured;
 }
 
@@ -1379,7 +1393,6 @@
   case Thread::kTimedWaiting: *pThreadStatus = JDWP::TS_WAIT;     break;
   case Thread::kBlocked:      *pThreadStatus = JDWP::TS_MONITOR;  break;
   case Thread::kWaiting:      *pThreadStatus = JDWP::TS_WAIT;     break;
-  case Thread::kInitializing: *pThreadStatus = JDWP::TS_ZOMBIE;   break;
   case Thread::kStarting:     *pThreadStatus = JDWP::TS_ZOMBIE;   break;
   case Thread::kNative:       *pThreadStatus = JDWP::TS_RUNNING;  break;
   case Thread::kVmWait:       *pThreadStatus = JDWP::TS_WAIT;     break;
@@ -1736,7 +1749,7 @@
 }
 
 void Dbg::PostException(Method** sp, Method* throwMethod, uintptr_t throwNativePc, Method* catchMethod, uintptr_t catchNativePc, Object* exception) {
-  if (!gDebuggerActive) {
+  if (!IsDebuggerActive()) {
     return;
   }
 
@@ -1765,7 +1778,7 @@
 }
 
 void Dbg::PostClassPrepare(Class* c) {
-  if (!gDebuggerActive) {
+  if (!IsDebuggerActive()) {
     return;
   }
 
@@ -1778,7 +1791,7 @@
 }
 
 void Dbg::UpdateDebugger(int32_t dex_pc, Thread* self, Method** sp) {
-  if (!gDebuggerActive || dex_pc == -2 /* fake method exit */) {
+  if (!IsDebuggerActive() || dex_pc == -2 /* fake method exit */) {
     return;
   }
 
@@ -2461,9 +2474,12 @@
 }
 
 void Dbg::PostThreadStartOrStop(Thread* t, uint32_t type) {
-  if (gDebuggerActive) {
+  if (IsDebuggerActive()) {
     JDWP::ObjectId id = gRegistry->Add(t->GetPeer());
     gJdwpState->PostThreadChange(id, type == CHUNK_TYPE("THCR"));
+    // If this thread's just joined the party while we're already debugging, make sure it knows
+    // to give us updates when it's running.
+    t->SetDebuggerUpdatesEnabled(true);
   }
   Dbg::DdmSendThreadNotification(t, type);
 }