Include Bundle values with ConnectivityDiagnostics calls.

ConnectivityDiagnostics allows PersistableBundles to be passed from
NetworkMonitor to ConnectivityDiagnosticsCallbacks that are registered
with the System in ConnectivityService. This change populates the
bundles passed from NetworkMonitor with values relating to
ConnectivityDiagnosticsManager#ConnectivityReport and
ConnectivityDiagnosticsManager#DataStallReport using keys defined in
those classes. The keys used for the bundles are defined in
ConstantsShim.

Bug: 147249364
Test: compiles
Test: atest NetworkStackTests
Change-Id: Id007ab38a20c6a107c9528e3e861dafa191797c3
(cherry picked from commit 091d5890ee5d3edd66a9e2add19b1ec97688c364)
diff --git a/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java b/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java
index fe2691e..29d8506 100644
--- a/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java
+++ b/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java
@@ -20,7 +20,14 @@
  * Utility class for defining and importing constants from the Android platform.
  */
 public class ConstantsShim {
-    // Constants defined in android.net.ConnectivityDiagnosticsManager.DataStallReport.
+    // Constants defined in android.net.ConnectivityDiagnosticsManager.
     public static final int DETECTION_METHOD_DNS_EVENTS = 1;
     public static final int DETECTION_METHOD_TCP_METRICS = 2;
+    public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+    public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttemped";
+    public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
+    public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+    public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
+            "tcpMetricsCollectionPeriodMillis";
+    public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
 }
diff --git a/apishim/30/com/android/networkstack/apishim/ConstantsShim.java b/apishim/30/com/android/networkstack/apishim/ConstantsShim.java
index 77e7be2..f040f76 100644
--- a/apishim/30/com/android/networkstack/apishim/ConstantsShim.java
+++ b/apishim/30/com/android/networkstack/apishim/ConstantsShim.java
@@ -16,6 +16,7 @@
 
 package com.android.networkstack.apishim;
 
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
 import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
 
 /**
@@ -26,4 +27,15 @@
             DataStallReport.DETECTION_METHOD_DNS_EVENTS;
     public static final int DETECTION_METHOD_TCP_METRICS =
             DataStallReport.DETECTION_METHOD_TCP_METRICS;
+    public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS =
+            DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
+    public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
+            ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
+    public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK =
+            ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
+    public static final String KEY_NETWORK_VALIDATION_RESULT =
+            ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT;
+    public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
+            DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
+    public static final String KEY_TCP_PACKET_FAIL_RATE = DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
 }
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index 3a3f95c..6fc146d 100644
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -70,6 +70,12 @@
 
 import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_DNS_EVENTS;
 import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_TCP_METRICS;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_DNS_CONSECUTIVE_TIMEOUTS;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_NETWORK_VALIDATION_RESULT;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_TCP_PACKET_FAIL_RATE;
 import static com.android.networkstack.util.DnsUtils.PRIVATE_DNS_PROBE_HOST_SUFFIX;
 import static com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG;
 
@@ -584,9 +590,15 @@
         return NetworkMonitorUtils.isPrivateDnsValidationRequired(mNetworkCapabilities);
     }
 
-    private void notifyNetworkTested(int result, @Nullable String redirectUrl) {
+    private void notifyNetworkTested(
+            int result, @Nullable String redirectUrl, PersistableBundle extras) {
         try {
-            mCallback.notifyNetworkTested(result, redirectUrl);
+            if (mCallbackVersion <= 5) {
+                mCallback.notifyNetworkTested(result, redirectUrl);
+            } else {
+                mCallback.notifyNetworkTestedWithExtras(
+                        result, redirectUrl, SystemClock.elapsedRealtime(), extras);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Error sending network test result", e);
         }
@@ -2288,8 +2300,10 @@
             } else if (tst.isDataStallSuspected()) {
                 result = true;
 
-                // TODO(b/147249364): add metrics to PersistableBundle once keys are defined
-                notifyDataStallSuspected(DETECTION_METHOD_TCP_METRICS, PersistableBundle.EMPTY);
+                final PersistableBundle extras = new PersistableBundle();
+                extras.putInt(KEY_TCP_PACKET_FAIL_RATE, tst.getLatestPacketFailPercentage());
+                extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, getTcpPollingInterval());
+                notifyDataStallSuspected(DETECTION_METHOD_TCP_METRICS, extras);
             }
             if (DBG || VDBG_STALL) {
                 msg.add("tcp packets received=" + tst.getLatestReceivedCount())
@@ -2308,8 +2322,10 @@
                 result = true;
                 logNetworkEvent(NetworkEvent.NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND);
 
-                // TODO(b/147249364): add metrics to PersistableBundle once keys are defined
-                notifyDataStallSuspected(DETECTION_METHOD_DNS_EVENTS, PersistableBundle.EMPTY);
+                final PersistableBundle extras = new PersistableBundle();
+                extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS,
+                        mDnsStallDetector.getConsecutiveTimeoutCount());
+                notifyDataStallSuspected(DETECTION_METHOD_DNS_EVENTS, extras);
             }
             if (DBG || VDBG_STALL) {
                 msg.add("consecutive dns timeout count=" + dsd.getConsecutiveTimeoutCount());
@@ -2387,7 +2403,12 @@
         protected void reportEvaluationResult(int result, @Nullable String redirectUrl) {
             mEvaluationResult = result;
             mRedirectUrl = redirectUrl;
-            notifyNetworkTested(getNetworkTestResult(), mRedirectUrl);
+            final PersistableBundle extras = new PersistableBundle();
+
+            extras.putInt(KEY_NETWORK_VALIDATION_RESULT, result);
+            extras.putInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, mProbeResults);
+            extras.putInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK, mProbeCompleted);
+            notifyNetworkTested(getNetworkTestResult(), mRedirectUrl, extras);
         }
 
         protected int getNetworkTestResult() {
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index 4383347..9c0936e 100644
--- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -40,6 +40,12 @@
 
 import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_DNS_EVENTS;
 import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_TCP_METRICS;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_DNS_CONSECUTIVE_TIMEOUTS;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_NETWORK_VALIDATION_RESULT;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_TCP_PACKET_FAIL_RATE;
 import static com.android.networkstack.util.DnsUtils.PRIVATE_DNS_PROBE_HOST_SUFFIX;
 
 import static junit.framework.Assert.assertEquals;
@@ -51,6 +57,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
@@ -121,6 +128,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -456,10 +464,13 @@
     }
 
     private void resetCallbacks() {
+        resetCallbacks(6);
+    }
+
+    private void resetCallbacks(int interfaceVersion) {
         reset(mCallbacks);
-        // TODO: make this a parameterized test.
         try {
-            when(mCallbacks.getInterfaceVersion()).thenReturn(3);
+            when(mCallbacks.getInterfaceVersion()).thenReturn(interfaceVersion);
         } catch (RemoteException e) {
             // Can't happen as mCallbacks is a mock
             fail("Error mocking getInterfaceVersion" + e);
@@ -781,7 +792,7 @@
         makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertTrue(wrappedMonitor.isDataStall());
         verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
-                any(PersistableBundle.class));
+                argThat(getDataStallDnsBundleMatcher()));
     }
 
     @Test
@@ -794,7 +805,7 @@
         makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertTrue(wrappedMonitor.isDataStall());
         verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
-                any(PersistableBundle.class));
+                argThat(getDataStallDnsBundleMatcher()));
     }
 
     @Test
@@ -811,7 +822,7 @@
         makeDnsTimeoutEvent(wrappedMonitor, 3);
         assertTrue(wrappedMonitor.isDataStall());
         verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
-                any(PersistableBundle.class));
+                argThat(getDataStallDnsBundleMatcher()));
 
         // Set the value to larger than the default dns log size.
         setConsecutiveDnsTimeoutThreshold(51);
@@ -823,7 +834,7 @@
         makeDnsTimeoutEvent(wrappedMonitor, 1);
         assertTrue(wrappedMonitor.isDataStall());
         verify(mCallbacks, times(2)).notifyDataStallSuspected(anyLong(),
-                eq(DETECTION_METHOD_DNS_EVENTS), any(PersistableBundle.class));
+                eq(DETECTION_METHOD_DNS_EVENTS), argThat(getDataStallDnsBundleMatcher()));
     }
 
     @Test
@@ -849,7 +860,7 @@
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
         assertTrue(wrappedMonitor.isDataStall());
         verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
-                any(PersistableBundle.class));
+                argThat(getDataStallDnsBundleMatcher()));
 
         // Test dns events happened before valid dns time threshold.
         setValidDataStallDnsTimeThreshold(0);
@@ -884,7 +895,7 @@
         HandlerUtilsKt.waitForIdle(wrappedMonitor.getHandler(), HANDLER_TIMEOUT_MS);
         assertTrue(wrappedMonitor.isDataStall());
         verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_TCP_METRICS),
-                any(PersistableBundle.class));
+                argThat(getDataStallTcpBundleMatcher()));
     }
 
     @Test
@@ -950,8 +961,9 @@
         resetCallbacks();
         nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP
-                        | NETWORK_VALIDATION_RESULT_VALID), any());
+                .notifyNetworkTestedWithExtras(eq(NETWORK_VALIDATION_PROBE_DNS
+                        | NETWORK_VALIDATION_PROBE_HTTP | NETWORK_VALIDATION_RESULT_VALID), any(),
+                        anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
         assertEquals(0, mRegisteredReceivers.size());
     }
 
@@ -967,8 +979,9 @@
                 new InetAddress[0]));
         wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
-                        eq(null));
+                .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
+                        | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
+                        argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
 
@@ -978,8 +991,9 @@
         wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns4.google",
                 new InetAddress[0]));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
-                        eq(null));
+                .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
+                        | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
+                        argThat(getNotifyNetworkTestedBundleMatcher()));
         // NetworkMonitor will check if the probes has changed or not, if the probes has not
         // changed, the callback won't be fired.
         verify(mCallbacks, never()).notifyProbeStatusChanged(
@@ -991,8 +1005,9 @@
         mFakeDns.setAnswer("dns.google", new String[]{"192.0.2.3"}, TYPE_A);
         wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
-                        eq(null));
+                .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
+                        | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
+                        argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, never()).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
     }
@@ -1006,8 +1021,9 @@
         WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
         wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
         wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null));
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
+                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null),
+                anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(NETWORK_VALIDATION_PROBE_DNS
                 | NETWORK_VALIDATION_PROBE_HTTPS));
@@ -1020,8 +1036,9 @@
         HandlerUtilsKt.waitForIdle(wnm.getHandler(), HANDLER_TIMEOUT_MS);
         assertEquals(wnm.getEvaluationState().getProbeCompletedResult(), 0);
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
-                        eq(null));
+                .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
+                        | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
+                        argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
     }
@@ -1035,8 +1052,9 @@
         WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
         wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
         wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS)).notifyNetworkTested(
-                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null));
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS)).notifyNetworkTestedWithExtras(
+                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null),
+                anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(NETWORK_VALIDATION_PROBE_DNS
                 | NETWORK_VALIDATION_PROBE_HTTPS));
@@ -1047,8 +1065,9 @@
 
         wnm.forceReevaluation(Process.myUid());
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
-                        eq(null));
+                .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
+                        | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
+                        argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
 
@@ -1060,8 +1079,9 @@
         // Strict mode hostname resolve fail. Expect only notification for evaluation fail. No probe
         // notification.
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS))
-                .notifyNetworkTested(eq(NETWORK_VALIDATION_PROBE_DNS
-                        | NETWORK_VALIDATION_PROBE_HTTPS), eq(null));
+                .notifyNetworkTestedWithExtras(eq(NETWORK_VALIDATION_PROBE_DNS
+                        | NETWORK_VALIDATION_PROBE_HTTPS), eq(null), anyLong(),
+                        argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(NETWORK_VALIDATION_PROBE_DNS
                 | NETWORK_VALIDATION_PROBE_HTTPS));
@@ -1072,8 +1092,9 @@
         mFakeDns.setNonBypassPrivateDnsWorking(false);
         wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google",
                 new InetAddress[0]));
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS)).notifyNetworkTested(
-                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null));
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS)).notifyNetworkTestedWithExtras(
+                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null),
+                anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
         // NetworkMonitor will check if the probes has changed or not, if the probes has not
         // changed, the callback won't be fired.
         verify(mCallbacks, never()).notifyProbeStatusChanged(
@@ -1085,8 +1106,9 @@
         mFakeDns.setNonBypassPrivateDnsWorking(true);
         wnm.forceReevaluation(Process.myUid());
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(
-                        eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null));
+                .notifyNetworkTestedWithExtras(
+                        eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null),
+                        anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
                 eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
     }
@@ -1154,8 +1176,9 @@
         resetCallbacks();
         nm.setAcceptPartialConnectivity();
         // Expect to update evaluation result notifications to CS.
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(VALIDATION_RESULT_PARTIAL | NETWORK_VALIDATION_RESULT_VALID), eq(null));
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
+                eq(VALIDATION_RESULT_PARTIAL | NETWORK_VALIDATION_RESULT_VALID), eq(null),
+                anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
     }
 
     @Test
@@ -1230,8 +1253,25 @@
         final ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
         // Expect to send HTTP, HTTPs, FALLBACK and evaluation results.
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS))
-            .notifyNetworkTested(eq(NETWORK_VALIDATION_PROBE_DNS |
-                    NETWORK_VALIDATION_PROBE_FALLBACK | NETWORK_VALIDATION_RESULT_PARTIAL), any());
+                .notifyNetworkTestedWithExtras(eq(NETWORK_VALIDATION_PROBE_DNS
+                        | NETWORK_VALIDATION_PROBE_FALLBACK | NETWORK_VALIDATION_RESULT_PARTIAL),
+                        any(), anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+    }
+
+    @Test
+    public void testNotifyNetwork_NotifyNetworkTestedOldInterfaceVersion() throws Exception {
+        // Use old interface version so notifyNetworkTested is used over
+        // notifyNetworkTestedWithExtras
+        resetCallbacks(5);
+
+        // Trigger Network validation
+        setStatus(mHttpsConnection, 204);
+        setStatus(mHttpConnection, 204);
+        final NetworkMonitor nm = makeMonitor(METERED_CAPABILITIES);
+        nm.notifyNetworkConnected(TEST_LINK_PROPERTIES, METERED_CAPABILITIES);
+
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS))
+                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID), any());
     }
 
     @Test
@@ -1250,7 +1290,8 @@
         resetCallbacks();
 
         nm.reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, CaptivePortalProbeResult.SUCCESS);
-        // Verify result should be appended and notifyNetworkTested callback is triggered once.
+        // Verify result should be appended and notifyNetworkTestedWithExtras callback is triggered
+        // once.
         assertEquals(nm.getEvaluationState().getNetworkTestResult(),
                 VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_HTTP);
 
@@ -1266,21 +1307,23 @@
 
         nm.getEvaluationState().reportEvaluationResult(NETWORK_VALIDATION_RESULT_PARTIAL,
                 null /* redirectUrl */);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
                 eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
-                | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null));
+                | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null), anyLong(),
+                argThat(getNotifyNetworkTestedBundleMatcher()));
 
         nm.getEvaluationState().reportEvaluationResult(
                 NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL,
                 null /* redirectUrl */);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null));
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
+                eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null),
+                anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
 
         nm.getEvaluationState().reportEvaluationResult(VALIDATION_RESULT_INVALID,
                 TEST_REDIRECT_URL);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
                 eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
-                eq(TEST_REDIRECT_URL));
+                eq(TEST_REDIRECT_URL), anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
     }
 
     private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
@@ -1392,7 +1435,9 @@
         monitor.notifyNetworkConnected(TEST_LINK_PROPERTIES, nc);
         try {
             verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS))
-                    .notifyNetworkTested(eq(testResult), mNetworkTestedRedirectUrlCaptor.capture());
+                    .notifyNetworkTestedWithExtras(eq(testResult),
+                            mNetworkTestedRedirectUrlCaptor.capture(), anyLong(),
+                            argThat(getNotifyNetworkTestedBundleMatcher()));
         } catch (RemoteException e) {
             fail("Unexpected exception: " + e);
         }
@@ -1424,5 +1469,21 @@
         }
     }
 
+    private ArgumentMatcher<PersistableBundle> getNotifyNetworkTestedBundleMatcher() {
+        return bundle ->
+                bundle.containsKey(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK)
+                && bundle.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK)
+                && bundle.containsKey(KEY_NETWORK_VALIDATION_RESULT);
+    }
+
+    private ArgumentMatcher<PersistableBundle> getDataStallDnsBundleMatcher() {
+        return bundle -> bundle.containsKey(KEY_DNS_CONSECUTIVE_TIMEOUTS);
+    }
+
+    private ArgumentMatcher<PersistableBundle> getDataStallTcpBundleMatcher() {
+        return bundle ->
+                bundle.containsKey(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS)
+                && bundle.containsKey(KEY_TCP_PACKET_FAIL_RATE);
+    }
 }