Implement thread name change notification for DDMS.

Change-Id: If63d89991951989f27ee267895244e115661dce9
diff --git a/src/debugger.cc b/src/debugger.cc
index 828ee4a..d8f58da 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -791,42 +791,43 @@
 }
 
 /*
- * Send a notification when a thread starts or stops.
+ * Send a notification when a thread starts, stops, or changes its name.
  *
  * Because we broadcast the full set of threads when the notifications are
  * first enabled, it's possible for "thread" to be actively executing.
  */
-void DdmSendThreadNotification(Thread* t, bool started) {
+void Dbg::DdmSendThreadNotification(Thread* t, uint32_t type) {
   if (!gDdmThreadNotification) {
     return;
   }
 
-  if (started) {
-    SirtRef<String> name(t->GetName());
-    size_t char_count = (name.get() != NULL) ? name->GetLength() : 0;
-
-    size_t byte_count = char_count*2 + sizeof(uint32_t)*2;
-    std::vector<uint8_t> buf(byte_count);
-    JDWP::Set4BE(&buf[0], t->GetThinLockId());
-    JDWP::Set4BE(&buf[4], char_count);
-    if (char_count > 0) {
-      // Copy the UTF-16 string, transforming to big-endian.
-      const jchar* src = name->GetCharArray()->GetData();
-      jchar* dst = reinterpret_cast<jchar*>(&buf[8]);
-      while (char_count--) {
-        JDWP::Set2BE(reinterpret_cast<uint8_t*>(dst++), *src++);
-      }
-    }
-    Dbg::DdmSendChunk(CHUNK_TYPE("THCR"), buf.size(), &buf[0]);
-  } else {
+  if (type == CHUNK_TYPE("THDE")) {
     uint8_t buf[4];
     JDWP::Set4BE(&buf[0], t->GetThinLockId());
     Dbg::DdmSendChunk(CHUNK_TYPE("THDE"), 4, buf);
+  } else {
+    CHECK(type == CHUNK_TYPE("THCR") || type == CHUNK_TYPE("THNM")) << type;
+    SirtRef<String> name(t->GetName());
+    size_t char_count = (name.get() != NULL) ? name->GetLength() : 0;
+    const jchar* chars = name->GetCharArray()->GetData();
+
+    size_t byte_count = char_count*2 + sizeof(uint32_t)*2;
+    std::vector<uint8_t> bytes(byte_count);
+    uint8_t* dst = &bytes[0];
+    JDWP::Write4BE(&dst, t->GetThinLockId());
+    JDWP::Write4BE(&dst, char_count);
+    if (char_count > 0) {
+      // Copy the UTF-16 string, transforming to big-endian.
+      while (char_count--) {
+        JDWP::Write2BE(&dst, *chars++);
+      }
+    }
+    Dbg::DdmSendChunk(type, bytes.size(), &bytes[0]);
   }
 }
 
 void DdmSendThreadStartCallback(Thread* t, void*) {
-  DdmSendThreadNotification(t, true);
+  Dbg::DdmSendThreadNotification(t, CHUNK_TYPE("THCR"));
 }
 
 void Dbg::DdmSetThreadNotification(bool enable) {
@@ -841,23 +842,23 @@
   }
 }
 
-void PostThreadStartOrStop(Thread* t, bool is_start) {
+void PostThreadStartOrStop(Thread* t, uint32_t type) {
   if (gDebuggerActive) {
     JDWP::ObjectId id = gRegistry->Add(t->GetPeer());
-    gJdwpState->PostThreadChange(id, is_start);
+    gJdwpState->PostThreadChange(id, type == CHUNK_TYPE("THCR"));
   }
-  DdmSendThreadNotification(t, is_start);
+  Dbg::DdmSendThreadNotification(t, type);
 }
 
 void Dbg::PostThreadStart(Thread* t) {
-  PostThreadStartOrStop(t, true);
+  PostThreadStartOrStop(t, CHUNK_TYPE("THCR"));
 }
 
 void Dbg::PostThreadDeath(Thread* t) {
-  PostThreadStartOrStop(t, false);
+  PostThreadStartOrStop(t, CHUNK_TYPE("THDE"));
 }
 
-void Dbg::DdmSendChunk(int type, size_t byte_count, const uint8_t* buf) {
+void Dbg::DdmSendChunk(uint32_t type, size_t byte_count, const uint8_t* buf) {
   CHECK(buf != NULL);
   iovec vec[1];
   vec[0].iov_base = reinterpret_cast<void*>(const_cast<uint8_t*>(buf));
@@ -865,7 +866,7 @@
   Dbg::DdmSendChunkV(type, vec, 1);
 }
 
-void Dbg::DdmSendChunkV(int type, const struct iovec* iov, int iovcnt) {
+void Dbg::DdmSendChunkV(uint32_t type, const struct iovec* iov, int iovcnt) {
   if (gJdwpState == NULL) {
     LOG(VERBOSE) << "Debugger thread not active, ignoring DDM send: " << type;
   } else {
@@ -977,7 +978,7 @@
   uint8_t* p;
   uint8_t* pieceLenField;
   size_t totalAllocationUnits;
-  int type;
+  uint32_t type;
   bool merge;
   bool needHeader;
 
diff --git a/src/debugger.h b/src/debugger.h
index b85a65d..7ae6609 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -232,12 +232,13 @@
   /*
    * DDM support.
    */
+  static void DdmSendThreadNotification(Thread* t, uint32_t type);
   static void DdmSetThreadNotification(bool enable);
   static bool DdmHandlePacket(const uint8_t* buf, int dataLen, uint8_t** pReplyBuf, int* pReplyLen);
   static void DdmConnected();
   static void DdmDisconnected();
-  static void DdmSendChunk(int type, size_t len, const uint8_t* buf);
-  static void DdmSendChunkV(int type, const struct iovec* iov, int iovcnt);
+  static void DdmSendChunk(uint32_t type, size_t len, const uint8_t* buf);
+  static void DdmSendChunkV(uint32_t type, const struct iovec* iov, int iovcnt);
 
   enum HpifWhen {
     HPIF_WHEN_NEVER = 0,
@@ -262,7 +263,7 @@
 };
 
 #define CHUNK_TYPE(_name) \
-    ((_name)[0] << 24 | (_name)[1] << 16 | (_name)[2] << 8 | (_name)[3])
+    static_cast<uint32_t>((_name)[0] << 24 | (_name)[1] << 16 | (_name)[2] << 8 | (_name)[3])
 
 }  // namespace art
 
diff --git a/src/java_lang_Thread.cc b/src/java_lang_Thread.cc
index 9031471..46b6241 100644
--- a/src/java_lang_Thread.cc
+++ b/src/java_lang_Thread.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "debugger.h"
 #include "jni_internal.h"
 #include "object.h"
 #include "ScopedUtfChars.h"
@@ -74,20 +75,13 @@
   }
 }
 
-void Thread_nativeSetName(JNIEnv* env, jobject javaThread, jstring javaName) {
+void Thread_nativeSetName(JNIEnv* env, jobject javaThread, jstring) {
   ScopedThreadListLock thread_list_lock;
   Thread* thread = Thread::FromManagedThread(env, javaThread);
-  if (thread != NULL) {
-    ScopedUtfChars name(env, javaName);
-    if (name.c_str() == NULL) {
-      return;
-    }
-    LOG(INFO) << "Thread " << *thread << " changing name to '" << name.c_str() << "'";
-    // TODO: needed for debugging (DDMS) support.
-    //StringObject* nameStr = (StringObject*) dvmDecodeIndirectRef(env, javaName);
-    //int threadId = (thread != NULL) ? thread->threadId : -1;
-    //dvmDdmSendThreadNameChange(threadId, nameStr);
+  if (thread == NULL) {
+    return;
   }
+  Dbg::DdmSendThreadNotification(thread, CHUNK_TYPE("THNM"));
 }
 
 /*
diff --git a/src/jdwp/jdwp.h b/src/jdwp/jdwp.h
index 2eae216..6f9625f 100644
--- a/src/jdwp/jdwp.h
+++ b/src/jdwp/jdwp.h
@@ -210,7 +210,7 @@
   /*
    * Send up a chunk of DDM data.
    */
-  void DdmSendChunkV(int type, const iovec* iov, int iovcnt);
+  void DdmSendChunkV(uint32_t type, const iovec* iov, int iovcnt);
 
   /*
    * Process a request from the debugger.
diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc
index 7d341d8..6b5ef8c 100644
--- a/src/jdwp/jdwp_event.cc
+++ b/src/jdwp/jdwp_event.cc
@@ -1146,7 +1146,7 @@
  * other debugger traffic, and can't suspend the VM, so we skip all of
  * the fun event token gymnastics.
  */
-void JdwpState::DdmSendChunkV(int type, const iovec* iov, int iovcnt) {
+void JdwpState::DdmSendChunkV(uint32_t type, const iovec* iov, int iovcnt) {
   uint8_t header[kJDWPHeaderLen + 8];
   size_t dataLen = 0;
 
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 45eedb8..5787c65 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -79,7 +79,6 @@
     locals.Dump();
     LOG(FATAL) << "Failed adding to JNI local reference table "
                << "(has " << locals.Capacity() << " entries)";
-    // TODO: dvmDumpThread(dvmThreadSelf(), false);
   }
 
 #if 0 // TODO: fix this to understand PushLocalFrame, so we can turn it on.
@@ -89,8 +88,7 @@
       LOG(WARNING) << "Warning: more than 16 JNI local references: "
                    << entry_count << " (most recent was a " << PrettyTypeOf(obj) << ")";
       locals.Dump();
-      // TODO: dvmDumpThread(dvmThreadSelf(), false);
-      // dvmAbort();
+      // TODO: LOG(FATAL) instead.
     }
   }
 #endif