Log view root, input and looper state in bug reports.

Bug: 10948648
Change-Id: I956cce2a0fb516c02f9bbbc021f6238bcb226891
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e29f8ea..193724d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -58,6 +58,7 @@
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.ActionMode;
@@ -4846,36 +4847,19 @@
                 writer.println(mChangingConfigurations);
         writer.print(innerPrefix); writer.print("mCurrentConfig=");
                 writer.println(mCurrentConfig);
+
         if (mLoaderManager != null) {
             writer.print(prefix); writer.print("Loader Manager ");
                     writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
                     writer.println(":");
             mLoaderManager.dump(prefix + "  ", fd, writer, args);
         }
-        mFragments.dump(prefix, fd, writer, args);
-        writer.print(prefix); writer.println("View Hierarchy:");
-        dumpViewHierarchy(prefix + "  ", writer, getWindow().getDecorView());
-    }
 
-    private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
-        writer.print(prefix);
-        if (view == null) {
-            writer.println("null");
-            return;
-        }
-        writer.println(view.toString());
-        if (!(view instanceof ViewGroup)) {
-            return;
-        }
-        ViewGroup grp = (ViewGroup)view;
-        final int N = grp.getChildCount();
-        if (N <= 0) {
-            return;
-        }
-        prefix = prefix + "  ";
-        for (int i=0; i<N; i++) {
-            dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
-        }
+        mFragments.dump(prefix, fd, writer, args);
+
+        getWindow().getDecorView().getViewRootImpl().dump(prefix, fd, writer, args);
+
+        mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
     }
 
     /**
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 78c859e..21e9f6b 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -59,7 +59,6 @@
 
     final MessageQueue mQueue;
     final Thread mThread;
-    volatile boolean mRun;
 
     private Printer mLogging;
 
@@ -187,7 +186,6 @@
 
     private Looper(boolean quitAllowed) {
         mQueue = new MessageQueue(quitAllowed);
-        mRun = true;
         mThread = Thread.currentThread();
     }
 
@@ -300,27 +298,12 @@
     }
 
     public void dump(Printer pw, String prefix) {
-        pw = PrefixPrinter.create(pw, prefix);
-        pw.println(this.toString());
-        pw.println("mRun=" + mRun);
-        pw.println("mThread=" + mThread);
-        pw.println("mQueue=" + ((mQueue != null) ? mQueue : "(null"));
-        if (mQueue != null) {
-            synchronized (mQueue) {
-                long now = SystemClock.uptimeMillis();
-                Message msg = mQueue.mMessages;
-                int n = 0;
-                while (msg != null) {
-                    pw.println("  Message " + n + ": " + msg.toString(now));
-                    n++;
-                    msg = msg.next;
-                }
-                pw.println("(Total messages: " + n + ")");
-            }
-        }
+        pw.println(prefix + toString());
+        mQueue.dump(pw, prefix + "  ");
     }
 
     public String toString() {
-        return "Looper{" + Integer.toHexString(System.identityHashCode(this)) + "}";
+        return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
+                + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
     }
 }
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 0abc149..51203a4 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -428,36 +428,48 @@
     public Message() {
     }
 
+    @Override
     public String toString() {
         return toString(SystemClock.uptimeMillis());
     }
 
     String toString(long now) {
-        StringBuilder   b = new StringBuilder();
-        
-        b.append("{ what=");
-        b.append(what);
+        StringBuilder b = new StringBuilder();
+        b.append("{ when=");
+        TimeUtils.formatDuration(when - now, b);
 
-        b.append(" when=");
-        TimeUtils.formatDuration(when-now, b);
+        if (target != null) {
+            if (callback != null) {
+                b.append(" callback=");
+                b.append(callback.getClass().getName());
+            } else {
+                b.append(" what=");
+                b.append(what);
+            }
 
-        if (arg1 != 0) {
-            b.append(" arg1=");
+            if (arg1 != 0) {
+                b.append(" arg1=");
+                b.append(arg1);
+            }
+
+            if (arg2 != 0) {
+                b.append(" arg2=");
+                b.append(arg2);
+            }
+
+            if (obj != null) {
+                b.append(" obj=");
+                b.append(obj);
+            }
+
+            b.append(" target=");
+            b.append(target.getClass().getName());
+        } else {
+            b.append(" barrier=");
             b.append(arg1);
         }
 
-        if (arg2 != 0) {
-            b.append(" arg2=");
-            b.append(arg2);
-        }
-
-        if (obj != null) {
-            b.append(" obj=");
-            b.append(obj);
-        }
-
         b.append(" }");
-        
         return b.toString();
     }
 
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index d1b8213..799de5c 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -18,6 +18,7 @@
 
 import android.util.AndroidRuntimeException;
 import android.util.Log;
+import android.util.Printer;
 
 import java.util.ArrayList;
 
@@ -252,6 +253,7 @@
         synchronized (this) {
             final int token = mNextBarrierToken++;
             final Message msg = Message.obtain();
+            msg.when = when;
             msg.arg1 = token;
 
             Message prev = null;
@@ -393,12 +395,16 @@
 
     boolean isIdling() {
         synchronized (this) {
-            // If the loop is quitting then it must not be idling.
-            // We can assume mPtr != 0 when mQuitting is false.
-            return !mQuitting && nativeIsIdling(mPtr);
+            return isIdlingLocked();
         }
     }
 
+    private boolean isIdlingLocked() {
+        // If the loop is quitting then it must not be idling.
+        // We can assume mPtr != 0 when mQuitting is false.
+        return !mQuitting && nativeIsIdling(mPtr);
+     }
+
     void removeMessages(Handler h, int what, Object object) {
         if (h == null) {
             return;
@@ -537,4 +543,17 @@
             }
         }
     }
+
+    void dump(Printer pw, String prefix) {
+        synchronized (this) {
+            long now = SystemClock.uptimeMillis();
+            int n = 0;
+            for (Message msg = mMessages; msg != null; msg = msg.next) {
+                pw.println(prefix + "Message " + n + ": " + msg.toString(now));
+                n++;
+            }
+            pw.println(prefix + "(Total messages: " + n + ", idling=" + isIdlingLocked()
+                    + ", quitting=" + mQuitting + ")");
+        }
+    }
 }
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index f28e4b5..f1523ae 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -23,6 +23,9 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.util.Log;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
 
 /**
  * Coordinates the timing of animations, input and drawing.
@@ -256,6 +259,15 @@
         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
     }
 
+    void dump(String prefix, PrintWriter writer) {
+        String innerPrefix = prefix + "  ";
+        writer.print(prefix); writer.println("Choreographer:");
+        writer.print(innerPrefix); writer.print("mFrameScheduled=");
+                writer.println(mFrameScheduled);
+        writer.print(innerPrefix); writer.print("mLastFrameTime=");
+                writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
+    }
+
     /**
      * Posts a callback to run on the next frame.
      * <p>
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9461068..ab93084 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -77,8 +77,10 @@
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.RootViewSurfaceTaker;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -3458,6 +3460,12 @@
                 finishInputEvent(q);
             }
         }
+
+        void dump(String prefix, PrintWriter writer) {
+            if (mNext != null) {
+                mNext.dump(prefix, writer);
+            }
+        }
     }
 
     /**
@@ -3595,6 +3603,16 @@
             mQueueLength -= 1;
             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
         }
+
+        @Override
+        void dump(String prefix, PrintWriter writer) {
+            writer.print(prefix);
+            writer.print(getClass().getName());
+            writer.print(": mQueueLength=");
+            writer.println(mQueueLength);
+
+            super.dump(prefix, writer);
+        }
     }
 
     /**
@@ -5201,6 +5219,53 @@
         mView.debug();
     }
 
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        String innerPrefix = prefix + "  ";
+        writer.print(prefix); writer.println("ViewRoot:");
+        writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
+                writer.print(" mRemoved="); writer.println(mRemoved);
+        writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
+                writer.println(mConsumeBatchedInputScheduled);
+        writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
+                writer.println(mPendingInputEventCount);
+        writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
+                writer.println(mProcessInputEventsScheduled);
+        writer.print(innerPrefix); writer.print("mTraversalScheduled=");
+                writer.print(mTraversalScheduled);
+        if (mTraversalScheduled) {
+            writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
+        } else {
+            writer.println();
+        }
+        mFirstInputStage.dump(innerPrefix, writer);
+
+        mChoreographer.dump(prefix, writer);
+
+        writer.print(prefix); writer.println("View Hierarchy:");
+        dumpViewHierarchy(innerPrefix, writer, mView);
+    }
+
+    private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
+        writer.print(prefix);
+        if (view == null) {
+            writer.println("null");
+            return;
+        }
+        writer.println(view.toString());
+        if (!(view instanceof ViewGroup)) {
+            return;
+        }
+        ViewGroup grp = (ViewGroup)view;
+        final int N = grp.getChildCount();
+        if (N <= 0) {
+            return;
+        }
+        prefix = prefix + "  ";
+        for (int i=0; i<N; i++) {
+            dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
+        }
+    }
+
     public void dumpGfxInfo(int[] info) {
         info[0] = info[1] = 0;
         if (mView != null) {