Include the thread name in Thread's operator<< output.

For example:

 Thread[2,tid=1692,VmWait,Thread*=0x416914d0,"Signal Catcher"]: reacting to signal 3

Change-Id: I2b00e82af2ad0f09141dbf4e418bc0582e9b966d
diff --git a/src/dalvik_system_VMDebug.cc b/src/dalvik_system_VMDebug.cc
index c388e62..5f4b6d9 100644
--- a/src/dalvik_system_VMDebug.cc
+++ b/src/dalvik_system_VMDebug.cc
@@ -224,10 +224,7 @@
  * for seeing both interpreted and native stack traces.
  */
 void VMDebug_crash(JNIEnv*, jclass) {
-  std::ostringstream os;
-  os << "Crashing VM on request:\n";
-  Thread::Current()->Dump(os);
-  LOG(FATAL) << os.str();
+  LOG(FATAL) << "Crashing VM on request";
 }
 
 /*
diff --git a/src/debugger.cc b/src/debugger.cc
index 751efa1..f1e6066 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -1088,7 +1088,7 @@
   if (thread == NULL) {
     return false;
   }
-  StringAppendF(&name, "<%d> %s", thread->GetThinLockId(), thread->GetName()->ToModifiedUtf8().c_str());
+  StringAppendF(&name, "<%d> %s", thread->GetThinLockId(), thread->GetThreadName()->ToModifiedUtf8().c_str());
   return true;
 }
 
@@ -1873,7 +1873,7 @@
     Dbg::DdmSendChunk(CHUNK_TYPE("THDE"), 4, buf);
   } else {
     CHECK(type == CHUNK_TYPE("THCR") || type == CHUNK_TYPE("THNM")) << type;
-    SirtRef<String> name(t->GetName());
+    SirtRef<String> name(t->GetThreadName());
     size_t char_count = (name.get() != NULL) ? name->GetLength() : 0;
     const jchar* chars = name->GetCharArray()->GetData();
 
diff --git a/src/java_lang_Thread.cc b/src/java_lang_Thread.cc
index 46b6241..0338454 100644
--- a/src/java_lang_Thread.cc
+++ b/src/java_lang_Thread.cc
@@ -75,13 +75,17 @@
   }
 }
 
-void Thread_nativeSetName(JNIEnv* env, jobject javaThread, jstring) {
+void Thread_nativeSetName(JNIEnv* env, jobject javaThread, jstring javaName) {
   ScopedThreadListLock thread_list_lock;
   Thread* thread = Thread::FromManagedThread(env, javaThread);
   if (thread == NULL) {
     return;
   }
-  Dbg::DdmSendThreadNotification(thread, CHUNK_TYPE("THNM"));
+  ScopedUtfChars name(env, javaName);
+  if (name.c_str() == NULL) {
+    return;
+  }
+  thread->SetThreadName(name.c_str());
 }
 
 /*
diff --git a/src/monitor_android.cc b/src/monitor_android.cc
index f80d248..c1949ec 100644
--- a/src/monitor_android.cc
+++ b/src/monitor_android.cc
@@ -69,7 +69,7 @@
   cp = EventLogWriteInt(cp, Monitor::IsSensitiveThread());
 
   // Emit self thread name string, <= 37 bytes.
-  std::string thread_name(self->GetName()->ToModifiedUtf8());
+  std::string thread_name(self->GetThreadName()->ToModifiedUtf8());
   cp = EventLogWriteString(cp, thread_name.c_str(), thread_name.size());
 
   // Emit the wait time, 5 bytes.
diff --git a/src/runtime.cc b/src/runtime.cc
index 114c538..fcbcc08 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -97,7 +97,11 @@
     if (self == NULL) {
       os << "(Aborting thread was not attached to runtime!)\n";
     } else {
-      self->Dump(os, true);
+      self->Dump(os);
+      if (self->IsExceptionPending()) {
+        os << "Pending " << PrettyTypeOf(self->GetException()) << " on thread:\n"
+           << self->GetException()->Dump();
+      }
     }
   }
 };
diff --git a/src/thread.cc b/src/thread.cc
index 189e1b9..7722866 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -173,8 +173,8 @@
 
   {
     CHECK_EQ(self->GetState(), Thread::kRunnable);
-    SirtRef<String> thread_name(self->GetName());
-    SetThreadName(thread_name->ToModifiedUtf8().c_str());
+    SirtRef<String> thread_name(self->GetThreadName());
+    self->SetThreadName(thread_name->ToModifiedUtf8().c_str());
   }
 
   Dbg::PostThreadStart(self);
@@ -315,7 +315,7 @@
   CHECK(!IsExceptionPending()) << " " << PrettyTypeOf(GetException());
   SetVmData(peer_, Thread::Current());
 
-  SirtRef<String> peer_thread_name(GetName());
+  SirtRef<String> peer_thread_name(GetThreadName());
   if (peer_thread_name.get() == NULL) {
     // The Thread constructor should have set the Thread.name to a
     // non-null value. However, because we can run without code
@@ -325,11 +325,11 @@
     gThread_group->SetObject(peer_, Decode<Object*>(env, thread_group.get()));
     gThread_name->SetObject(peer_, Decode<Object*>(env, thread_name.get()));
     gThread_priority->SetInt(peer_, thread_priority);
-    peer_thread_name.reset(GetName());
+    peer_thread_name.reset(GetThreadName());
   }
   // thread_name may have been null, so don't trust this to be non-null
   if (peer_thread_name.get() != NULL) {
-    SetThreadName(GetName()->ToModifiedUtf8().c_str());
+    SetThreadName(peer_thread_name->ToModifiedUtf8().c_str());
   }
 
   // Pre-allocate an OutOfMemoryError for the double-OOME case.
@@ -340,6 +340,12 @@
   pre_allocated_OutOfMemoryError_ = Decode<Throwable*>(env, exception.get());
 }
 
+void Thread::SetThreadName(const char* name) {
+  name_->assign(name);
+  ::art::SetThreadName(name);
+  Dbg::DdmSendThreadNotification(this, CHUNK_TYPE("THNM"));
+}
+
 void Thread::InitStackHwm() {
 #if defined(__APPLE__)
   // Only needed to run code. Try implementing this with pthread_get_stacksize_np and pthread_get_stackaddr_np.
@@ -368,12 +374,21 @@
 #endif
 }
 
-void Thread::Dump(std::ostream& os, bool dump_pending_exception) const {
-  DumpState(os);
-  DumpStack(os);
-  if (dump_pending_exception && IsExceptionPending()) {
-    os << "Pending " << PrettyTypeOf(GetException()) << " on thread:\n";
-    os << GetException()->Dump();
+void Thread::Dump(std::ostream& os, bool full) const {
+  if (full) {
+    DumpState(os);
+    DumpStack(os);
+  } else {
+    os << "Thread[";
+    if (GetThinLockId() != 0) {
+      // If we're in kStarting, we won't have a thin lock id or tid yet.
+      os << GetThinLockId()
+         << ",tid=" << GetTid() << ',';
+    }
+    os << GetState()
+       << ",Thread*=" << this
+       << ",\"" << *name_ << "\""
+       << "]";
   }
 }
 
@@ -402,19 +417,16 @@
   return "";
 }
 
-String* Thread::GetName() const {
+String* Thread::GetThreadName() const {
   return (peer_ != NULL) ? reinterpret_cast<String*>(gThread_name->GetObject(peer_)) : NULL;
 }
 
 void Thread::DumpState(std::ostream& os) const {
-  std::string thread_name("<native thread without managed peer>");
   std::string group_name;
   int priority;
   bool is_daemon = false;
 
   if (peer_ != NULL) {
-    String* thread_name_string = reinterpret_cast<String*>(gThread_name->GetObject(peer_));
-    thread_name = (thread_name_string != NULL) ? thread_name_string->ToModifiedUtf8() : "<null>";
     priority = gThread_priority->GetInt(peer_);
     is_daemon = gThread_daemon->GetBoolean(peer_);
 
@@ -424,13 +436,6 @@
       group_name = (group_name_string != NULL) ? group_name_string->ToModifiedUtf8() : "<null>";
     }
   } else {
-    // This name may be truncated, but it's the best we can do in the absence of a managed peer.
-    std::string stats;
-    if (ReadFileToString(StringPrintf("/proc/self/task/%d/stat", GetTid()).c_str(), &stats)) {
-      size_t start = stats.find('(') + 1;
-      size_t end = stats.find(')') - start;
-      thread_name = stats.substr(start, end);
-    }
     priority = GetNativePriority();
   }
 
@@ -443,7 +448,7 @@
     scheduler_group = "default";
   }
 
-  os << '"' << thread_name << '"';
+  os << '"' << *name_ << '"';
   if (is_daemon) {
     os << " daemon";
   }
@@ -801,7 +806,8 @@
       throwing_OutOfMemoryError_(false),
       pre_allocated_OutOfMemoryError_(NULL),
       debug_invoke_req_(new DebugInvokeReq),
-      trace_stack_(new std::vector<TraceStackFrame>) {
+      trace_stack_(new std::vector<TraceStackFrame>),
+      name_(new std::string("<native thread without managed peer>")) {
   CHECK_EQ((sizeof(Thread) % 4), 0U) << sizeof(Thread);
 }
 
@@ -847,6 +853,7 @@
 
   delete debug_invoke_req_;
   delete trace_stack_;
+  delete name_;
 }
 
 void Thread::HandleUncaughtExceptions() {
@@ -1608,16 +1615,7 @@
 }
 
 std::ostream& operator<<(std::ostream& os, const Thread& thread) {
-  os << "Thread[";
-  if (thread.GetThinLockId() != 0) {
-    // If we're in kStarting, we won't have a thin lock id or tid yet.
-    os << thread.GetThinLockId()
-       << ",tid=" << thread.GetTid() << ',';
-  }
-  os << thread.GetState()
-     << ",Thread*=" << &thread
-     << ",Object*=" << thread.GetPeer()
-     << "]";
+  thread.Dump(os, false);
   return os;
 }
 
diff --git a/src/thread.h b/src/thread.h
index aee784d..856fd5c 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -184,7 +184,9 @@
   static Thread* FromManagedThread(JNIEnv* env, jobject thread);
   static uint32_t LockOwnerFromThreadLock(Object* thread_lock);
 
-  void Dump(std::ostream& os, bool dump_pending_exception = false) const;
+  // When full == true, dumps the detailed thread state and the thread stack (used for SIGQUIT).
+  // When full == false, dumps a one-line summary of thread state (used for operator<<).
+  void Dump(std::ostream& os, bool full = true) const;
 
   State GetState() const {
     return state_;
@@ -231,7 +233,10 @@
   }
 
   // Returns the java.lang.Thread's name, or NULL.
-  String* GetName() const;
+  String* GetThreadName() const;
+
+  // Sets the thread's name.
+  void SetThreadName(const char* name);
 
   Object* GetPeer() const {
     return peer_;
@@ -309,8 +314,6 @@
                                      const DexFile& dex_file,
                                      ClassLinker* class_linker);
 
-  void SetName(const char* name);
-
   static void Startup();
   static void FinishStartup();
   static void Shutdown();
@@ -628,6 +631,9 @@
   // Stored as a pointer since std::vector is not PACKED.
   std::vector<TraceStackFrame>* trace_stack_;
 
+  // A cached copy of the java.lang.Thread's name.
+  std::string* name_;
+
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
diff --git a/src/trace.cc b/src/trace.cc
index c149634..83f50d3 100644
--- a/src/trace.cc
+++ b/src/trace.cc
@@ -402,7 +402,7 @@
 
 static void DumpThread(Thread* t, void* arg) {
   std::ostream* os = reinterpret_cast<std::ostream*>(arg);
-  *os << StringPrintf("%d\t%s\n", t->GetTid(), t->GetName()->ToModifiedUtf8().c_str());
+  *os << StringPrintf("%d\t%s\n", t->GetTid(), t->GetThreadName()->ToModifiedUtf8().c_str());
 }
 
 void Trace::DumpThreadList(std::ostream& os) {