Merge "Register APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer"
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 5750845..27bf114 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -294,7 +294,6 @@
     method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
     method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
     method @NonNull public android.net.NetworkCapabilities build();
-    method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
     method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
     method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
@@ -308,6 +307,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
     method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
     method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
+    method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities();
   }
 
   public class NetworkProvider {
@@ -381,6 +381,7 @@
   public abstract class QosFilter {
     method @NonNull public abstract android.net.Network getNetwork();
     method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+    method public abstract boolean matchesRemoteAddress(@NonNull java.net.InetAddress, int, int);
   }
 
   public final class QosSession implements android.os.Parcelable {
@@ -403,6 +404,7 @@
     method public int describeContents();
     method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
     method @NonNull public android.net.Network getNetwork();
+    method @Nullable public java.net.InetSocketAddress getRemoteSocketAddress();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
   }
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index c19a906..90d821b 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -2399,6 +2399,11 @@
         return mTransportInfo.getApplicableRedactions();
     }
 
+    private NetworkCapabilities removeDefaultCapabilites() {
+        mNetworkCapabilities &= ~DEFAULT_CAPABILITIES;
+        return this;
+    }
+
     /**
      * Builder class for NetworkCapabilities.
      *
@@ -2435,6 +2440,16 @@
         }
 
         /**
+         * Creates a new Builder without the default capabilities.
+         */
+        @NonNull
+        public static Builder withoutDefaultCapabilities() {
+            final NetworkCapabilities nc = new NetworkCapabilities();
+            nc.removeDefaultCapabilites();
+            return new Builder(nc);
+        }
+
+        /**
          * Adds the given transport type.
          *
          * Multiple transports may be added. Note that when searching for a network to satisfy a
@@ -2495,17 +2510,6 @@
         }
 
         /**
-         * Completely clears the contents of this object, removing even the capabilities that are
-         * set by default when the object is constructed.
-         * @return this builder
-         */
-        @NonNull
-        public Builder clearAll() {
-            mCaps.clearAll();
-            return this;
-        }
-
-        /**
          * Sets the owner UID.
          *
          * The default value is {@link Process#INVALID_UID}. Pass this value to reset.
diff --git a/framework/src/android/net/QosFilter.java b/framework/src/android/net/QosFilter.java
index ab55002..957c867 100644
--- a/framework/src/android/net/QosFilter.java
+++ b/framework/src/android/net/QosFilter.java
@@ -71,5 +71,16 @@
      */
     public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
             int startPort, int endPort);
+
+    /**
+     * Determines whether or not the parameters is a match for the filter.
+     *
+     * @param address the remote address
+     * @param startPort the start of the port range
+     * @param endPort the end of the port range
+     * @return whether the parameters match the remote address of the filter
+     */
+    public abstract boolean matchesRemoteAddress(@NonNull InetAddress address,
+            int startPort, int endPort);
 }
 
diff --git a/framework/src/android/net/QosSocketFilter.java b/framework/src/android/net/QosSocketFilter.java
index 2080e68..69da7f4 100644
--- a/framework/src/android/net/QosSocketFilter.java
+++ b/framework/src/android/net/QosSocketFilter.java
@@ -138,13 +138,26 @@
         if (mQosSocketInfo.getLocalSocketAddress() == null) {
             return false;
         }
-
-        return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
+        return matchesAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
                 endPort);
     }
 
     /**
-     * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the
+     * @inheritDoc
+     */
+    @Override
+    public boolean matchesRemoteAddress(@NonNull final InetAddress address, final int startPort,
+            final int endPort) {
+        if (mQosSocketInfo.getRemoteSocketAddress() == null) {
+            return false;
+        }
+        return matchesAddress(mQosSocketInfo.getRemoteSocketAddress(), address, startPort,
+                endPort);
+    }
+
+    /**
+     * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)}
+     * and {@link QosSocketFilter#matchesRemoteAddress(InetAddress, int, int)} with the
      * filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
      * <p>
      * This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
@@ -156,7 +169,7 @@
      * @param endPort the end of the port range to check
      */
     @VisibleForTesting
-    public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress,
+    public static boolean matchesAddress(@NonNull final InetSocketAddress filterSocketAddress,
             @NonNull final InetAddress address,
             final int startPort, final int endPort) {
         return startPort <= filterSocketAddress.getPort()
diff --git a/framework/src/android/net/QosSocketInfo.java b/framework/src/android/net/QosSocketInfo.java
index 53d9669..a45d507 100644
--- a/framework/src/android/net/QosSocketInfo.java
+++ b/framework/src/android/net/QosSocketInfo.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
@@ -32,7 +33,8 @@
 /**
  * Used in conjunction with
  * {@link ConnectivityManager#registerQosCallback}
- * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}.
+ * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}
+ * and/or remote address and port of a connected {@link Socket}.
  *
  * @hide
  */
@@ -48,6 +50,9 @@
     @NonNull
     private final InetSocketAddress mLocalSocketAddress;
 
+    @Nullable
+    private final InetSocketAddress mRemoteSocketAddress;
+
     /**
      * The {@link Network} the socket is on.
      *
@@ -81,6 +86,18 @@
     }
 
     /**
+     * The remote address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
+     * The value does not reflect any changes that occur to the socket after it is first set
+     * in the constructor.
+     *
+     * @return the remote address of the socket if socket is connected, null otherwise
+     */
+    @Nullable
+    public InetSocketAddress getRemoteSocketAddress() {
+        return mRemoteSocketAddress;
+    }
+
+    /**
      * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}.  The
      * {@link Socket} must remain bound in order to receive {@link QosSession}s.
      *
@@ -95,6 +112,12 @@
         mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
         mLocalSocketAddress =
                 new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
+
+        if (socket.isConnected()) {
+            mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
+        } else {
+            mRemoteSocketAddress = null;
+        }
     }
 
     /* Parcelable methods */
@@ -102,11 +125,15 @@
         mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
         mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
 
-        final int addressLength = in.readInt();
-        mLocalSocketAddress = readSocketAddress(in, addressLength);
+        final int localAddressLength = in.readInt();
+        mLocalSocketAddress = readSocketAddress(in, localAddressLength);
+
+        final int remoteAddressLength = in.readInt();
+        mRemoteSocketAddress = remoteAddressLength == 0 ? null
+                : readSocketAddress(in, remoteAddressLength);
     }
 
-    private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
+    private @NonNull InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
         final byte[] address = new byte[addressLength];
         in.readByteArray(address);
         final int port = in.readInt();
@@ -130,10 +157,19 @@
         mNetwork.writeToParcel(dest, 0);
         mParcelFileDescriptor.writeToParcel(dest, 0);
 
-        final byte[] address = mLocalSocketAddress.getAddress().getAddress();
-        dest.writeInt(address.length);
-        dest.writeByteArray(address);
+        final byte[] localAddress = mLocalSocketAddress.getAddress().getAddress();
+        dest.writeInt(localAddress.length);
+        dest.writeByteArray(localAddress);
         dest.writeInt(mLocalSocketAddress.getPort());
+
+        if (mRemoteSocketAddress == null) {
+            dest.writeInt(0);
+        } else {
+            final byte[] remoteAddress = mRemoteSocketAddress.getAddress().getAddress();
+            dest.writeInt(remoteAddress.length);
+            dest.writeByteArray(remoteAddress);
+            dest.writeInt(mRemoteSocketAddress.getPort());
+        }
     }
 
     @NonNull
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 051a00b..085943a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -8588,11 +8588,7 @@
         final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
         try {
             final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>();
-            // TODO: Directly use NetworkStateSnapshot when feasible.
-            for (final NetworkState state : getAllNetworkState()) {
-                final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
-                        state.networkCapabilities, state.linkProperties, state.subscriberId,
-                        state.legacyNetworkType);
+            for (final NetworkStateSnapshot snapshot : getAllNetworkStateSnapshots()) {
                 snapshots.add(snapshot);
             }
             mStatsManager.notifyNetworkStatus(getDefaultNetworks(),
diff --git a/tests/unit/java/android/net/QosSocketFilterTest.java b/tests/unit/java/android/net/QosSocketFilterTest.java
index ad58960..40f8f1b 100644
--- a/tests/unit/java/android/net/QosSocketFilterTest.java
+++ b/tests/unit/java/android/net/QosSocketFilterTest.java
@@ -35,7 +35,7 @@
     public void testPortExactMatch() {
         final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
         final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
-        assertTrue(QosSocketFilter.matchesLocalAddress(
+        assertTrue(QosSocketFilter.matchesAddress(
                 new InetSocketAddress(addressA, 10), addressB, 10, 10));
 
     }
@@ -44,7 +44,7 @@
     public void testPortLessThanStart() {
         final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
         final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
-        assertFalse(QosSocketFilter.matchesLocalAddress(
+        assertFalse(QosSocketFilter.matchesAddress(
                 new InetSocketAddress(addressA, 8), addressB, 10, 10));
     }
 
@@ -52,7 +52,7 @@
     public void testPortGreaterThanEnd() {
         final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
         final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
-        assertFalse(QosSocketFilter.matchesLocalAddress(
+        assertFalse(QosSocketFilter.matchesAddress(
                 new InetSocketAddress(addressA, 18), addressB, 10, 10));
     }
 
@@ -60,7 +60,7 @@
     public void testPortBetweenStartAndEnd() {
         final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
         final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
-        assertTrue(QosSocketFilter.matchesLocalAddress(
+        assertTrue(QosSocketFilter.matchesAddress(
                 new InetSocketAddress(addressA, 10), addressB, 8, 18));
     }
 
@@ -68,7 +68,7 @@
     public void testAddressesDontMatch() {
         final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
         final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
-        assertFalse(QosSocketFilter.matchesLocalAddress(
+        assertFalse(QosSocketFilter.matchesAddress(
                 new InetSocketAddress(addressA, 10), addressB, 10, 10));
     }
 }
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 9683e1c..41458f1 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -127,6 +127,7 @@
 import static com.android.testutils.MiscAsserts.assertEmpty;
 import static com.android.testutils.MiscAsserts.assertLength;
 import static com.android.testutils.MiscAsserts.assertRunsInAtMost;
+import static com.android.testutils.MiscAsserts.assertSameElements;
 import static com.android.testutils.MiscAsserts.assertThrows;
 
 import static org.junit.Assert.assertEquals;
@@ -5806,20 +5807,8 @@
         mCm.unregisterNetworkCallback(networkCallback);
     }
 
-    private <T> void assertSameElementsNoDuplicates(T[] expected, T[] actual) {
-        // Easier to implement than a proper "assertSameElements" method that also correctly deals
-        // with duplicates.
-        final String msg = Arrays.toString(expected) + " != " + Arrays.toString(actual);
-        assertEquals(msg, expected.length, actual.length);
-        Set expectedSet = new ArraySet<>(Arrays.asList(expected));
-        assertEquals("expected contains duplicates", expectedSet.size(), expected.length);
-        // actual cannot have duplicates because it's the same length and has the same elements.
-        Set actualSet = new ArraySet<>(Arrays.asList(actual));
-        assertEquals(expectedSet, actualSet);
-    }
-
-    private void expectNetworkStatus(Network[] networks, String defaultIface,
-            Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
+    private void expectNotifyNetworkStatus(List<Network> networks, String defaultIface,
+            Integer vpnUid, String vpnIfname, List<String> underlyingIfaces) throws Exception {
         ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
         ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
                 ArgumentCaptor.forClass(List.class);
@@ -5827,26 +5816,24 @@
         verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
                 any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
 
-        assertSameElementsNoDuplicates(networksCaptor.getValue().toArray(), networks);
+        assertSameElements(networksCaptor.getValue(), networks);
 
-        UnderlyingNetworkInfo[] infos =
-                vpnInfosCaptor.getValue().toArray(new UnderlyingNetworkInfo[0]);
+        List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue();
         if (vpnUid != null) {
-            assertEquals("Should have exactly one VPN:", 1, infos.length);
-            UnderlyingNetworkInfo info = infos[0];
+            assertEquals("Should have exactly one VPN:", 1, infos.size());
+            UnderlyingNetworkInfo info = infos.get(0);
             assertEquals("Unexpected VPN owner:", (int) vpnUid, info.getOwnerUid());
             assertEquals("Unexpected VPN interface:", vpnIfname, info.getInterface());
-            assertSameElementsNoDuplicates(underlyingIfaces,
-                    info.getUnderlyingInterfaces().toArray(new String[0]));
+            assertSameElements(underlyingIfaces, info.getUnderlyingInterfaces());
         } else {
-            assertEquals(0, infos.length);
+            assertEquals(0, infos.size());
             return;
         }
     }
 
-    private void expectNetworkStatus(
-            Network[] networks, String defaultIface) throws Exception {
-        expectNetworkStatus(networks, defaultIface, null, null, new String[0]);
+    private void expectNotifyNetworkStatus(
+            List<Network> networks, String defaultIface) throws Exception {
+        expectNotifyNetworkStatus(networks, defaultIface, null, null, List.of());
     }
 
     @Test
@@ -5854,8 +5841,8 @@
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
 
-        final Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
-        final Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
+        final List<Network> onlyCell = List.of(mCellNetworkAgent.getNetwork());
+        final List<Network> onlyWifi = List.of(mWiFiNetworkAgent.getNetwork());
 
         LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -5866,7 +5853,7 @@
         mCellNetworkAgent.connect(false);
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
-        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
         reset(mStatsManager);
 
         // Default network switch should update ifaces.
@@ -5874,37 +5861,37 @@
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
         waitForIdle();
         assertEquals(wifiLp, mService.getActiveLinkProperties());
-        expectNetworkStatus(onlyWifi, WIFI_IFNAME);
+        expectNotifyNetworkStatus(onlyWifi, WIFI_IFNAME);
         reset(mStatsManager);
 
         // Disconnect should update ifaces.
         mWiFiNetworkAgent.disconnect();
         waitForIdle();
-        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
         reset(mStatsManager);
 
         // Metered change should update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         waitForIdle();
-        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
         reset(mStatsManager);
 
         mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         waitForIdle();
-        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
         reset(mStatsManager);
 
         // Temp metered change shouldn't update ifaces
         mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
         waitForIdle();
-        verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)),
+        verify(mStatsManager, never()).notifyNetworkStatus(eq(onlyCell),
                 any(List.class), eq(MOBILE_IFNAME), any(List.class));
         reset(mStatsManager);
 
         // Roaming change should update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
         waitForIdle();
-        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
         reset(mStatsManager);
 
         // Test VPNs.
@@ -5914,29 +5901,29 @@
         mMockVpn.establishForMyUid(lp);
         assertUidRangesUpdatedForMyUid(true);
 
-        final Network[] cellAndVpn = new Network[] {
-                mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
+        final List<Network> cellAndVpn =
+                List.of(mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork());
 
         // A VPN with default (null) underlying networks sets the underlying network's interfaces...
-        expectNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                new String[]{MOBILE_IFNAME});
+        expectNotifyNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+                List.of(MOBILE_IFNAME));
 
         // ...and updates them as the default network switches.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
         final Network[] onlyNull = new Network[]{null};
-        final Network[] wifiAndVpn = new Network[] {
-                mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
-        final Network[] cellAndWifi = new Network[] {
-                mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
-        final Network[] cellNullAndWifi = new Network[] {
-                mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
+        final List<Network> wifiAndVpn =
+                List.of(mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork());
+        final List<Network> cellAndWifi =
+                List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork());
+        final Network[] cellNullAndWifi =
+                new Network[]{mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
 
         waitForIdle();
         assertEquals(wifiLp, mService.getActiveLinkProperties());
-        expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
-                new String[]{WIFI_IFNAME});
+        expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+                List.of(WIFI_IFNAME));
         reset(mStatsManager);
 
         // A VPN that sets its underlying networks passes the underlying interfaces, and influences
@@ -5945,23 +5932,23 @@
         // MOBILE_IFNAME even though the default network is wifi.
         // TODO: fix this to pass in the actual default network interface. Whether or not the VPN
         // applies to the system server UID should not have any bearing on network stats.
-        mMockVpn.setUnderlyingNetworks(onlyCell);
+        mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
         waitForIdle();
-        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                new String[]{MOBILE_IFNAME});
+        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+                List.of(MOBILE_IFNAME));
         reset(mStatsManager);
 
-        mMockVpn.setUnderlyingNetworks(cellAndWifi);
+        mMockVpn.setUnderlyingNetworks(cellAndWifi.toArray(new Network[0]));
         waitForIdle();
-        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+                List.of(MOBILE_IFNAME, WIFI_IFNAME));
         reset(mStatsManager);
 
         // Null underlying networks are ignored.
         mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
         waitForIdle();
-        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+                List.of(MOBILE_IFNAME, WIFI_IFNAME));
         reset(mStatsManager);
 
         // If an underlying network disconnects, that interface should no longer be underlying.
@@ -5974,8 +5961,8 @@
         mCellNetworkAgent.disconnect();
         waitForIdle();
         assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
-        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+                List.of(MOBILE_IFNAME, WIFI_IFNAME));
 
         // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
         // network for the VPN...
@@ -6009,26 +5996,26 @@
         // Also, for the same reason as above, the active interface passed in is null.
         mMockVpn.setUnderlyingNetworks(new Network[0]);
         waitForIdle();
-        expectNetworkStatus(wifiAndVpn, null);
+        expectNotifyNetworkStatus(wifiAndVpn, null);
         reset(mStatsManager);
 
         // Specifying only a null underlying network is the same as no networks.
         mMockVpn.setUnderlyingNetworks(onlyNull);
         waitForIdle();
-        expectNetworkStatus(wifiAndVpn, null);
+        expectNotifyNetworkStatus(wifiAndVpn, null);
         reset(mStatsManager);
 
         // Specifying networks that are all disconnected is the same as specifying no networks.
-        mMockVpn.setUnderlyingNetworks(onlyCell);
+        mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
         waitForIdle();
-        expectNetworkStatus(wifiAndVpn, null);
+        expectNotifyNetworkStatus(wifiAndVpn, null);
         reset(mStatsManager);
 
         // Passing in null again means follow the default network again.
         mMockVpn.setUnderlyingNetworks(null);
         waitForIdle();
-        expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
-                new String[]{WIFI_IFNAME});
+        expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+                List.of(WIFI_IFNAME));
         reset(mStatsManager);
     }
 
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index fd374bc..fe2985c 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -306,7 +306,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
@@ -349,7 +349,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
@@ -423,7 +423,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // modify some number on wifi, and trigger poll event
@@ -464,7 +464,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // create some traffic on first network
@@ -499,7 +499,7 @@
                 .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
                 .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
         forcePollAndWaitForIdle();
 
@@ -539,7 +539,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // create some traffic
@@ -607,7 +607,7 @@
         expectNetworkStatsUidDetail(buildEmptyStats());
 
         setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
@@ -699,7 +699,7 @@
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
@@ -714,7 +714,7 @@
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
@@ -730,7 +730,7 @@
                           NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
@@ -744,7 +744,7 @@
         states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
@@ -797,7 +797,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // create some traffic for two apps
@@ -856,7 +856,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         NetworkStats.Entry entry1 = new NetworkStats.Entry(
@@ -900,7 +900,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         NetworkStats.Entry uidStats = new NetworkStats.Entry(
@@ -931,7 +931,7 @@
 
         // mStatsFactory#readNetworkStatsDetail() has the following invocations:
         // 1) NetworkStatsService#systemReady from #setUp.
-        // 2) mService#forceUpdateIfaces in the test above.
+        // 2) mService#notifyNetworkStatus in the test above.
         //
         // Additionally, we should have one call from the above call to mService#getDetailedUidStats
         // with the augmented ifaceFilter.
@@ -955,7 +955,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // create some initial traffic
@@ -1013,7 +1013,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // create some initial traffic
@@ -1053,7 +1053,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic
@@ -1092,7 +1092,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // create some tethering traffic
@@ -1149,7 +1149,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
@@ -1255,7 +1255,7 @@
                 mService.registerNetworkStatsProvider("TEST", provider);
         assertNotNull(cb);
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Verifies that one requestStatsUpdate will be called during iface update.
@@ -1320,7 +1320,7 @@
                 mService.registerNetworkStatsProvider("TEST", provider);
         assertNotNull(cb);
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Verifies that one requestStatsUpdate will be called during iface update.
@@ -1378,7 +1378,7 @@
         expectDefaultSettings();
         NetworkStateSnapshot[] states =
                 new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Register custom provider and retrieve callback.
@@ -1428,7 +1428,7 @@
 
         // 3G network comes online.
         setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
@@ -1450,7 +1450,8 @@
         setCombineSubtypeEnabled(true);
 
         // Call handleOnCollapsedRatTypeChanged manually to simulate the callback fired
-        // when stopping monitor, this is needed by NetworkStatsService to trigger updateIfaces.
+        // when stopping monitor, this is needed by NetworkStatsService to trigger
+        // handleNotifyNetworkStatus.
         mService.handleOnCollapsedRatTypeChanged();
         HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
         // Create some traffic.
@@ -1499,7 +1500,7 @@
         NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
                 buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
         expectNetworkStatsUidDetail(buildEmptyStats());
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
         // Create some traffic on mobile network.