Merge "LooperStats - add debug entries to output for data validation"
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 2b661c2..cf2a297 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -50,6 +50,7 @@
     private int mSamplingInterval;
     private CachedDeviceState.Readonly mDeviceState;
     private long mStartTime = System.currentTimeMillis();
+    private boolean mAddDebugEntries = false;
 
     public LooperStats(int samplingInterval, int entriesSizeCap) {
         this.mSamplingInterval = samplingInterval;
@@ -60,6 +61,10 @@
         mDeviceState = deviceState;
     }
 
+    public void setAddDebugEntries(boolean addDebugEntries) {
+        mAddDebugEntries = addDebugEntries;
+    }
+
     @Override
     public Object messageDispatchStarting() {
         if (deviceStateAllowsCollection() && shouldCollectDetailedData()) {
@@ -142,9 +147,22 @@
         // Add the overflow and collision entries only if they have any data.
         maybeAddSpecialEntry(exportedEntries, mOverflowEntry);
         maybeAddSpecialEntry(exportedEntries, mHashCollisionEntry);
+        // Debug entries added to help validate the data.
+        if (mAddDebugEntries) {
+            exportedEntries.add(createDebugEntry("start_time_millis", mStartTime));
+            exportedEntries.add(createDebugEntry("end_time_millis", System.currentTimeMillis()));
+        }
         return exportedEntries;
     }
 
+    private ExportedEntry createDebugEntry(String variableName, long value) {
+        final Entry entry = new Entry("__DEBUG_" + variableName);
+        entry.messageCount = 1;
+        entry.recordedMessageCount = 1;
+        entry.maxDelayMillis = value;
+        return new ExportedEntry(entry);
+    }
+
     /** Returns a timestamp indicating when the statistics were last reset. */
     public long getStartTimeMillis() {
         return mStartTime;
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index f637b7c..31dde5c 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -105,7 +105,6 @@
         assertThat(entry.recordedDelayMessageCount).isEqualTo(1);
         assertThat(entry.delayMillis).isEqualTo(30);
         assertThat(entry.maxDelayMillis).isEqualTo(30);
-
     }
 
     @Test
@@ -429,6 +428,28 @@
         assertThat(entries).hasSize(0);
     }
 
+    @Test
+    public void testAddsDebugEntries() {
+        TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+        looperStats.setAddDebugEntries(true);
+
+        Message message = mHandlerFirst.obtainMessage(1000);
+        message.when = looperStats.getSystemUptimeMillis();
+        Object token = looperStats.messageDispatchStarting();
+        looperStats.messageDispatched(token, message);
+
+        List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+        assertThat(entries).hasSize(3);
+        LooperStats.ExportedEntry debugEntry1 = entries.get(1);
+        assertThat(debugEntry1.handlerClassName).isEqualTo("");
+        assertThat(debugEntry1.messageName).isEqualTo("__DEBUG_start_time_millis");
+        assertThat(debugEntry1.maxDelayMillis).isEqualTo(looperStats.getStartTimeMillis());
+        LooperStats.ExportedEntry debugEntry2 = entries.get(2);
+        assertThat(debugEntry2.handlerClassName).isEqualTo("");
+        assertThat(debugEntry2.messageName).isEqualTo("__DEBUG_end_time_millis");
+        assertThat(debugEntry2.maxDelayMillis).isAtLeast(looperStats.getStartTimeMillis());
+    }
+
     private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
         try {
             r.run();
@@ -450,6 +471,7 @@
             super(samplingInterval, sizeCap);
             this.mSamplingInterval = samplingInterval;
             this.setDeviceState(mDeviceState.getReadonlyClient());
+            this.setAddDebugEntries(false);
         }
 
         void tickRealtime(long micros) {
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 2dee3a0..c563ad2 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -141,6 +141,7 @@
         if (mEnabled != enabled) {
             mEnabled = enabled;
             mStats.reset();
+            mStats.setAddDebugEntries(enabled);
             Looper.setObserver(enabled ? mStats : null);
         }
     }