DefaultNetworkEvent metrics: rehaul

This patch changes instrumentation of default networks and default
network events:
- stop logging events for default network transitions,
  but instead consistently log one event per continuous segment
  when one given network was the default, including logging an
  event for when there is no default network.
- keep a separate rolling buffer of DefaultNetworkEvent for
  dumpsys and bug reports.

These changes allow to simplify post aggregation of default network
event metrics by removing any need to do time series processing.
Instead, metrics and counters can be implemented withouth any ambiguity
by following the recipe:

% of x = sum(duration | x = true) / sum (all durations)

where x can be various conditions such as:
- the default network was validated
- the default network was WiFi
- the default network was IPv6
- there was no default network
- ...

Most importantly, this new logging scheme allows to measure much more
reliably:
- the % of the time that a device had Internet, in the sense that the
default network was validated.
- the time transitions between default networks, keyed by previous and
new transports/link layer, which allows to derive wakelock durations
and wakelock power costs from default network switches.

This patch also simplifies the dumpsys interface of the connmetrics
service and reduces the commands to three:
- "flush" for metrics upload.
- "proto" for printing buffered event in text proto format.
- "list" for listing all events and statistics.

Bug: 34901696
Bug: 65700460
Test: runtest frameworks-net
Change-Id: I0521f1681a60cca07ac3bfd5741d64ce44de4cdd
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 6723601..83194d9 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -82,9 +82,8 @@
     public void testWakeupEventLogging() throws Exception {
         final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
 
-        // Assert no events
-        String[] events1 = listNetdEvent();
-        assertEquals(new String[]{""}, events1);
+        // Baseline without any event
+        String[] baseline = listNetdEvent();
 
         long now = System.currentTimeMillis();
         String prefix = "iface:wlan0";
@@ -93,7 +92,7 @@
             mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
         }
 
-        String[] events2 = listNetdEvent();
+        String[] events2 = remove(listNetdEvent(), baseline);
         int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
         assertEquals(expectedLength2, events2.length);
         assertContains(events2[0], "WakeupStats");
@@ -111,7 +110,7 @@
             mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts);
         }
 
-        String[] events3 = listNetdEvent();
+        String[] events3 = remove(listNetdEvent(), baseline);
         int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
         assertEquals(expectedLength3, events3.length);
         assertContains(events2[0], "WakeupStats");
@@ -126,7 +125,7 @@
         uid = 45678;
         mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
 
-        String[] events4 = listNetdEvent();
+        String[] events4 = remove(listNetdEvent(), baseline);
         String lastEvent = events4[events4.length - 1];
         assertContains(lastEvent, "WakeupEvent");
         assertContains(lastEvent, "wlan0");
@@ -423,7 +422,7 @@
         final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
         new Thread(() -> {
             while (System.currentTimeMillis() < stop) {
-                mNetdEventListenerService.dump(pw);
+                mNetdEventListenerService.list(pw);
             }
         }).start();
     }
@@ -461,4 +460,16 @@
     static void assertContains(String got, String want) {
         assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
     }
+
+    static <T> T[] remove(T[] array, T[] filtered) {
+        List<T> c = Arrays.asList(filtered);
+        int next = 0;
+        for (int i = 0; i < array.length; i++) {
+            if (c.contains(array[i])) {
+                continue;
+            }
+            array[next++] = array[i];
+        }
+        return Arrays.copyOf(array, next);
+    }
 }