Export BatteryStats events to Atrace.

Similar to http://ag/19779936, this reports event details to Perfetto.
All events are recorded as instants. Ideally, the start/finish would
correspond to a single async segment, but that requires storing unique
cookie ids for every event (if not managed carefully, can grow in
memory). Instead, we can generate synthetic segments in Perfetto itself.

Bug: 245749764
Test: atest FrameworksServicesTests:BatteryStatsTests
Change-Id: If24c0d52c76a9cba6692ae5de20b80cb759b9a4d
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index f097bf7..5523344 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -247,6 +247,13 @@
                 SystemProperties.set("debug.tracing." + name, Integer.toString(value));
             }
         }
+
+        /**
+         * Records an instant event (one with no duration).
+         */
+        public void traceInstantEvent(@NonNull String track, @NonNull String name) {
+            Trace.instantForTrack(Trace.TRACE_TAG_POWER, track, name);
+        }
     }
 
     private TraceDelegate mTracer;
@@ -1165,6 +1172,25 @@
     }
 
     /**
+     * Writes event details into Atrace.
+     */
+    private void recordTraceEvents(int code, HistoryTag tag) {
+        if (code == HistoryItem.EVENT_NONE) return;
+        if (!mTracer.tracingEnabled()) return;
+
+        final int idx = code & HistoryItem.EVENT_TYPE_MASK;
+        final String prefix = (code & HistoryItem.EVENT_FLAG_START) != 0 ? "+" :
+                  (code & HistoryItem.EVENT_FLAG_FINISH) != 0 ? "-" : "";
+
+        final String[] names = BatteryStats.HISTORY_EVENT_NAMES;
+        if (idx < 0 || idx >= names.length) return;
+
+        final String track = "battery_stats." + names[idx];
+        final String name = prefix + names[idx] + "=" + tag.uid + ":\"" + tag.string + "\"";
+        mTracer.traceInstantEvent(track, name);
+    }
+
+    /**
      * Writes changes to a HistoryItem state bitmap to Atrace.
      */
     private void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) {
@@ -1229,6 +1255,7 @@
                     + Integer.toHexString(lastDiffStates2));
         }
 
+        recordTraceEvents(cur.eventCode, cur.eventTag);
         recordTraceCounters(mHistoryLastWritten.states,
                 cur.states & mActiveHistoryStates, BatteryStats.HISTORY_STATE_DESCRIPTIONS);
         recordTraceCounters(mHistoryLastWritten.states2,
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index d5b923a..4100ff1 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -148,6 +148,25 @@
     }
 
     @Test
+    public void testAtraceInstantEvent() {
+        mHistory.forceRecordAllHistory();
+
+        InOrder inOrder = Mockito.inOrder(mTracer);
+        Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+        mHistory.recordEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(),
+                HistoryItem.EVENT_WAKEUP_AP, "", 1234);
+        mHistory.recordEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(),
+                HistoryItem.EVENT_JOB_START, "jobname", 2468);
+        mHistory.recordEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(),
+                HistoryItem.EVENT_JOB_FINISH, "jobname", 2468);
+
+        inOrder.verify(mTracer).traceInstantEvent("battery_stats.wakeupap", "wakeupap=1234:\"\"");
+        inOrder.verify(mTracer).traceInstantEvent("battery_stats.job", "+job=2468:\"jobname\"");
+        inOrder.verify(mTracer).traceInstantEvent("battery_stats.job", "-job=2468:\"jobname\"");
+    }
+
+    @Test
     public void testConstruct() {
         createActiveFile(mHistory);
         verifyFileNumbers(mHistory, Arrays.asList(0));