Merge "Support ignoring validation failures after roam."
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt
index c502f72..0149115 100644
--- a/framework-t/api/system-current.txt
+++ b/framework-t/api/system-current.txt
@@ -37,7 +37,7 @@
 
   public final class EthernetNetworkUpdateRequest implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public android.net.IpConfiguration getIpConfiguration();
+    method @Nullable public android.net.IpConfiguration getIpConfiguration();
     method @Nullable public android.net.NetworkCapabilities getNetworkCapabilities();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR;
@@ -47,7 +47,7 @@
     ctor public EthernetNetworkUpdateRequest.Builder();
     ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest);
     method @NonNull public android.net.EthernetNetworkUpdateRequest build();
-    method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration);
+    method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@Nullable android.net.IpConfiguration);
     method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
   }
 
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index f21aa6f..e4e2151 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -141,7 +141,7 @@
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public java.util.Set<java.lang.Integer> getAccessUids();
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public java.util.Set<java.lang.Integer> getAllowedUids();
     method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
     method public boolean hasForbiddenCapability(int);
     field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
@@ -153,7 +153,7 @@
   }
 
   public static final class NetworkCapabilities.Builder {
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAccessUids(@NonNull java.util.Set<java.lang.Integer>);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAllowedUids(@NonNull java.util.Set<java.lang.Integer>);
     method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
   }
 
diff --git a/framework/src/android/net/ITestNetworkManager.aidl b/framework/src/android/net/ITestNetworkManager.aidl
index 2a863ad..847f14e 100644
--- a/framework/src/android/net/ITestNetworkManager.aidl
+++ b/framework/src/android/net/ITestNetworkManager.aidl
@@ -29,8 +29,7 @@
  */
 interface ITestNetworkManager
 {
-    TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs);
-    TestNetworkInterface createTapInterface();
+    TestNetworkInterface createInterface(boolean isTun, boolean bringUp, in LinkAddress[] addrs);
 
     void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
             in int[] administratorUids, in IBinder binder);
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 87b343c..f7f2f57 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -269,7 +269,7 @@
         mTransportInfo = null;
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
         mUids = null;
-        mAccessUids.clear();
+        mAllowedUids.clear();
         mAdministratorUids = new int[0];
         mOwnerUid = Process.INVALID_UID;
         mSSID = null;
@@ -300,7 +300,7 @@
         }
         mSignalStrength = nc.mSignalStrength;
         mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids);
-        setAccessUids(nc.mAccessUids);
+        setAllowedUids(nc.mAllowedUids);
         setAdministratorUids(nc.getAdministratorUids());
         mOwnerUid = nc.mOwnerUid;
         mForbiddenNetworkCapabilities = nc.mForbiddenNetworkCapabilities;
@@ -1034,7 +1034,7 @@
         final int[] originalAdministratorUids = getAdministratorUids();
         final TransportInfo originalTransportInfo = getTransportInfo();
         final Set<Integer> originalSubIds = getSubscriptionIds();
-        final Set<Integer> originalAccessUids = new ArraySet<>(mAccessUids);
+        final Set<Integer> originalAllowedUids = new ArraySet<>(mAllowedUids);
         clearAll();
         if (0 != (originalCapabilities & (1 << NET_CAPABILITY_NOT_RESTRICTED))) {
             // If the test network is not restricted, then it is only allowed to declare some
@@ -1054,7 +1054,7 @@
         mNetworkSpecifier = originalSpecifier;
         mSignalStrength = originalSignalStrength;
         mTransportInfo = originalTransportInfo;
-        mAccessUids.addAll(originalAccessUids);
+        mAllowedUids.addAll(originalAllowedUids);
 
         // Only retain the owner and administrator UIDs if they match the app registering the remote
         // caller that registered the network.
@@ -1841,20 +1841,20 @@
      * @hide
      */
     @NonNull
-    private final ArraySet<Integer> mAccessUids = new ArraySet<>();
+    private final ArraySet<Integer> mAllowedUids = new ArraySet<>();
 
     /**
      * Set the list of UIDs that can always access this network.
      * @param uids
      * @hide
      */
-    public void setAccessUids(@NonNull final Set<Integer> uids) {
+    public void setAllowedUids(@NonNull final Set<Integer> uids) {
         // could happen with nc.set(nc), cheaper than always making a defensive copy
-        if (uids == mAccessUids) return;
+        if (uids == mAllowedUids) return;
 
         Objects.requireNonNull(uids);
-        mAccessUids.clear();
-        mAccessUids.addAll(uids);
+        mAllowedUids.clear();
+        mAllowedUids.addAll(uids);
     }
 
     /**
@@ -1872,35 +1872,36 @@
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
-    public @NonNull Set<Integer> getAccessUids() {
-        return new ArraySet<>(mAccessUids);
+    public @NonNull Set<Integer> getAllowedUids() {
+        return new ArraySet<>(mAllowedUids);
     }
 
     /** @hide */
     // For internal clients that know what they are doing and need to avoid the performance hit
     // of the defensive copy.
-    public @NonNull ArraySet<Integer> getAccessUidsNoCopy() {
-        return mAccessUids;
+    public @NonNull ArraySet<Integer> getAllowedUidsNoCopy() {
+        return mAllowedUids;
     }
 
     /**
-     * Test whether this UID has special permission to access this network, as per mAccessUids.
+     * Test whether this UID has special permission to access this network, as per mAllowedUids.
      * @hide
      */
-    public boolean isAccessUid(int uid) {
-        return mAccessUids.contains(uid);
+    // TODO : should this be "doesUidHaveAccess" and check the USE_RESTRICTED_NETWORKS permission ?
+    public boolean isUidWithAccess(int uid) {
+        return mAllowedUids.contains(uid);
     }
 
     /**
      * @return whether any UID is in the list of access UIDs
      * @hide
      */
-    public boolean hasAccessUids() {
-        return !mAccessUids.isEmpty();
+    public boolean hasAllowedUids() {
+        return !mAllowedUids.isEmpty();
     }
 
-    private boolean equalsAccessUids(@NonNull NetworkCapabilities other) {
-        return mAccessUids.equals(other.mAccessUids);
+    private boolean equalsAllowedUids(@NonNull NetworkCapabilities other) {
+        return mAllowedUids.equals(other.mAllowedUids);
     }
 
     /**
@@ -2057,7 +2058,7 @@
                 && equalsSpecifier(that)
                 && equalsTransportInfo(that)
                 && equalsUids(that)
-                && equalsAccessUids(that)
+                && equalsAllowedUids(that)
                 && equalsSSID(that)
                 && equalsOwnerUid(that)
                 && equalsPrivateDnsBroken(that)
@@ -2082,7 +2083,7 @@
                 + mSignalStrength * 29
                 + mOwnerUid * 31
                 + Objects.hashCode(mUids) * 37
-                + Objects.hashCode(mAccessUids) * 41
+                + Objects.hashCode(mAllowedUids) * 41
                 + Objects.hashCode(mSSID) * 43
                 + Objects.hashCode(mTransportInfo) * 47
                 + Objects.hashCode(mPrivateDnsBroken) * 53
@@ -2119,7 +2120,7 @@
         dest.writeParcelable((Parcelable) mTransportInfo, flags);
         dest.writeInt(mSignalStrength);
         writeParcelableArraySet(dest, mUids, flags);
-        dest.writeIntArray(CollectionUtils.toIntArray(mAccessUids));
+        dest.writeIntArray(CollectionUtils.toIntArray(mAllowedUids));
         dest.writeString(mSSID);
         dest.writeBoolean(mPrivateDnsBroken);
         dest.writeIntArray(getAdministratorUids());
@@ -2146,10 +2147,10 @@
                 netCap.mTransportInfo = in.readParcelable(null);
                 netCap.mSignalStrength = in.readInt();
                 netCap.mUids = readParcelableArraySet(in, null /* ClassLoader, null for default */);
-                final int[] accessUids = in.createIntArray();
-                netCap.mAccessUids.ensureCapacity(accessUids.length);
-                for (int uid : accessUids) {
-                    netCap.mAccessUids.add(uid);
+                final int[] allowedUids = in.createIntArray();
+                netCap.mAllowedUids.ensureCapacity(allowedUids.length);
+                for (int uid : allowedUids) {
+                    netCap.mAllowedUids.add(uid);
                 }
                 netCap.mSSID = in.readString();
                 netCap.mPrivateDnsBroken = in.readBoolean();
@@ -2228,8 +2229,8 @@
             }
         }
 
-        if (hasAccessUids()) {
-            sb.append(" AccessUids: <").append(mAccessUids).append(">");
+        if (hasAllowedUids()) {
+            sb.append(" AllowedUids: <").append(mAllowedUids).append(">");
         }
 
         if (mOwnerUid != Process.INVALID_UID) {
@@ -3048,9 +3049,9 @@
         @NonNull
         @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
-        public Builder setAccessUids(@NonNull Set<Integer> uids) {
+        public Builder setAllowedUids(@NonNull Set<Integer> uids) {
             Objects.requireNonNull(uids);
-            mCaps.setAccessUids(uids);
+            mCaps.setAllowedUids(uids);
             return this;
         }
 
diff --git a/framework/src/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java
index 9ddd2f5..280e497 100644
--- a/framework/src/android/net/TestNetworkManager.java
+++ b/framework/src/android/net/TestNetworkManager.java
@@ -49,6 +49,11 @@
 
     @NonNull private final ITestNetworkManager mService;
 
+    private static final boolean TAP = false;
+    private static final boolean TUN = true;
+    private static final boolean BRING_UP = true;
+    private static final LinkAddress[] NO_ADDRS = new LinkAddress[0];
+
     /** @hide */
     public TestNetworkManager(@NonNull ITestNetworkManager service) {
         mService = Objects.requireNonNull(service, "missing ITestNetworkManager");
@@ -155,7 +160,7 @@
     public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) {
         try {
             final LinkAddress[] arr = new LinkAddress[linkAddrs.size()];
-            return mService.createTunInterface(linkAddrs.toArray(arr));
+            return mService.createInterface(TUN, BRING_UP, linkAddrs.toArray(arr));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -173,10 +178,28 @@
     @NonNull
     public TestNetworkInterface createTapInterface() {
         try {
-            return mService.createTapInterface();
+            return mService.createInterface(TAP, BRING_UP, NO_ADDRS);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
+    /**
+     * Create a tap interface for testing purposes
+     *
+     * @param bringUp whether to bring up the interface before returning it.
+     *
+     * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
+     *     TAP interface.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
+    @NonNull
+    public TestNetworkInterface createTapInterface(boolean bringUp) {
+        try {
+            return mService.createInterface(TAP, bringUp, NO_ADDRS);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 3496386..d647664 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -2256,7 +2256,7 @@
         newNc.setAdministratorUids(new int[0]);
         if (!checkAnyPermissionOf(
                 callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
-            newNc.setAccessUids(new ArraySet<>());
+            newNc.setAllowedUids(new ArraySet<>());
             newNc.setSubscriptionIds(Collections.emptySet());
         }
 
@@ -6495,7 +6495,7 @@
         if (nc.isPrivateDnsBroken()) {
             throw new IllegalArgumentException("Can't request broken private DNS");
         }
-        if (nc.hasAccessUids()) {
+        if (nc.hasAllowedUids()) {
             throw new IllegalArgumentException("Can't request access UIDs");
         }
     }
@@ -7952,7 +7952,7 @@
         final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
 
         updateVpnUids(nai, prevNc, newNc);
-        updateAccessUids(nai, prevNc, newNc);
+        updateAllowedUids(nai, prevNc, newNc);
         nai.updateScoreForNetworkAgentUpdate();
 
         if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
@@ -8182,17 +8182,17 @@
         }
     }
 
-    private void updateAccessUids(@NonNull NetworkAgentInfo nai,
+    private void updateAllowedUids(@NonNull NetworkAgentInfo nai,
             @Nullable NetworkCapabilities prevNc, @Nullable NetworkCapabilities newNc) {
         // In almost all cases both NC code for empty access UIDs. return as fast as possible.
-        final boolean prevEmpty = null == prevNc || prevNc.getAccessUidsNoCopy().isEmpty();
-        final boolean newEmpty = null == newNc || newNc.getAccessUidsNoCopy().isEmpty();
+        final boolean prevEmpty = null == prevNc || prevNc.getAllowedUidsNoCopy().isEmpty();
+        final boolean newEmpty = null == newNc || newNc.getAllowedUidsNoCopy().isEmpty();
         if (prevEmpty && newEmpty) return;
 
         final ArraySet<Integer> prevUids =
-                null == prevNc ? new ArraySet<>() : prevNc.getAccessUidsNoCopy();
+                null == prevNc ? new ArraySet<>() : prevNc.getAllowedUidsNoCopy();
         final ArraySet<Integer> newUids =
-                null == newNc ? new ArraySet<>() : newNc.getAccessUidsNoCopy();
+                null == newNc ? new ArraySet<>() : newNc.getAllowedUidsNoCopy();
 
         if (prevUids.equals(newUids)) return;
 
@@ -9142,7 +9142,7 @@
             }
             networkAgent.created = true;
             networkAgent.onNetworkCreated();
-            updateAccessUids(networkAgent, null, networkAgent.networkCapabilities);
+            updateAllowedUids(networkAgent, null, networkAgent.networkCapabilities);
         }
 
         if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
index fffd2be..a0bfb4a 100644
--- a/service/src/com/android/server/TestNetworkService.java
+++ b/service/src/com/android/server/TestNetworkService.java
@@ -99,12 +99,14 @@
     }
 
     /**
-     * Create a TUN or TAP interface with the given interface name and link addresses
+     * Create a TUN or TAP interface with the specified parameters.
      *
      * <p>This method will return the FileDescriptor to the interface. Close it to tear down the
      * interface.
      */
-    private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
+    @Override
+    public TestNetworkInterface createInterface(boolean isTun, boolean bringUp,
+            LinkAddress[] linkAddrs) {
         enforceTestNetworkPermissions(mContext);
 
         Objects.requireNonNull(linkAddrs, "missing linkAddrs");
@@ -122,7 +124,9 @@
                         addr.getPrefixLength());
             }
 
-            NetdUtils.setInterfaceUp(mNetd, iface);
+            if (bringUp) {
+                NetdUtils.setInterfaceUp(mNetd, iface);
+            }
 
             return new TestNetworkInterface(tunIntf, iface);
         } catch (RemoteException e) {
@@ -132,28 +136,6 @@
         }
     }
 
-    /**
-     * Create a TUN interface with the given interface name and link addresses
-     *
-     * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
-     * TUN interface.
-     */
-    @Override
-    public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
-        return createInterface(true, linkAddrs);
-    }
-
-    /**
-     * Create a TAP interface with the given interface name
-     *
-     * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the
-     * TAP interface.
-     */
-    @Override
-    public TestNetworkInterface createTapInterface() {
-        return createInterface(false, new LinkAddress[0]);
-    }
-
     // Tracker for TestNetworkAgents
     @GuardedBy("mTestNetworkTracker")
     @NonNull
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 046e934..b73e2cc 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -1221,16 +1221,16 @@
         if (nc.hasTransport(TRANSPORT_TEST)) {
             nc.restrictCapabilitiesForTestNetwork(creatorUid);
         }
-        if (!areAccessUidsAcceptableFromNetworkAgent(nc, authenticator)) {
-            nc.setAccessUids(new ArraySet<>());
+        if (!areAllowedUidsAcceptableFromNetworkAgent(nc, authenticator)) {
+            nc.setAllowedUids(new ArraySet<>());
         }
     }
 
-    private static boolean areAccessUidsAcceptableFromNetworkAgent(
+    private static boolean areAllowedUidsAcceptableFromNetworkAgent(
             @NonNull final NetworkCapabilities nc,
             @Nullable final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) {
         // NCs without access UIDs are fine.
-        if (!nc.hasAccessUids()) return true;
+        if (!nc.hasAllowedUids()) return true;
         // S and below must never accept access UIDs, even if an agent sends them, because netd
         // didn't support the required feature in S.
         if (!SdkLevel.isAtLeastT()) return false;
@@ -1246,9 +1246,9 @@
         // This can only work in T where there is support for CarrierPrivilegeAuthenticator
         if (null != carrierPrivilegeAuthenticator
                 && nc.hasSingleTransport(TRANSPORT_CELLULAR)
-                && (1 == nc.getAccessUidsNoCopy().size())
+                && (1 == nc.getAllowedUidsNoCopy().size())
                 && (carrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
-                        nc.getAccessUidsNoCopy().valueAt(0), nc))) {
+                        nc.getAllowedUidsNoCopy().valueAt(0), nc))) {
             return true;
         }
 
diff --git a/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
index 2e51be3..509110d 100644
--- a/service/src/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
@@ -206,7 +206,7 @@
         }
 
         for (RouteInfo route : mLinkProperties.getRoutes()) {
-            if (route.hasGateway()) {
+            if (route.getType() == RouteInfo.RTN_UNICAST && route.hasGateway()) {
                 InetAddress gateway = route.getGateway();
                 prepareIcmpMeasurement(gateway);
                 if (route.isIPv6Default()) {
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index b6926a8..9ae5fab 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -310,38 +310,38 @@
     }
 
     @Test @IgnoreUpTo(SC_V2)
-    public void testSetAccessUids() {
+    public void testSetAllowedUids() {
         final NetworkCapabilities nc = new NetworkCapabilities();
-        assertThrows(NullPointerException.class, () -> nc.setAccessUids(null));
-        assertFalse(nc.hasAccessUids());
-        assertFalse(nc.isAccessUid(0));
-        assertFalse(nc.isAccessUid(1000));
-        assertEquals(0, nc.getAccessUids().size());
-        nc.setAccessUids(new ArraySet<>());
-        assertFalse(nc.hasAccessUids());
-        assertFalse(nc.isAccessUid(0));
-        assertFalse(nc.isAccessUid(1000));
-        assertEquals(0, nc.getAccessUids().size());
+        assertThrows(NullPointerException.class, () -> nc.setAllowedUids(null));
+        assertFalse(nc.hasAllowedUids());
+        assertFalse(nc.isUidWithAccess(0));
+        assertFalse(nc.isUidWithAccess(1000));
+        assertEquals(0, nc.getAllowedUids().size());
+        nc.setAllowedUids(new ArraySet<>());
+        assertFalse(nc.hasAllowedUids());
+        assertFalse(nc.isUidWithAccess(0));
+        assertFalse(nc.isUidWithAccess(1000));
+        assertEquals(0, nc.getAllowedUids().size());
 
         final ArraySet<Integer> uids = new ArraySet<>();
         uids.add(200);
         uids.add(250);
         uids.add(-1);
         uids.add(Integer.MAX_VALUE);
-        nc.setAccessUids(uids);
+        nc.setAllowedUids(uids);
         assertNotEquals(nc, new NetworkCapabilities());
-        assertTrue(nc.hasAccessUids());
+        assertTrue(nc.hasAllowedUids());
 
         final List<Integer> includedList = List.of(-2, 0, 199, 700, 901, 1000, Integer.MIN_VALUE);
         final List<Integer> excludedList = List.of(-1, 200, 250, Integer.MAX_VALUE);
         for (final int uid : includedList) {
-            assertFalse(nc.isAccessUid(uid));
+            assertFalse(nc.isUidWithAccess(uid));
         }
         for (final int uid : excludedList) {
-            assertTrue(nc.isAccessUid(uid));
+            assertTrue(nc.isUidWithAccess(uid));
         }
 
-        final Set<Integer> outUids = nc.getAccessUids();
+        final Set<Integer> outUids = nc.getAllowedUids();
         assertEquals(4, outUids.size());
         for (final int uid : includedList) {
             assertFalse(outUids.contains(uid));
@@ -361,10 +361,10 @@
             .addCapability(NET_CAPABILITY_EIMS)
             .addCapability(NET_CAPABILITY_NOT_METERED);
         if (isAtLeastS()) {
-            final ArraySet<Integer> accessUids = new ArraySet<>();
-            accessUids.add(4);
-            accessUids.add(9);
-            netCap.setAccessUids(accessUids);
+            final ArraySet<Integer> allowedUids = new ArraySet<>();
+            allowedUids.add(4);
+            allowedUids.add(9);
+            netCap.setAllowedUids(allowedUids);
             netCap.setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2));
             netCap.setUids(uids);
         }
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
new file mode 100644
index 0000000..0a32f09
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.cts
+
+import android.Manifest.permission.MANAGE_TEST_NETWORKS
+import android.Manifest.permission.NETWORK_SETTINGS
+import android.net.IpConfiguration
+import android.net.TestNetworkInterface
+import android.net.TestNetworkManager
+import android.platform.test.annotations.AppModeFull
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.android.net.module.util.ArrayTrackRecord
+import com.android.net.module.util.TrackRecord
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.SC_V2
+import com.android.testutils.runAsShell
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertNull
+import kotlin.test.fail
+import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.InterfaceStateChanged
+import android.os.Handler
+import android.os.HandlerExecutor
+import android.os.Looper
+import com.android.networkstack.apishim.common.EthernetManagerShim.InterfaceStateListener
+import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_ABSENT
+import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_DOWN
+import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_UP
+import com.android.networkstack.apishim.common.EthernetManagerShim.ROLE_CLIENT
+import com.android.networkstack.apishim.common.EthernetManagerShim.ROLE_NONE
+import com.android.networkstack.apishim.EthernetManagerShimImpl
+import java.util.concurrent.Executor
+import kotlin.test.assertEquals
+
+private const val TIMEOUT_MS = 1000L
+private const val NO_CALLBACK_TIMEOUT_MS = 200L
+private val DEFAULT_IP_CONFIGURATION = IpConfiguration(IpConfiguration.IpAssignment.DHCP,
+    IpConfiguration.ProxySettings.NONE, null, null)
+
+@AppModeFull(reason = "Instant apps can't access EthernetManager")
+@RunWith(AndroidJUnit4::class)
+class EthernetManagerTest {
+    // EthernetManager is not updatable before T, so tests do not need to be backwards compatible
+    @get:Rule
+    val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = SC_V2)
+
+    private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
+    private val em by lazy { EthernetManagerShimImpl.newInstance(context) }
+
+    private val createdIfaces = ArrayList<TestNetworkInterface>()
+    private val addedListeners = ArrayList<InterfaceStateListener>()
+
+    private open class EthernetStateListener private constructor(
+        private val history: ArrayTrackRecord<CallbackEntry>
+    ) : InterfaceStateListener,
+                TrackRecord<EthernetStateListener.CallbackEntry> by history {
+        constructor() : this(ArrayTrackRecord())
+
+        val events = history.newReadHead()
+
+        sealed class CallbackEntry {
+            data class InterfaceStateChanged(
+                val iface: String,
+                val state: Int,
+                val role: Int,
+                val configuration: IpConfiguration?
+            ) : CallbackEntry()
+        }
+
+        override fun onInterfaceStateChanged(
+            iface: String,
+            state: Int,
+            role: Int,
+            cfg: IpConfiguration?
+        ) {
+            add(InterfaceStateChanged(iface, state, role, cfg))
+        }
+
+        fun <T : CallbackEntry> expectCallback(expected: T): T {
+            val event = pollForNextCallback()
+            assertEquals(expected, event)
+            return event as T
+        }
+
+        fun expectCallback(iface: TestNetworkInterface, state: Int, role: Int) {
+            expectCallback(InterfaceStateChanged(iface.interfaceName, state, role,
+                if (state != STATE_ABSENT) DEFAULT_IP_CONFIGURATION else null))
+        }
+
+        fun pollForNextCallback(): CallbackEntry {
+            return events.poll(TIMEOUT_MS) ?: fail("Did not receive callback after ${TIMEOUT_MS}ms")
+        }
+
+        fun assertNoCallback() {
+            val cb = events.poll(NO_CALLBACK_TIMEOUT_MS)
+            assertNull(cb, "Expected no callback but got $cb")
+        }
+    }
+
+    @Test
+    public fun testCallbacks() {
+        val executor = HandlerExecutor(Handler(Looper.getMainLooper()))
+
+        // If an interface exists when the callback is registered, it is reported on registration.
+        val iface = runAsShell(MANAGE_TEST_NETWORKS) {
+            createInterface()
+        }
+        val listener = EthernetStateListener()
+        addInterfaceStateListener(executor, listener)
+        listener.expectCallback(iface, STATE_LINK_UP, ROLE_CLIENT)
+
+        // If an interface appears, existing callbacks see it.
+        // TODO: fix the up/up/down/up callbacks and only send down/up.
+        val iface2 = runAsShell(MANAGE_TEST_NETWORKS) {
+            createInterface()
+        }
+        listener.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
+        listener.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
+        listener.expectCallback(iface2, STATE_LINK_DOWN, ROLE_CLIENT)
+        listener.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
+
+        // Removing interfaces first sends link down, then STATE_ABSENT/ROLE_NONE.
+        removeInterface(iface)
+        listener.expectCallback(iface, STATE_LINK_DOWN, ROLE_CLIENT)
+        listener.expectCallback(iface, STATE_ABSENT, ROLE_NONE)
+
+        removeInterface(iface2)
+        listener.expectCallback(iface2, STATE_LINK_DOWN, ROLE_CLIENT)
+        listener.expectCallback(iface2, STATE_ABSENT, ROLE_NONE)
+        listener.assertNoCallback()
+    }
+
+    @Before
+    fun setUp() {
+        runAsShell(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS) {
+            em.setIncludeTestInterfaces(true)
+        }
+    }
+
+    @After
+    fun tearDown() {
+        runAsShell(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS) {
+            em.setIncludeTestInterfaces(false)
+            for (iface in createdIfaces) {
+                if (iface.fileDescriptor.fileDescriptor.valid()) iface.fileDescriptor.close()
+            }
+            for (listener in addedListeners) {
+                em.removeInterfaceStateListener(listener)
+            }
+        }
+    }
+
+    private fun addInterfaceStateListener(executor: Executor, listener: InterfaceStateListener) {
+        em.addInterfaceStateListener(executor, listener)
+        addedListeners.add(listener)
+    }
+
+    private fun createInterface(): TestNetworkInterface {
+        val tnm = context.getSystemService(TestNetworkManager::class.java)
+        return tnm.createTapInterface(false /* bringUp */).also { createdIfaces.add(it) }
+    }
+
+    private fun removeInterface(iface: TestNetworkInterface) {
+        iface.fileDescriptor.close()
+        createdIfaces.remove(iface)
+    }
+}
\ No newline at end of file
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index af567ff..53b00db 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -493,33 +493,33 @@
         }
     }
 
-    private fun ncWithAccessUids(vararg uids: Int) = NetworkCapabilities.Builder()
+    private fun ncWithAllowedUids(vararg uids: Int) = NetworkCapabilities.Builder()
                 .addTransportType(TRANSPORT_TEST)
-                .setAccessUids(uids.toSet()).build()
+                .setAllowedUids(uids.toSet()).build()
 
     @Test
     fun testRejectedUpdates() {
         val callback = TestableNetworkCallback(DEFAULT_TIMEOUT_MS)
         // will be cleaned up in tearDown
         registerNetworkCallback(makeTestNetworkRequest(), callback)
-        val agent = createNetworkAgent(initialNc = ncWithAccessUids(200))
+        val agent = createNetworkAgent(initialNc = ncWithAllowedUids(200))
         agent.register()
         agent.markConnected()
 
         // Make sure the UIDs have been ignored.
         callback.expectCallback<Available>(agent.network!!)
         callback.expectCapabilitiesThat(agent.network!!) {
-            it.accessUids.isEmpty() && !it.hasCapability(NET_CAPABILITY_VALIDATED)
+            it.allowedUids.isEmpty() && !it.hasCapability(NET_CAPABILITY_VALIDATED)
         }
         callback.expectCallback<LinkPropertiesChanged>(agent.network!!)
         callback.expectCallback<BlockedStatus>(agent.network!!)
         callback.expectCapabilitiesThat(agent.network!!) {
-            it.accessUids.isEmpty() && it.hasCapability(NET_CAPABILITY_VALIDATED)
+            it.allowedUids.isEmpty() && it.hasCapability(NET_CAPABILITY_VALIDATED)
         }
         callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
 
         // Make sure that the UIDs are also ignored upon update
-        agent.sendNetworkCapabilities(ncWithAccessUids(200, 300))
+        agent.sendNetworkCapabilities(ncWithAllowedUids(200, 300))
         callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
     }
 
diff --git a/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java b/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java
index 314fbcf..ca9558b 100644
--- a/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java
+++ b/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java
@@ -17,7 +17,9 @@
 package android.net;
 
 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
-import static com.android.testutils.ParcelUtils.assertParcelSane;
+import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
+
+import static org.junit.Assert.assertThrows;
 
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
@@ -47,8 +49,19 @@
         EthernetNetworkUpdateRequest reqWithNullCaps =
                 new EthernetNetworkUpdateRequest.Builder().setIpConfiguration(
                         buildIpConfiguration()).build();
+        EthernetNetworkUpdateRequest reqWithNullConfig =
+                new EthernetNetworkUpdateRequest.Builder().setNetworkCapabilities(
+                        buildNetworkCapabilities()).build();
 
-        assertParcelSane(reqWithNonNull, 2);
-        assertParcelSane(reqWithNullCaps, 2);
+        assertParcelingIsLossless(reqWithNonNull);
+        assertParcelingIsLossless(reqWithNullCaps);
+        assertParcelingIsLossless(reqWithNullConfig);
+    }
+
+    @Test
+    public void testEmptyUpdateRequestThrows() {
+        EthernetNetworkUpdateRequest.Builder emptyBuilder =
+                new EthernetNetworkUpdateRequest.Builder();
+        assertThrows(IllegalStateException.class, () -> emptyBuilder.build());
     }
 }
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index b3293b6..6eec2eb 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -3908,14 +3908,14 @@
     }
 
     @Test
-    public void testNoAccessUidsInNetworkRequests() throws Exception {
+    public void testNoAllowedUidsInNetworkRequests() throws Exception {
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(
                 mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
         final NetworkRequest r = new NetworkRequest.Builder().build();
-        final ArraySet<Integer> accessUids = new ArraySet<>();
-        accessUids.add(6);
-        accessUids.add(9);
-        r.networkCapabilities.setAccessUids(accessUids);
+        final ArraySet<Integer> allowedUids = new ArraySet<>();
+        allowedUids.add(6);
+        allowedUids.add(9);
+        r.networkCapabilities.setAllowedUids(allowedUids);
 
         final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
         final NetworkCallback cb = new NetworkCallback();
@@ -3930,7 +3930,7 @@
 
         // Make sure that resetting the access UIDs to the empty set will allow calling
         // requestNetwork and registerNetworkCallback.
-        r.networkCapabilities.setAccessUids(Collections.emptySet());
+        r.networkCapabilities.setAllowedUids(Collections.emptySet());
         mCm.requestNetwork(r, cb);
         mCm.unregisterNetworkCallback(cb);
         mCm.registerNetworkCallback(r, cb);
@@ -14690,7 +14690,7 @@
     }
 
     @Test
-    public void testAccessUids() throws Exception {
+    public void testAllowedUids() throws Exception {
         final int preferenceOrder =
                 ConnectivityService.PREFERENCE_ORDER_IRRELEVANT_BECAUSE_NOT_DEFAULT;
         mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
@@ -14707,7 +14707,7 @@
         final NetworkCapabilities nc = new NetworkCapabilities.Builder()
                 .addTransportType(TRANSPORT_TEST)
                 .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
-                .setAccessUids(uids)
+                .setAllowedUids(uids)
                 .build();
         final TestNetworkAgentWrapper agent = new TestNetworkAgentWrapper(TRANSPORT_TEST,
                 new LinkProperties(), nc);
@@ -14725,10 +14725,10 @@
 
         uids.add(300);
         uids.add(400);
-        nc.setAccessUids(uids);
+        nc.setAllowedUids(uids);
         agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
         if (SdkLevel.isAtLeastT()) {
-            cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+            cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids));
         } else {
             cb.assertNoCallback();
         }
@@ -14742,10 +14742,10 @@
             inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel);
         }
 
-        nc.setAccessUids(uids);
+        nc.setAllowedUids(uids);
         agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
         if (SdkLevel.isAtLeastT()) {
-            cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+            cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids));
             inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel);
         } else {
             cb.assertNoCallback();
@@ -14753,10 +14753,10 @@
 
         uids.clear();
         uids.add(600);
-        nc.setAccessUids(uids);
+        nc.setAllowedUids(uids);
         agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
         if (SdkLevel.isAtLeastT()) {
-            cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+            cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids));
         } else {
             cb.assertNoCallback();
         }
@@ -14770,10 +14770,10 @@
         }
 
         uids.clear();
-        nc.setAccessUids(uids);
+        nc.setAllowedUids(uids);
         agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
         if (SdkLevel.isAtLeastT()) {
-            cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().isEmpty());
+            cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().isEmpty());
             inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel);
         } else {
             cb.assertNoCallback();
@@ -14784,7 +14784,7 @@
     }
 
     @Test
-    public void testCbsAccessUids() throws Exception {
+    public void testCbsAllowedUids() throws Exception {
         mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
         mServiceContext.setPermission(MANAGE_TEST_NETWORKS, PERMISSION_GRANTED);
 
@@ -14821,29 +14821,29 @@
                 new LinkProperties(), ncb.build());
         mCellNetworkAgent.connect(true);
         cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        ncb.setAccessUids(serviceUidSet);
+        ncb.setAllowedUids(serviceUidSet);
         mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
         if (SdkLevel.isAtLeastT()) {
             cb.expectCapabilitiesThat(mCellNetworkAgent,
-                    caps -> caps.getAccessUids().equals(serviceUidSet));
+                    caps -> caps.getAllowedUids().equals(serviceUidSet));
         } else {
             // S must ignore access UIDs.
             cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
         }
 
         // ...but not to some other UID. Rejection sets UIDs to the empty set
-        ncb.setAccessUids(nonServiceUidSet);
+        ncb.setAllowedUids(nonServiceUidSet);
         mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
         if (SdkLevel.isAtLeastT()) {
             cb.expectCapabilitiesThat(mCellNetworkAgent,
-                    caps -> caps.getAccessUids().isEmpty());
+                    caps -> caps.getAllowedUids().isEmpty());
         } else {
             // S must ignore access UIDs.
             cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
         }
 
         // ...and also not to multiple UIDs even including the service UID
-        ncb.setAccessUids(serviceUidSetPlus);
+        ncb.setAllowedUids(serviceUidSetPlus);
         mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
         cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
 
@@ -14866,7 +14866,7 @@
                 new LinkProperties(), ncb.build());
         mWiFiNetworkAgent.connect(true);
         cb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
-        ncb.setAccessUids(serviceUidSet);
+        ncb.setAllowedUids(serviceUidSet);
         mWiFiNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
         cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
         mCm.unregisterNetworkCallback(cb);