Improve "waiting on"/"waiting to lock" SIGQUIT dump info.

In particular, when we're waiting on a Class, say which class:

  I(16573)   - waiting on <0xf5ed54f8> (java.lang.Class<java.lang.ref.ReferenceQueue>)

versus:

  I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)

Bug: http://code.google.com/p/android/issues/detail?id=17349
Change-Id: I844d02c008b1499adb02995ff3da25ba8cad0e0a
diff --git a/vm/Misc.cpp b/vm/Misc.cpp
index 627c4e2..3b1179e 100644
--- a/vm/Misc.cpp
+++ b/vm/Misc.cpp
@@ -715,3 +715,58 @@
 
     return NULL;
 }
+
+// From RE2.
+static void StringAppendV(std::string* dst, const char* format, va_list ap) {
+    // First try with a small fixed size buffer
+    char space[1024];
+
+    // It's possible for methods that use a va_list to invalidate
+    // the data in it upon use.  The fix is to make a copy
+    // of the structure before using it and use that copy instead.
+    va_list backup_ap;
+    va_copy(backup_ap, ap);
+    int result = vsnprintf(space, sizeof(space), format, backup_ap);
+    va_end(backup_ap);
+
+    if ((result >= 0) && ((size_t) result < sizeof(space))) {
+        // It fit
+        dst->append(space, result);
+        return;
+    }
+
+    // Repeatedly increase buffer size until it fits
+    int length = sizeof(space);
+    while (true) {
+        if (result < 0) {
+            // Older behavior: just try doubling the buffer size
+            length *= 2;
+        } else {
+            // We need exactly "result+1" characters
+            length = result+1;
+        }
+        char* buf = new char[length];
+
+        // Restore the va_list before we use it again
+        va_copy(backup_ap, ap);
+        result = vsnprintf(buf, length, format, backup_ap);
+        va_end(backup_ap);
+
+        if ((result >= 0) && (result < length)) {
+            // It fit
+            dst->append(buf, result);
+            delete[] buf;
+            return;
+        }
+        delete[] buf;
+    }
+}
+
+std::string dvmStringPrintf(const char* fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    std::string result;
+    StringAppendV(&result, fmt, ap);
+    va_end(ap);
+    return result;
+}
diff --git a/vm/Misc.h b/vm/Misc.h
index aabddfb..017548d 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -22,6 +22,7 @@
 
 #include <string>
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -303,4 +304,9 @@
  */
 const char* dvmPathToAbsolutePortion(const char* path);
 
+/**
+ * Returns a string corresponding to printf-like formatting of the arguments.
+ */
+std::string dvmStringPrintf(const char* fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
+
 #endif /*_DALVIK_MISC*/
diff --git a/vm/Profile.cpp b/vm/Profile.cpp
index f7240ce..f3f73a8 100644
--- a/vm/Profile.cpp
+++ b/vm/Profile.cpp
@@ -249,16 +249,11 @@
 /*
  * Dump the thread list to the specified file.
  */
-static void dumpThreadList(FILE* fp)
-{
-    Thread* thread;
-
+static void dumpThreadList(FILE* fp) {
     dvmLockThreadList(NULL);
-    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
-        char* name = dvmGetThreadName(thread);
-
-        fprintf(fp, "%d\t%s\n", thread->threadId, name);
-        free(name);
+    for (Thread* thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        std::string threadName(dvmGetThreadName(thread));
+        fprintf(fp, "%d\t%s\n", thread->threadId, threadName.c_str());
     }
     dvmUnlockThreadList();
 }
diff --git a/vm/Sync.cpp b/vm/Sync.cpp
index 8257f80..09b12e4 100644
--- a/vm/Sync.cpp
+++ b/vm/Sync.cpp
@@ -271,7 +271,7 @@
     u4 relativePc;
     char eventBuffer[174];
     const char *fileName;
-    char procName[33], *selfName;
+    char procName[33];
     char *cp;
     size_t len;
     int fd;
@@ -299,9 +299,8 @@
     cp = logWriteInt(cp, isSensitive);
 
     /* Emit self thread name string, <= 37 bytes. */
-    selfName = dvmGetThreadName(self);
-    cp = logWriteString(cp, selfName, strlen(selfName));
-    free(selfName);
+    std::string selfName = dvmGetThreadName(self);
+    cp = logWriteString(cp, selfName.c_str(), selfName.size());
 
     /* Emit the wait time, 5 bytes. */
     cp = logWriteInt(cp, waitMs);
diff --git a/vm/Thread.cpp b/vm/Thread.cpp
index 4947316..bef4bc6 100644
--- a/vm/Thread.cpp
+++ b/vm/Thread.cpp
@@ -554,10 +554,9 @@
                 threadId, target->threadId);
         }
 
-        char* threadName = dvmGetThreadName(target);
+        std::string threadName(dvmGetThreadName(target));
         LOGV("threadid=%d: suspending daemon id=%d name='%s'",
-            threadId, target->threadId, threadName);
-        free(threadName);
+                threadId, target->threadId, threadName.c_str());
 
         /* mark as suspended */
         lockThreadSuspendCount();
@@ -1455,9 +1454,8 @@
 {
     Thread* self = (Thread*) arg;
 
-    char *threadName = dvmGetThreadName(self);
-    setThreadName(threadName);
-    free(threadName);
+    std::string threadName(dvmGetThreadName(self));
+    setThreadName(threadName.c_str());
 
     /*
      * Finish initializing the Thread struct.
@@ -3121,13 +3119,11 @@
     }
 
     if (setpriority(PRIO_PROCESS, pid, newNice) != 0) {
-        char* str = dvmGetThreadName(thread);
+        std::string threadName(dvmGetThreadName(thread));
         LOGI("setPriority(%d) '%s' to prio=%d(n=%d) failed: %s",
-            pid, str, newPriority, newNice, strerror(errno));
-        free(str);
+                pid, threadName.c_str(), newPriority, newNice, strerror(errno));
     } else {
-        LOGV("setPriority(%d) to prio=%d(n=%d)",
-            pid, newPriority, newNice);
+        LOGV("setPriority(%d) to prio=%d(n=%d)", pid, newPriority, newNice);
     }
 }
 
@@ -3414,24 +3410,13 @@
     free(groupName);
 }
 
-/*
- * Get the name of a thread.
- *
- * For correctness, the caller should hold the thread list lock to ensure
- * that the thread doesn't go away mid-call.
- *
- * Returns a newly-allocated string, or NULL if the Thread doesn't have a name.
- */
-char* dvmGetThreadName(Thread* thread)
-{
-    StringObject* nameObj;
-
+std::string dvmGetThreadName(Thread* thread) {
     if (thread->threadObj == NULL) {
         LOGW("threadObj is NULL, name not available");
-        return strdup("-unknown-");
+        return "-unknown-";
     }
 
-    nameObj = (StringObject*)
+    StringObject* nameObj = (StringObject*)
         dvmGetFieldObject(thread->threadObj, gDvm.offJavaLangThread_name);
     return dvmCreateCstrFromString(nameObj);
 }
diff --git a/vm/Thread.h b/vm/Thread.h
index a4c64ec..b4c866e 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -532,9 +532,12 @@
 void dvmThreadSleep(u8 msec, u4 nsec);
 
 /*
- * Get the name of a thread.  (For safety, hold the thread list lock.)
+ * Get the name of a thread.
+ *
+ * For correctness, the caller should hold the thread list lock to ensure
+ * that the thread doesn't go away mid-call.
  */
-char* dvmGetThreadName(Thread* thread);
+std::string dvmGetThreadName(Thread* thread);
 
 /*
  * Convert ThreadStatus to a string.
diff --git a/vm/interp/Stack.cpp b/vm/interp/Stack.cpp
index bbce741..3c0d9da 100644
--- a/vm/interp/Stack.cpp
+++ b/vm/interp/Stack.cpp
@@ -1156,6 +1156,28 @@
     return true;
 }
 
+static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
+        Thread* thread)
+{
+    std::string msg(dvmStringPrintf("  - waiting %s <%p> ", detail, obj));
+
+    if (obj->clazz != gDvm.classJavaLangClass) {
+        // I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)
+        msg += "(a " + dvmHumanReadableDescriptor(obj->clazz->descriptor) + ")";
+    } else {
+        // I(16573)   - waiting on <0xf5ed54f8> (java.lang.Class<java.lang.ref.ReferenceQueue>)
+        ClassObject* clazz = reinterpret_cast<ClassObject*>(obj);
+        msg += "(java.lang.Class<" + dvmHumanReadableDescriptor(clazz->descriptor) + ">)";
+    }
+
+    if (thread != NULL) {
+        std::string threadName(dvmGetThreadName(thread));
+        msg += dvmStringPrintf(" held by tid=%d (%s)", thread->threadId, threadName.c_str());
+    }
+
+    dvmPrintDebugMessage(target, "%s\n", msg.c_str());
+}
+
 /*
  * Dump stack frames, starting from the specified frame and moving down.
  *
@@ -1234,35 +1256,16 @@
                     Object* obj = dvmGetMonitorObject(mon);
                     if (obj != NULL) {
                         Thread* joinThread = NULL;
-                        std::string className(dvmHumanReadableDescriptor(obj->clazz->descriptor));
-                        if (className == "java.lang.VMThread") {
+                        if (obj->clazz == gDvm.classJavaLangVMThread) {
                             joinThread = dvmGetThreadFromThreadObject(obj);
                         }
-                        if (joinThread == NULL) {
-                            dvmPrintDebugMessage(target,
-                                    "  - waiting on <%p> (a %s)\n", obj, className.c_str());
-                        } else {
-                            dvmPrintDebugMessage(target,
-                                    "  - waiting on <%p> (a %s) tid=%d\n", obj, className.c_str(),
-                                    joinThread->threadId);
-                        }
+                        printWaitMessage(target, "on", obj, joinThread);
                     }
                 } else if (thread->status == THREAD_MONITOR) {
                     Object* obj;
                     Thread* owner;
                     if (extractMonitorEnterObject(thread, &obj, &owner)) {
-                        std::string className(dvmHumanReadableDescriptor(obj->clazz->descriptor));
-                        if (owner != NULL) {
-                            char* threadName = dvmGetThreadName(owner);
-                            dvmPrintDebugMessage(target,
-                                    "  - waiting to lock <%p> (a %s) held by threadid=%d (%s)\n",
-                                    obj, className.c_str(), owner->threadId, threadName);
-                            free(threadName);
-                        } else {
-                            dvmPrintDebugMessage(target,
-                                    "  - waiting to lock <%p> (a %s) held by ???\n",
-                                    obj, className.c_str());
-                        }
+                        printWaitMessage(target, "to lock", obj, owner);
                     }
                 }
             }