OSDN Git Service

Remove Parcelable interface from DefaultNetworkEvent
authorHugo Benichi <hugobenichi@google.com>
Thu, 19 Oct 2017 05:58:15 +0000 (14:58 +0900)
committerHugo Benichi <hugobenichi@google.com>
Wed, 25 Oct 2017 03:40:13 +0000 (12:40 +0900)
This patch takes advantage of the direct DefaultNetworkMetrics interface
between ConnectivityService and IpConnectivityMetrics and removes the
Parcelable interface from DefaultNetworkEvent.

IpConnectivityMetrics, IpConnectivityEventBuilder and associated tests
are updated as necessary.

Bug: 34901696
Test: runtest frameworks-net
Change-Id: I59b6e04fc126051320d08a422cfbd4d27042123e

core/java/android/net/metrics/DefaultNetworkEvent.java
services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java

index 28cf42f..eb61c15 100644 (file)
 
 package android.net.metrics;
 
+import static android.net.ConnectivityManager.NETID_UNSET;
+
 import android.net.NetworkCapabilities;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * An event recorded by ConnectivityService when there is a change in the default network.
  * {@hide}
  */
-public final class DefaultNetworkEvent implements Parcelable {
+public class DefaultNetworkEvent {
+
     // The ID of the network that has become the new default or NETID_UNSET if none.
-    public final int netId;
+    public int netId = NETID_UNSET;
     // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
     // defined in NetworkCapabilities.java.
-    public final int[] transportTypes;
+    public int[] transportTypes = new int[0];
     // The ID of the network that was the default before or NETID_UNSET if none.
-    public final int prevNetId;
+    public int prevNetId = NETID_UNSET;
     // Whether the previous network had IPv4/IPv6 connectivity.
-    public final boolean prevIPv4;
-    public final boolean prevIPv6;
-
-    public DefaultNetworkEvent(int netId, int[] transportTypes,
-                int prevNetId, boolean prevIPv4, boolean prevIPv6) {
-        this.netId = netId;
-        this.transportTypes = transportTypes;
-        this.prevNetId = prevNetId;
-        this.prevIPv4 = prevIPv4;
-        this.prevIPv6 = prevIPv6;
-    }
-
-    private DefaultNetworkEvent(Parcel in) {
-        this.netId = in.readInt();
-        this.transportTypes = in.createIntArray();
-        this.prevNetId = in.readInt();
-        this.prevIPv4 = (in.readByte() > 0);
-        this.prevIPv6 = (in.readByte() > 0);
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(netId);
-        out.writeIntArray(transportTypes);
-        out.writeInt(prevNetId);
-        out.writeByte(prevIPv4 ? (byte) 1 : (byte) 0);
-        out.writeByte(prevIPv6 ? (byte) 1 : (byte) 0);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
+    public boolean prevIPv4;
+    public boolean prevIPv6;
 
     @Override
     public String toString() {
-      String prevNetwork = String.valueOf(prevNetId);
-      String newNetwork = String.valueOf(netId);
-      if (prevNetId != 0) {
-          prevNetwork += ":" + ipSupport();
-      }
-      if (netId != 0) {
-          newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes);
-      }
-      return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork);
+        String prevNetwork = String.valueOf(prevNetId);
+        String newNetwork = String.valueOf(netId);
+        if (prevNetId != 0) {
+            prevNetwork += ":" + ipSupport();
+        }
+        if (netId != 0) {
+            newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes);
+        }
+        return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork);
     }
 
     private String ipSupport() {
         if (prevIPv4 && prevIPv6) {
-            return "DUAL";
+            return "IPv4v6";
         }
         if (prevIPv6) {
             return "IPv6";
@@ -92,15 +62,4 @@ public final class DefaultNetworkEvent implements Parcelable {
         }
         return "NONE";
     }
-
-    public static final Parcelable.Creator<DefaultNetworkEvent> CREATOR
-        = new Parcelable.Creator<DefaultNetworkEvent>() {
-        public DefaultNetworkEvent createFromParcel(Parcel in) {
-            return new DefaultNetworkEvent(in);
-        }
-
-        public DefaultNetworkEvent[] newArray(int size) {
-            return new DefaultNetworkEvent[size];
-        }
-    };
 }
index c7c00bb..8981db1 100644 (file)
 
 package com.android.server.connectivity;
 
-import static android.net.ConnectivityManager.NETID_UNSET;
-
 import android.net.LinkProperties;
 import android.net.metrics.DefaultNetworkEvent;
 import android.net.metrics.IpConnectivityLog;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Tracks events related to the default network for the purpose of default network metrics.
  * {@hide}
  */
 public class DefaultNetworkMetrics {
 
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+    private static final int ROLLING_LOG_SIZE = 64;
+
+    // Event buffer used for metrics upload. The buffer is cleared when events are collected.
+    @GuardedBy("this")
+    private final List<DefaultNetworkEvent> mEvents = new ArrayList<>();
+
+    public synchronized void listEvents(PrintWriter pw) {
+        long localTimeMs = System.currentTimeMillis();
+        for (DefaultNetworkEvent ev : mEvents) {
+            pw.println(ev);
+        }
+    }
+
+    public synchronized void listEventsAsProto(PrintWriter pw) {
+        for (DefaultNetworkEvent ev : mEvents) {
+            pw.print(IpConnectivityEventBuilder.toProto(ev));
+        }
+    }
 
-    public void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
-        int newNetid = NETID_UNSET;
-        int prevNetid = NETID_UNSET;
-        int[] transports = new int[0];
-        boolean hadIPv4 = false;
-        boolean hadIPv6 = false;
+    public synchronized void flushEvents(List<IpConnectivityEvent> out) {
+        for (DefaultNetworkEvent ev : mEvents) {
+            out.add(IpConnectivityEventBuilder.toProto(ev));
+        }
+        mEvents.clear();
+    }
 
+    public synchronized void logDefaultNetworkEvent(
+            NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
+        DefaultNetworkEvent ev = new DefaultNetworkEvent();
         if (newNai != null) {
-            newNetid = newNai.network.netId;
-            transports = newNai.networkCapabilities.getTransportTypes();
+            ev.netId = newNai.network().netId;
+            ev.transportTypes = newNai.networkCapabilities.getTransportTypes();
         }
         if (prevNai != null) {
-            prevNetid = prevNai.network.netId;
+            ev.prevNetId = prevNai.network().netId;
             final LinkProperties lp = prevNai.linkProperties;
-            hadIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
-            hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+            ev.prevIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
+            ev.prevIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
         }
 
-        mMetricsLog.log(new DefaultNetworkEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6));
+        mEvents.add(ev);
     }
 }
index 67e7216..3d71ecb 100644 (file)
@@ -132,6 +132,18 @@ final public class IpConnectivityEventBuilder {
         return out;
     }
 
+    public static IpConnectivityEvent toProto(DefaultNetworkEvent in) {
+        IpConnectivityLogClass.DefaultNetworkEvent ev =
+                new IpConnectivityLogClass.DefaultNetworkEvent();
+        ev.networkId = netIdOf(in.netId);
+        ev.previousNetworkId = netIdOf(in.prevNetId);
+        ev.transportTypes = in.transportTypes;
+        ev.previousNetworkIpSupport = ipSupportOf(in);
+        final IpConnectivityEvent out = buildEvent(in.netId, 0, null);
+        out.setDefaultNetworkEvent(ev);
+        return out;
+    }
+
     private static IpConnectivityEvent buildEvent(int netId, long transports, String ifname) {
         final IpConnectivityEvent ev = new IpConnectivityEvent();
         ev.networkId = netId;
@@ -164,11 +176,6 @@ final public class IpConnectivityEventBuilder {
             return true;
         }
 
-        if (in instanceof DefaultNetworkEvent) {
-            setDefaultNetworkEvent(out, (DefaultNetworkEvent) in);
-            return true;
-        }
-
         if (in instanceof NetworkEvent) {
             setNetworkEvent(out, (NetworkEvent) in);
             return true;
@@ -225,16 +232,6 @@ final public class IpConnectivityEventBuilder {
         out.setIpReachabilityEvent(ipReachabilityEvent);
     }
 
-    private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) {
-        IpConnectivityLogClass.DefaultNetworkEvent defaultNetworkEvent =
-                new IpConnectivityLogClass.DefaultNetworkEvent();
-        defaultNetworkEvent.networkId = netIdOf(in.netId);
-        defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
-        defaultNetworkEvent.transportTypes = in.transportTypes;
-        defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
-        out.setDefaultNetworkEvent(defaultNetworkEvent);
-    }
-
     private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
         IpConnectivityLogClass.NetworkEvent networkEvent =
                 new IpConnectivityLogClass.NetworkEvent();
index 25e541f..24217e6 100644 (file)
@@ -196,6 +196,8 @@ final public class IpConnectivityMetrics extends SystemService {
 
         final List<IpConnectivityEvent> protoEvents = IpConnectivityEventBuilder.toProto(events);
 
+        mDefaultNetworkMetrics.flushEvents(protoEvents);
+
         if (mNetdListener != null) {
             mNetdListener.flushStatistics(protoEvents);
         }
@@ -236,6 +238,7 @@ final public class IpConnectivityMetrics extends SystemService {
             if (mNetdListener != null) {
                 mNetdListener.listAsProtos(pw);
             }
+            mDefaultNetworkMetrics.listEventsAsProto(pw);
             return;
         }
 
@@ -245,6 +248,7 @@ final public class IpConnectivityMetrics extends SystemService {
         if (mNetdListener != null) {
             mNetdListener.list(pw);
         }
+        mDefaultNetworkMetrics.listEvents(pw);
     }
 
     /**
@@ -262,6 +266,7 @@ final public class IpConnectivityMetrics extends SystemService {
         if (mNetdListener != null) {
             mNetdListener.list(pw);
         }
+        mDefaultNetworkMetrics.listEvents(pw);
     }
 
     private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
index 2624176..ad6ebf9 100644 (file)
@@ -198,21 +198,20 @@ public class IpConnectivityEventBuilderTest {
 
     @Test
     public void testDefaultNetworkEventSerialization() {
-        ConnectivityMetricsEvent ev = describeIpEvent(
-                aType(DefaultNetworkEvent.class),
-                anInt(102),
-                anIntArray(1, 2, 3),
-                anInt(101),
-                aBool(true),
-                aBool(false));
+        DefaultNetworkEvent ev = new DefaultNetworkEvent();
+        ev.netId = 102;
+        ev.prevNetId = 101;
+        ev.transportTypes = new int[]{1, 2, 3};
+        ev.prevIPv4 = true;
+        ev.prevIPv6 = true;
 
         String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
                 "  link_layer: 0",
-                "  network_id: 0",
-                "  time_ms: 1",
+                "  network_id: 102",
+                "  time_ms: 0",
                 "  transports: 0",
                 "  default_network_event <",
                 "    default_network_duration_ms: 0",
@@ -226,7 +225,7 @@ public class IpConnectivityEventBuilderTest {
                 "    previous_network_id <",
                 "      network_id: 101",
                 "    >",
-                "    previous_network_ip_support: 1",
+                "    previous_network_ip_support: 3",
                 "    transport_types: 1",
                 "    transport_types: 2",
                 "    transport_types: 3",
@@ -234,7 +233,7 @@ public class IpConnectivityEventBuilderTest {
                 ">",
                 "version: 2\n");
 
-        verifySerialization(want, ev);
+        verifySerialization(want, IpConnectivityEventBuilder.toProto(ev));
     }
 
     @Test
index a395c48..6c1decc 100644 (file)
@@ -18,6 +18,7 @@ package com.android.server.connectivity;
 
 import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
 import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -30,6 +31,10 @@ import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityMetricsEvent;
 import android.net.IIpConnectivityMetrics;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.metrics.ApfProgramEvent;
@@ -41,18 +46,22 @@ import android.net.metrics.IpManagerEvent;
 import android.net.metrics.IpReachabilityEvent;
 import android.net.metrics.RaEvent;
 import android.net.metrics.ValidationProbeEvent;
-import android.system.OsConstants;
 import android.os.Parcelable;
 import android.support.test.runner.AndroidJUnit4;
+import android.system.OsConstants;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Base64;
+
+import com.android.internal.util.BitUtils;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
+
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -162,6 +171,144 @@ public class IpConnectivityMetricsTest {
     }
 
     @Test
+    public void testDefaultNetworkEvents() throws Exception {
+        final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
+        final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+
+        NetworkAgentInfo[][] defaultNetworks = {
+            // nothing -> cell
+            {null, makeNai(100, 10, false, true, cell)},
+            // cell -> wifi
+            {makeNai(100, 50, true, true, cell), makeNai(101, 20, true, false, wifi)},
+            // wifi -> nothing
+            {makeNai(101, 60, true, false, wifi), null},
+            // nothing -> cell
+            {null, makeNai(102, 10, true, true, cell)},
+            // cell -> wifi
+            {makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
+        };
+
+        for (NetworkAgentInfo[] pair : defaultNetworks) {
+            mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(pair[1], pair[0]);
+        }
+
+        String want = String.join("\n",
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 100",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 0",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    network_id <",
+                "      network_id: 100",
+                "    >",
+                "    no_default_network_duration_ms: 0",
+                "    previous_network_id <",
+                "      network_id: 0",
+                "    >",
+                "    previous_network_ip_support: 0",
+                "    transport_types: 0",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 101",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 0",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    network_id <",
+                "      network_id: 101",
+                "    >",
+                "    no_default_network_duration_ms: 0",
+                "    previous_network_id <",
+                "      network_id: 100",
+                "    >",
+                "    previous_network_ip_support: 3",
+                "    transport_types: 1",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 0",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 0",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    network_id <",
+                "      network_id: 0",
+                "    >",
+                "    no_default_network_duration_ms: 0",
+                "    previous_network_id <",
+                "      network_id: 101",
+                "    >",
+                "    previous_network_ip_support: 1",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 102",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 0",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    network_id <",
+                "      network_id: 102",
+                "    >",
+                "    no_default_network_duration_ms: 0",
+                "    previous_network_id <",
+                "      network_id: 0",
+                "    >",
+                "    previous_network_ip_support: 0",
+                "    transport_types: 0",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 103",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 0",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    network_id <",
+                "      network_id: 103",
+                "    >",
+                "    no_default_network_duration_ms: 0",
+                "    previous_network_id <",
+                "      network_id: 102",
+                "    >",
+                "    previous_network_ip_support: 3",
+                "    transport_types: 1",
+                "  >",
+                ">",
+                "version: 2\n");
+
+        verifySerialization(want, getdump("flush"));
+    }
+
+    @Test
     public void testEndToEndLogging() throws Exception {
         // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
         IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
@@ -194,7 +341,6 @@ public class IpConnectivityMetricsTest {
         Parcelable[] events = {
             new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED),
             new DhcpClientEvent("SomeState", 192),
-            new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
             new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
             validationEv,
             apfStats,
@@ -233,6 +379,13 @@ public class IpConnectivityMetricsTest {
         wakeupEvent("wlan0", 10008);
         wakeupEvent("rmnet0", 1000);
 
+        final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
+        final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+        NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
+        NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
+        mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(cellNai, null);
+        mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(wifiNai, cellNai);
+
         String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
@@ -264,30 +417,6 @@ public class IpConnectivityMetricsTest {
                 "  network_id: 0",
                 "  time_ms: 300",
                 "  transports: 0",
-                "  default_network_event <",
-                "    default_network_duration_ms: 0",
-                "    final_score: 0",
-                "    initial_score: 0",
-                "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 102",
-                "    >",
-                "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 101",
-                "    >",
-                "    previous_network_ip_support: 1",
-                "    transport_types: 1",
-                "    transport_types: 2",
-                "    transport_types: 3",
-                "  >",
-                ">",
-                "events <",
-                "  if_name: \"\"",
-                "  link_layer: 4",
-                "  network_id: 0",
-                "  time_ms: 400",
-                "  transports: 0",
                 "  ip_provisioning_event <",
                 "    event_type: 1",
                 "    if_name: \"\"",
@@ -298,7 +427,7 @@ public class IpConnectivityMetricsTest {
                 "  if_name: \"\"",
                 "  link_layer: 4",
                 "  network_id: 0",
-                "  time_ms: 500",
+                "  time_ms: 400",
                 "  transports: 0",
                 "  validation_probe_event <",
                 "    latency_ms: 40730",
@@ -310,7 +439,7 @@ public class IpConnectivityMetricsTest {
                 "  if_name: \"\"",
                 "  link_layer: 4",
                 "  network_id: 0",
-                "  time_ms: 600",
+                "  time_ms: 500",
                 "  transports: 0",
                 "  apf_statistics <",
                 "    dropped_ras: 2",
@@ -331,7 +460,7 @@ public class IpConnectivityMetricsTest {
                 "  if_name: \"\"",
                 "  link_layer: 4",
                 "  network_id: 0",
-                "  time_ms: 700",
+                "  time_ms: 600",
                 "  transports: 0",
                 "  ra_event <",
                 "    dnssl_lifetime: -1",
@@ -344,6 +473,50 @@ public class IpConnectivityMetricsTest {
                 ">",
                 "events <",
                 "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 100",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 0",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    network_id <",
+                "      network_id: 100",
+                "    >",
+                "    no_default_network_duration_ms: 0",
+                "    previous_network_id <",
+                "      network_id: 0",
+                "    >",
+                "    previous_network_ip_support: 0",
+                "    transport_types: 0",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 101",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 0",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    network_id <",
+                "      network_id: 101",
+                "    >",
+                "    no_default_network_duration_ms: 0",
+                "    previous_network_id <",
+                "      network_id: 100",
+                "    >",
+                "    previous_network_ip_support: 2",
+                "    transport_types: 1",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
                 "  link_layer: 4",
                 "  network_id: 100",
                 "  time_ms: 0",
@@ -471,6 +644,26 @@ public class IpConnectivityMetricsTest {
         mNetdListener.onWakeupEvent(prefix, uid, uid, 0);
     }
 
+    NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) {
+        NetworkAgentInfo nai = mock(NetworkAgentInfo.class);
+        when(nai.network()).thenReturn(new Network(netId));
+        when(nai.getCurrentScore()).thenReturn(score);
+        nai.linkProperties = new LinkProperties();
+        nai.networkCapabilities = new NetworkCapabilities();
+        for (int t : BitUtils.unpackBits(transports)) {
+            nai.networkCapabilities.addTransportType(t);
+        }
+        if (ipv4) {
+            nai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.12/24"));
+            nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
+        }
+        if (ipv6) {
+            nai.linkProperties.addLinkAddress(new LinkAddress("2001:db8:dead:beef:f00::a0/64"));
+            nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("::/0")));
+        }
+        return nai;
+    }
+
     List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
         ArgumentCaptor<ConnectivityMetricsEvent> captor =
                 ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);