NBLog: add retroactive dump and standard printing format

The retroactive dump outputs historical snapshots of data that
correspond to important NBLog Events at the time they were read.

The standard printing format added is as follows: for each line, the
first column is the NBLog Event as a string, and the following columns
correspond to each field of the struct, or the type, that the NBLog
Event maps to. All columns are separated by commas.

Other changes:
Added option to Reader::getSnapshot() for flushing the buffer. This
makes it possible to always read the full buffer contents when doing a
dump of the raw log contents.

Test: dumpsys media.log with -r and --retro options
Bug: 68148948
Change-Id: I4bbbf6e2f9a3a86fae976986ac35a7eef79520de
diff --git a/media/libnblog/Merger.cpp b/media/libnblog/Merger.cpp
index 5e6f79a..30f6fe3 100644
--- a/media/libnblog/Merger.cpp
+++ b/media/libnblog/Merger.cpp
@@ -167,12 +167,24 @@
             const double timeMs = it.payload<double>();
             data.warmupHist.add(timeMs);
         } break;
-        case EVENT_UNDERRUN:
+        case EVENT_UNDERRUN: {
+            const int64_t ts = it.payload<int64_t>();
             data.underruns++;
-            break;
-        case EVENT_OVERRUN:
+            data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+            // TODO have a data structure to automatically handle resizing
+            if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+                data.snapshots.pop_back();
+            }
+        } break;
+        case EVENT_OVERRUN: {
+            const int64_t ts = it.payload<int64_t>();
             data.overruns++;
-            break;
+            data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+            // TODO have a data structure to automatically handle resizing
+            if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+                data.snapshots.pop_back();
+            }
+        } break;
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
             ALOGW("warning: unexpected event %d", it->type);
@@ -216,7 +228,7 @@
 {
     // TODO: add a mutex around media.log dump
     // Options for dumpsys
-    bool pa = false, json = false, plots = false;
+    bool pa = false, json = false, plots = false, retro = false;
     for (const auto &arg : args) {
         if (arg == String16("--pa")) {
             pa = true;
@@ -224,6 +236,8 @@
             json = true;
         } else if (arg == String16("--plots")) {
             plots = true;
+        } else if (arg == String16("--retro")) {
+            retro = true;
         }
     }
     if (pa) {
@@ -235,6 +249,9 @@
     if (plots) {
         ReportPerformance::dumpPlots(fd, mThreadPerformanceData);
     }
+    if (retro) {
+        ReportPerformance::dumpRetro(fd, mThreadPerformanceData);
+    }
 }
 
 void MergeReader::handleAuthor(const AbstractEntry &entry, String8 *body)