Connectivity metrics: log DnsEvents in-band

This patch changes how DnsEvents are logged in IpConnectivityMetrics.
The following changes are made:
 - DnsEventBatch are not logged after 100 queries on the same network
    - this allows to merge DnsEvent and DnsEventBatch into one class
 - DnsEventBatch are not logged after a network disconnect
    - this allows to remove the NetworkCallback
 - DnsEvent are now logged similarly to ConnectStats when statistics are
   flushed, in a direct call from IpConnectivityMetrics into
   NetdEventListenerService, in a direct call from IpConnectivityMetrics
   into NetdEventListenerService.
    - this allows to remove the Parcelable implementation of DnsEvent
 - transports information is added to DnsEvent.

Test: - simplified NetdEventListenerServiceTest covering dns logging
      - updated IpConnectivityEventBuilderTest
      - updated IpConnectivityMetricsTest
      - $ runtest frameworks-net passes
      - manually verified $ adb shell dumpsys connmetrics list proto
Bug: 34901696
Change-Id: I4fcd0ad7a7b85d587647f471a90c1e53a18fc95a
Merged-In: Ia4b33fd4212741152662a2adbb0533bd1b4902ee

(cherry picked from commit 0699cf98042a64e41ee076c464eb115a6579be08)
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index d819b96..66ca4b6 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -57,7 +57,7 @@
                 aType(IpReachabilityEvent.class),
                 anInt(IpReachabilityEvent.NUD_FAILED));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -70,13 +70,13 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
         verifySerialization(want, ev);
 
         ev.netId = 123;
         ev.transports = 3; // transports have priority for inferrence of link layer
         ev.ifname = "wlan0";
-        want = joinLines(
+        want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -89,12 +89,12 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
         verifySerialization(want, ev);
 
         ev.transports = 1;
         ev.ifname = null;
-        want = joinLines(
+        want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -107,12 +107,12 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
         verifySerialization(want, ev);
 
         ev.transports = 0;
         ev.ifname = "not_inferred";
-        want = joinLines(
+        want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"not_inferred\"",
@@ -125,11 +125,11 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
         verifySerialization(want, ev);
 
         ev.ifname = "bt-pan";
-        want = joinLines(
+        want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -142,11 +142,11 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
         verifySerialization(want, ev);
 
         ev.ifname = "rmnet_ipa0";
-        want = joinLines(
+        want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -159,11 +159,11 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
         verifySerialization(want, ev);
 
         ev.ifname = "wlan0";
-        want = joinLines(
+        want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -176,7 +176,7 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
         verifySerialization(want, ev);
     }
 
@@ -190,7 +190,7 @@
                 aBool(true),
                 aBool(false));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -211,7 +211,7 @@
                 "    transport_types: 3",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -223,7 +223,7 @@
                 aString("SomeState"),
                 anInt(192));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -237,7 +237,7 @@
                 "    state_transition: \"SomeState\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -248,7 +248,7 @@
                 aType(DhcpErrorEvent.class),
                 anInt(DhcpErrorEvent.L4_NOT_UDP));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -262,59 +262,7 @@
                 "    error_code: 50397184",
                 "  >",
                 ">",
-                "version: 2");
-
-        verifySerialization(want, ev);
-    }
-
-    @SmallTest
-    public void testDnsEventSerialization() {
-        ConnectivityMetricsEvent ev = describeIpEvent(
-                aType(DnsEvent.class),
-                anInt(101),
-                aByteArray(b(1), b(1), b(2), b(1), b(1), b(1), b(2), b(2)),
-                aByteArray(b(0), b(0), b(22), b(3), b(1), b(0), b(200), b(178)),
-                anIntArray(3456, 267, 1230, 45, 2111, 450, 638, 1300));
-
-        String want = joinLines(
-                "dropped_events: 0",
-                "events <",
-                "  if_name: \"\"",
-                "  link_layer: 0",
-                "  network_id: 0",
-                "  time_ms: 1",
-                "  transports: 0",
-                "  dns_lookup_batch <",
-                "    event_types: 1",
-                "    event_types: 1",
-                "    event_types: 2",
-                "    event_types: 1",
-                "    event_types: 1",
-                "    event_types: 1",
-                "    event_types: 2",
-                "    event_types: 2",
-                "    latencies_ms: 3456",
-                "    latencies_ms: 267",
-                "    latencies_ms: 1230",
-                "    latencies_ms: 45",
-                "    latencies_ms: 2111",
-                "    latencies_ms: 450",
-                "    latencies_ms: 638",
-                "    latencies_ms: 1300",
-                "    network_id <",
-                "      network_id: 101",
-                "    >",
-                "    return_codes: 0",
-                "    return_codes: 0",
-                "    return_codes: 22",
-                "    return_codes: 3",
-                "    return_codes: 1",
-                "    return_codes: 0",
-                "    return_codes: 200",
-                "    return_codes: 178",
-                "  >",
-                ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -326,7 +274,7 @@
                 anInt(IpManagerEvent.PROVISIONING_OK),
                 aLong(5678));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -340,7 +288,7 @@
                 "    latency_ms: 5678",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -351,7 +299,7 @@
                 aType(IpReachabilityEvent.class),
                 anInt(IpReachabilityEvent.NUD_FAILED));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -364,7 +312,7 @@
                 "    if_name: \"\"",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -377,7 +325,7 @@
                 anInt(5),
                 aLong(20410));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -393,7 +341,7 @@
                 "    >",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -406,7 +354,7 @@
                 anInt(ValidationProbeEvent.PROBE_HTTP),
                 anInt(204));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -420,7 +368,7 @@
                 "    probe_type: 1",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -436,7 +384,7 @@
                 anInt(2048),
                 anInt(3));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -454,7 +402,7 @@
                 "    program_length: 2048",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -474,7 +422,7 @@
                 anInt(3),
                 anInt(2048));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -495,7 +443,7 @@
                 "    zero_lifetime_ras: 1",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -511,7 +459,7 @@
                 aLong(1000),
                 aLong(-1));
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -528,7 +476,7 @@
                 "    router_lifetime: 2000",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, ev);
     }
@@ -543,13 +491,4 @@
             fail(e.toString());
         }
     }
-
-    static String joinLines(String ... elems) {
-        StringBuilder b = new StringBuilder();
-        for (String s : elems) {
-            b.append(s);
-            b.append("\n");
-        }
-        return b.toString();
-    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 68786d0..fd81c90 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -138,6 +138,7 @@
     }
 
     @SmallTest
+    // TODO: add NetdEventListenerService coverage too
     public void testEndToEndLogging() {
         // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
         IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
@@ -177,7 +178,7 @@
             logger.log(ev);
         }
 
-        String want = joinLines(
+        String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
@@ -279,7 +280,7 @@
                 "    router_lifetime: 2000",
                 "  >",
                 ">",
-                "version: 2");
+                "version: 2\n");
 
         verifySerialization(want, getdump("flush"));
     }
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 0ab4406..05c9767 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -16,161 +16,161 @@
 
 package com.android.server.connectivity;
 
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.net.metrics.ConnectStats;
-import android.net.metrics.DnsEvent;
-import android.net.metrics.INetdEventListener;
-import android.net.metrics.IpConnectivityLog;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.system.OsConstants;
-import android.test.suitebuilder.annotation.SmallTest;
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-import java.util.OptionalInt;
-import java.util.stream.IntStream;
-import junit.framework.TestCase;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
+import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
+import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
-public class NetdEventListenerServiceTest extends TestCase {
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.support.test.runner.AndroidJUnit4;
+import android.system.OsConstants;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.DNSLookupBatch;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    // TODO: read from NetdEventListenerService after this constant is read from system property
-    static final int BATCH_SIZE = 100;
-    static final int EVENT_TYPE = INetdEventListener.EVENT_GETADDRINFO;
-    // TODO: read from INetdEventListener
-    static final int RETURN_CODE = 1;
-
-    static final byte[] EVENT_TYPES  = new byte[BATCH_SIZE];
-    static final byte[] RETURN_CODES = new byte[BATCH_SIZE];
-    static final int[] LATENCIES     = new int[BATCH_SIZE];
-    static {
-        for (int i = 0; i < BATCH_SIZE; i++) {
-            EVENT_TYPES[i] = EVENT_TYPE;
-            RETURN_CODES[i] = RETURN_CODE;
-            LATENCIES[i] = i;
-        }
-    }
-
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetdEventListenerServiceTest {
     private static final String EXAMPLE_IPV4 = "192.0.2.1";
     private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
 
     NetdEventListenerService mNetdEventListenerService;
+    ConnectivityManager mCm;
 
-    @Mock ConnectivityManager mCm;
-    @Mock IpConnectivityLog mLog;
-    ArgumentCaptor<NetworkCallback> mCallbackCaptor;
-    ArgumentCaptor<DnsEvent> mDnsEvCaptor;
-
+    @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
-        mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
-        mNetdEventListenerService = new NetdEventListenerService(mCm, mLog);
-
-        verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
+        mCm = mock(ConnectivityManager.class);
+        mNetdEventListenerService = new NetdEventListenerService(mCm);
     }
 
-    @SmallTest
-    public void testOneDnsBatch() throws Exception {
-        log(105, LATENCIES);
-        log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
+    @Test
+    public void testDnsLogging() throws Exception {
+        NetworkCapabilities ncWifi = new NetworkCapabilities();
+        NetworkCapabilities ncCell = new NetworkCapabilities();
+        ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+        ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
 
-        verifyLoggedDnsEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
+        when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
+        when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
 
-        log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
+        dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
+        dnsEvent(100, EVENT_GETADDRINFO, 0, 267);
+        dnsEvent(100, EVENT_GETHOSTBYNAME, 22, 1230);
+        dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
+        dnsEvent(100, EVENT_GETADDRINFO, 1, 2111);
+        dnsEvent(100, EVENT_GETADDRINFO, 0, 450);
+        dnsEvent(100, EVENT_GETHOSTBYNAME, 200, 638);
+        dnsEvent(100, EVENT_GETHOSTBYNAME, 178, 1300);
+        dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
+        dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
+        dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
+        dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 56);
+        dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
+        dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
 
-        mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
-        verifyLoggedDnsEvents(
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
+        String got = flushStatistics();
+        String want = String.join("\n",
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 0",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  connect_statistics <",
+                "    connect_blocking_count: 0",
+                "    connect_count: 0",
+                "    ipv6_addr_count: 0",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 4",
+                "  network_id: 100",
+                "  time_ms: 0",
+                "  transports: 2",
+                "  dns_lookup_batch <",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 2",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 2",
+                "    event_types: 2",
+                "    latencies_ms: 3456",
+                "    latencies_ms: 267",
+                "    latencies_ms: 1230",
+                "    latencies_ms: 45",
+                "    latencies_ms: 2111",
+                "    latencies_ms: 450",
+                "    latencies_ms: 638",
+                "    latencies_ms: 1300",
+                "    return_codes: 0",
+                "    return_codes: 0",
+                "    return_codes: 22",
+                "    return_codes: 3",
+                "    return_codes: 1",
+                "    return_codes: 0",
+                "    return_codes: 200",
+                "    return_codes: 178",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 2",
+                "  network_id: 101",
+                "  time_ms: 0",
+                "  transports: 1",
+                "  dns_lookup_batch <",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 2",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    latencies_ms: 56",
+                "    latencies_ms: 78",
+                "    latencies_ms: 14",
+                "    latencies_ms: 56",
+                "    latencies_ms: 78",
+                "    latencies_ms: 14",
+                "    return_codes: 0",
+                "    return_codes: 0",
+                "    return_codes: 0",
+                "    return_codes: 0",
+                "    return_codes: 0",
+                "    return_codes: 0",
+                "  >",
+                ">",
+                "version: 2\n");
+        assertEquals(want, got);
     }
 
-    @SmallTest
-    public void testSeveralDmsBatches() throws Exception {
-        log(105, LATENCIES);
-        log(106, LATENCIES);
-        log(105, LATENCIES);
-        log(107, LATENCIES);
-
-        verifyLoggedDnsEvents(
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
-    }
-
-    @SmallTest
-    public void testDnsBatchAndNetworkLost() throws Exception {
-        byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
-        byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
-        int[] latencies = Arrays.copyOf(LATENCIES, 20);
-
-        log(105, LATENCIES);
-        log(105, latencies);
-        mCallbackCaptor.getValue().onLost(new Network(105));
-        log(105, LATENCIES);
-
-        verifyLoggedDnsEvents(
-            new DnsEvent(105, eventTypes, returnCodes, latencies),
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
-    }
-
-    @SmallTest
-    public void testConcurrentDnsBatchesAndDumps() throws Exception {
-        final long stop = System.currentTimeMillis() + 100;
-        final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
-        new Thread() {
-            public void run() {
-                while (System.currentTimeMillis() < stop) {
-                    mNetdEventListenerService.dump(pw);
-                }
-            }
-        }.start();
-
-        logDnsAsync(105, LATENCIES);
-        logDnsAsync(106, LATENCIES);
-        logDnsAsync(107, LATENCIES);
-
-        verifyLoggedDnsEvents(500,
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
-    }
-
-    @SmallTest
-    public void testConcurrentDnsBatchesAndNetworkLoss() throws Exception {
-        logDnsAsync(105, LATENCIES);
-        Thread.sleep(10L);
-        // call onLost() asynchronously to logDnsAsync's onDnsEvent() calls.
-        mCallbackCaptor.getValue().onLost(new Network(105));
-
-        // do not verify batch with unpredictable length
-        verify(mLog, timeout(500).times(1)).log(any(Parcelable.class));
-    }
-
-    @SmallTest
+    @Test
     public void testConnectLogging() throws Exception {
         final int OK = 0;
         Thread[] logActions = {
@@ -268,44 +268,18 @@
         });
     }
 
-    void log(int netId, int[] latencies) {
-        try {
-            for (int l : latencies) {
-                mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null,
-                        0, 0);
+    void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+        mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
+    }
+
+    Thread dumpAction(long durationMs) throws Exception {
+        final long stop = System.currentTimeMillis() + durationMs;
+        final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
+        return new Thread(() -> {
+            while (System.currentTimeMillis() < stop) {
+                mNetdEventListenerService.dump(pw);
             }
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    void logDnsAsync(int netId, int[] latencies) {
-        new Thread(() -> log(netId, latencies)).start();
-    }
-
-    void verifyLoggedDnsEvents(DnsEvent... expected) {
-        verifyLoggedDnsEvents(0, expected);
-    }
-
-    void verifyLoggedDnsEvents(int wait, DnsEvent... expectedEvents) {
-        verify(mLog, timeout(wait).times(expectedEvents.length)).log(mDnsEvCaptor.capture());
-        for (DnsEvent got : mDnsEvCaptor.getAllValues()) {
-            OptionalInt index = IntStream.range(0, expectedEvents.length)
-                    .filter(i -> dnsEventsEqual(expectedEvents[i], got))
-                    .findFirst();
-            // Don't match same expected event more than once.
-            index.ifPresent(i -> expectedEvents[i] = null);
-            assertTrue(index.isPresent());
-        }
-    }
-
-    /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
-    static boolean dnsEventsEqual(DnsEvent expected, DnsEvent got) {
-        return (expected == got) || ((expected != null) && (got != null)
-                && (expected.netId == got.netId)
-                && Arrays.equals(expected.eventTypes, got.eventTypes)
-                && Arrays.equals(expected.returnCodes, got.returnCodes)
-                && Arrays.equals(expected.latenciesMs, got.latenciesMs));
+        });
     }
 
     static void verifyConnectEvent(String expected, IpConnectivityEvent got) {
@@ -318,4 +292,17 @@
             fail(e.toString());
         }
     }
+
+    // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
+    String flushStatistics() throws Exception {
+        IpConnectivityMetrics metricsService =
+                new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000);
+        metricsService.mNetdListener = mNetdEventListenerService;
+
+        StringWriter buffer = new StringWriter();
+        PrintWriter writer = new PrintWriter(buffer);
+        metricsService.impl.dump(null, writer, new String[]{"flush"});
+        byte[] bytes = Base64.decode(buffer.toString(), Base64.DEFAULT);
+        return IpConnectivityLog.parseFrom(bytes).toString();
+    }
 }