[automerger skipped] Add INTERACT_ACROSS_USERS_FULL to test for setCurrentProxyScriptUrl am: d9639a9bf4 -s ours

am skip reason: Merged-In I2ddff09b4c9cda1e7c5f3566662ba9cc07fffaae with SHA-1 ac8c47eef6 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/15426434

Change-Id: I3c66761a093e132e1c3d12495de60651dd28b287
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 465f727..0ac09cc 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,5 +1,8 @@
 {
   "presubmit": [
+    {
+      "name": "ConnectivityCoverageTests"
+    },
     // Run in addition to mainline-presubmit as mainline-presubmit is not
     // supported in every branch.
     // CtsNetTestCasesLatestSdk uses stable API shims, so does not exercise
@@ -21,7 +24,7 @@
   ],
   "postsubmit": [
     {
-      "name": "ConnectivityCoverageTests"
+      "name": "TetheringPrivilegedTests"
     }
   ],
   "mainline-presubmit": [
@@ -33,6 +36,9 @@
           "exclude-annotation": "com.android.testutils.SkipPresubmit"
         }
       ]
+    },
+    {
+      "name": "ConnectivityCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
     }
   ],
   "mainline-postsubmit": [
@@ -43,14 +49,6 @@
     },
     {
       "name": "TetheringCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
-    },
-    {
-      "name": "ConnectivityCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
-    }
-  ],
-  "imports": [
-    {
-      "path": "packages/modules/NetworkStack"
     }
   ],
   "imports": [
diff --git a/Tethering/apex/AndroidManifest.xml b/Tethering/apex/AndroidManifest.xml
index 4aae3cc..dbc8ec8 100644
--- a/Tethering/apex/AndroidManifest.xml
+++ b/Tethering/apex/AndroidManifest.xml
@@ -18,12 +18,4 @@
   package="com.android.tethering">
   <!-- APEX does not have classes.dex -->
   <application android:hasCode="false" />
-  <!-- b/145383354: Current minSdk is locked to Q for development cycle, lock it to next version
-                    before ship. -->
-  <!-- TODO: Uncomment this when the R API level is fixed. b/148281152 -->
-  <!--uses-sdk
-      android:minSdkVersion="29"
-      android:targetSdkVersion="29"
-  />
-  -->
 </manifest>
diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp
index 27c84cf..2e76501 100644
--- a/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ b/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -34,6 +34,10 @@
 static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr);
 static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
 
+static void throwSocketException(JNIEnv *env, const char* msg, int error) {
+    jniThrowExceptionFmt(env, "java/net/SocketException", "%s: %s", msg, strerror(error));
+}
+
 static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32_t type) {
     sock_filter filter_code[] = {
         // Check header is ICMPv6.
@@ -56,8 +60,7 @@
 
     int fd = netjniutils::GetNativeFileDescriptor(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+        throwSocketException(env, "setsockopt(SO_ATTACH_FILTER)", errno);
     }
 }
 
@@ -84,8 +87,7 @@
     ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &rs_only);
     socklen_t len = sizeof(rs_only);
     if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &rs_only, len) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(ICMP6_FILTER): %s", strerror(errno));
+        throwSocketException(env, "setsockopt(ICMP6_FILTER)", errno);
         return;
     }
 
@@ -97,8 +99,7 @@
     int hops = kLinkLocalHopLimit;
     len = sizeof(hops);
     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, len) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno));
+        throwSocketException(env, "setsockopt(IPV6_MULTICAST_HOPS)", errno);
         return;
     }
 
@@ -106,8 +107,7 @@
     hops = kLinkLocalHopLimit;
     len = sizeof(hops);
     if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, len) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno));
+        throwSocketException(env, "setsockopt(IPV6_UNICAST_HOPS)", errno);
         return;
     }
 
@@ -115,16 +115,14 @@
     int off = 0;
     len = sizeof(off);
     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, len) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(IPV6_MULTICAST_LOOP): %s", strerror(errno));
+        throwSocketException(env, "setsockopt(IPV6_MULTICAST_LOOP)", errno);
         return;
     }
 
     // Specify the IPv6 interface to use for outbound multicast.
     len = sizeof(ifIndex);
     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, len) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno));
+        throwSocketException(env, "setsockopt(IPV6_MULTICAST_IF)", errno);
         return;
     }
 
@@ -144,8 +142,7 @@
     auto sa = reinterpret_cast<const struct sockaddr *>(&sin6);
     len = sizeof(sin6);
     if (bind(fd, sa, len) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "bind(IN6ADDR_ANY): %s", strerror(errno));
+        throwSocketException(env, "bind(IN6ADDR_ANY)", errno);
         return;
     }
 
@@ -156,8 +153,7 @@
     };
     len = sizeof(all_rtrs);
     if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &all_rtrs, len) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno));
+        throwSocketException(env, "setsockopt(IPV6_JOIN_GROUP)", errno);
         return;
     }
 }
diff --git a/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp b/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp
index eadc210..7970a23 100644
--- a/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp
+++ b/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp
@@ -27,40 +27,11 @@
 
 namespace android {
 
-static jclass sErrnoExceptionClass;
-static jmethodID sErrnoExceptionCtor2;
-static jmethodID sErrnoExceptionCtor3;
-
-static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
-    if (sErrnoExceptionClass == nullptr || sErrnoExceptionClass == nullptr) return;
-
-    jthrowable cause = nullptr;
-    if (env->ExceptionCheck()) {
-        cause = env->ExceptionOccurred();
-        env->ExceptionClear();
-    }
-
-    ScopedLocalRef<jstring> msg(env, env->NewStringUTF(functionName));
-
-    // Not really much we can do here if msg is null, let's try to stumble on...
-    if (msg.get() == nullptr) env->ExceptionClear();
-
-    jobject errnoException;
-    if (cause != nullptr) {
-        errnoException = env->NewObject(sErrnoExceptionClass, sErrnoExceptionCtor3, msg.get(),
-                error, cause);
-    } else {
-        errnoException = env->NewObject(sErrnoExceptionClass, sErrnoExceptionCtor2, msg.get(),
-                error);
-    }
-    env->Throw(static_cast<jthrowable>(errnoException));
-}
-
 static jint com_android_networkstack_tethering_BpfMap_closeMap(JNIEnv *env, jobject clazz,
         jint fd) {
     int ret = close(fd);
 
-    if (ret) throwErrnoException(env, "closeMap", errno);
+    if (ret) jniThrowErrnoException(env, "closeMap", errno);
 
     return ret;
 }
@@ -82,13 +53,13 @@
     int ret = bpf::writeToMapEntry(static_cast<int>(fd), keyRO.get(), valueRO.get(),
             static_cast<int>(flags));
 
-    if (ret) throwErrnoException(env, "writeToMapEntry", errno);
+    if (ret) jniThrowErrnoException(env, "writeToMapEntry", errno);
 }
 
 static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, int err) {
     if (ret == 0) return true;
 
-    if (err != ENOENT) throwErrnoException(env, functionName, err);
+    if (err != ENOENT) jniThrowErrnoException(env, functionName, err);
     return false;
 }
 
@@ -155,18 +126,6 @@
 };
 
 int register_com_android_networkstack_tethering_BpfMap(JNIEnv* env) {
-    sErrnoExceptionClass = static_cast<jclass>(env->NewGlobalRef(
-            env->FindClass("android/system/ErrnoException")));
-    if (sErrnoExceptionClass == nullptr) return JNI_ERR;
-
-    sErrnoExceptionCtor2 = env->GetMethodID(sErrnoExceptionClass, "<init>",
-            "(Ljava/lang/String;I)V");
-    if (sErrnoExceptionCtor2 == nullptr) return JNI_ERR;
-
-    sErrnoExceptionCtor3 = env->GetMethodID(sErrnoExceptionClass, "<init>",
-            "(Ljava/lang/String;ILjava/lang/Throwable;)V");
-    if (sErrnoExceptionCtor3 == nullptr) return JNI_ERR;
-
     return jniRegisterNativeMethods(env,
             "com/android/networkstack/tethering/BpfMap",
             gMethods, NELEM(gMethods));
diff --git a/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp b/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp
index 2fb5985..2d679a8 100644
--- a/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp
+++ b/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp
@@ -44,37 +44,36 @@
 const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK;
 const sockaddr_nl KERNEL_NLADDR = {AF_NETLINK, 0, 0, 0};
 
+static void throwIOException(JNIEnv *env, const char* msg, int error) {
+    jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg, strerror(error));
+}
+
 // TODO: move to frameworks/libs/net/common/native for sharing with
 // system/netd/server/OffloadUtils.{c, h}.
 static void sendAndProcessNetlinkResponse(JNIEnv* env, const void* req, int len) {
     int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);  // TODO: use unique_fd
     if (fd == -1) {
-        jniThrowExceptionFmt(env, "java/io/IOException",
-                             "socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE): %s",
-                             strerror(errno));
+        throwIOException(env, "socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)", errno);
         return;
     }
 
     static constexpr int on = 1;
     if (setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on))) {
-        jniThrowExceptionFmt(env, "java/io/IOException",
-                             "setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, %d)", on);
+        throwIOException(env, "setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, 1)", errno);
         close(fd);
         return;
     }
 
     // this is needed to get valid strace netlink parsing, it allocates the pid
     if (bind(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR))) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "bind(fd, {AF_NETLINK, 0, 0}): %s",
-                             strerror(errno));
+        throwIOException(env, "bind(fd, {AF_NETLINK, 0, 0})", errno);
         close(fd);
         return;
     }
 
     // we do not want to receive messages from anyone besides the kernel
     if (connect(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR))) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "connect(fd, {AF_NETLINK, 0, 0}): %s",
-                             strerror(errno));
+        throwIOException(env, "connect(fd, {AF_NETLINK, 0, 0})", errno);
         close(fd);
         return;
     }
@@ -82,15 +81,13 @@
     int rv = send(fd, req, len, 0);
 
     if (rv == -1) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "send(fd, req, len, 0): %s",
-                             strerror(errno));
+        throwIOException(env, "send(fd, req, len, 0)", errno);
         close(fd);
         return;
     }
 
     if (rv != len) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "send(fd, req, len, 0): %s",
-                             strerror(EMSGSIZE));
+        throwIOException(env, "send(fd, req, len, 0)", EMSGSIZE);
         close(fd);
         return;
     }
@@ -104,7 +101,7 @@
     rv = recv(fd, &resp, sizeof(resp), MSG_TRUNC);
 
     if (rv == -1) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "recv() failed: %s", strerror(errno));
+        throwIOException(env, "recv() failed", errno);
         close(fd);
         return;
     }
@@ -131,8 +128,7 @@
     }
 
     if (resp.e.error) {  // returns 0 on success
-        jniThrowExceptionFmt(env, "java/io/IOException", "NLMSG_ERROR message return error: %s",
-                             strerror(-resp.e.error));
+        throwIOException(env, "NLMSG_ERROR message return error", -resp.e.error);
     }
     close(fd);
     return;
@@ -198,8 +194,7 @@
 
     const int bpfFd = bpf::retrieveProgram(pathname.c_str());
     if (bpfFd == -1) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "retrieveProgram failed %s",
-                             strerror(errno));
+        throwIOException(env, "retrieveProgram failed", errno);
         return;
     }
 
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 067542f..01be97a 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -125,9 +125,9 @@
     }
 
     @VisibleForTesting
-    static final int POLLING_CONNTRACK_TIMEOUT_MS = 60_000;
+    static final int CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS = 60_000;
     @VisibleForTesting
-    static final int NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED = 432000;
+    static final int NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED = 432_000;
     @VisibleForTesting
     static final int NF_CONNTRACK_UDP_TIMEOUT_STREAM = 180;
 
@@ -250,10 +250,10 @@
         maybeSchedulePollingStats();
     };
 
-    // Runnable that used by scheduling next polling of conntrack timeout.
-    private final Runnable mScheduledPollingConntrackTimeout = () -> {
-        maybeRefreshConntrackTimeout();
-        maybeSchedulePollingConntrackTimeout();
+    // Runnable that used by scheduling next refreshing of conntrack timeout.
+    private final Runnable mScheduledConntrackTimeoutUpdate = () -> {
+        refreshAllConntrackTimeouts();
+        maybeScheduleConntrackTimeoutUpdate();
     };
 
     // TODO: add BpfMap<TetherDownstream64Key, TetherDownstream64Value> retrieving function.
@@ -435,7 +435,7 @@
 
         mPollingStarted = true;
         maybeSchedulePollingStats();
-        maybeSchedulePollingConntrackTimeout();
+        maybeScheduleConntrackTimeoutUpdate();
 
         mLog.i("Polling started");
     }
@@ -452,8 +452,8 @@
         if (!mPollingStarted) return;
 
         // Stop scheduled polling conntrack timeout.
-        if (mHandler.hasCallbacks(mScheduledPollingConntrackTimeout)) {
-            mHandler.removeCallbacks(mScheduledPollingConntrackTimeout);
+        if (mHandler.hasCallbacks(mScheduledConntrackTimeoutUpdate)) {
+            mHandler.removeCallbacks(mScheduledConntrackTimeoutUpdate);
         }
         // Stop scheduled polling stats and poll the latest stats from BPF maps.
         if (mHandler.hasCallbacks(mScheduledPollingStats)) {
@@ -1057,6 +1057,15 @@
         }
     }
 
+    private String l4protoToString(int proto) {
+        if (proto == OsConstants.IPPROTO_TCP) {
+            return "tcp";
+        } else if (proto == OsConstants.IPPROTO_UDP) {
+            return "udp";
+        }
+        return String.format("unknown(%d)", proto);
+    }
+
     private String ipv4RuleToString(long now, boolean downstream,
             Tether4Key key, Tether4Value value) {
         final String src4, public4, dst4;
@@ -1075,12 +1084,11 @@
             throw new AssertionError("IP address array not valid IPv4 address!");
         }
 
-        final String protoStr = (key.l4proto == OsConstants.IPPROTO_TCP) ? "tcp" : "udp";
         final String ageStr = (value.lastUsed == 0) ? "-"
                 : String.format("%dms", (now - value.lastUsed) / 1_000_000);
         return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %s",
-                protoStr, key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort,
-                value.oif, getIfName(value.oif),
+                l4protoToString(key.l4proto), key.dstMac, key.iif, getIfName(key.iif),
+                src4, key.srcPort, value.oif, getIfName(value.oif),
                 public4, publicPort, dst4, value.dstPort, value.ethDstMac, ageStr);
     }
 
@@ -1449,25 +1457,6 @@
         return addr6;
     }
 
-    @Nullable
-    private Inet4Address ipv4MappedAddressBytesToIpv4Address(final byte[] addr46) {
-        if (addr46.length != 16) return null;
-        if (addr46[0] != 0 || addr46[1] != 0 || addr46[2] != 0 || addr46[3] != 0
-                || addr46[4] != 0 || addr46[5] != 0 || addr46[6] != 0 || addr46[7] != 0
-                || addr46[8] != 0 && addr46[9] != 0 || (addr46[10] & 0xff) != 0xff
-                || (addr46[11] & 0xff) != 0xff) {
-            return null;
-        }
-
-        final byte[] addr4 = new byte[4];
-        addr4[0] = addr46[12];
-        addr4[1] = addr46[13];
-        addr4[2] = addr46[14];
-        addr4[3] = addr46[15];
-
-        return parseIPv4Address(addr4);
-    }
-
     // TODO: parse CTA_PROTOINFO of conntrack event in ConntrackMonitor. For TCP, only add rules
     // while TCP status is established.
     @VisibleForTesting
@@ -1867,7 +1856,7 @@
         try {
             final InetAddress ia = Inet4Address.getByAddress(addrBytes);
             if (ia instanceof Inet4Address) return (Inet4Address) ia;
-        } catch (UnknownHostException | IllegalArgumentException e) {
+        } catch (UnknownHostException e) {
             mLog.e("Failed to parse IPv4 address: " + e);
         }
         return null;
@@ -1877,7 +1866,15 @@
     // coming a conntrack event to notify updated timeout.
     private void updateConntrackTimeout(byte proto, Inet4Address src4, short srcPort,
             Inet4Address dst4, short dstPort) {
-        if (src4 == null || dst4 == null) return;
+        if (src4 == null || dst4 == null) {
+            mLog.e("Either source or destination IPv4 address is invalid ("
+                    + "proto: " + proto + ", "
+                    + "src4: " + src4 + ", "
+                    + "srcPort: " + Short.toUnsignedInt(srcPort) + ", "
+                    + "dst4: " + dst4 + ", "
+                    + "dstPort: " + Short.toUnsignedInt(dstPort) + ")");
+            return;
+        }
 
         // TODO: consider acquiring the timeout setting from nf_conntrack_* variables.
         // - proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
@@ -1891,38 +1888,50 @@
         try {
             NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg);
         } catch (ErrnoException e) {
-            mLog.e("Error updating conntrack entry ("
+            // Lower the log level for the entry not existing. The conntrack entry may have been
+            // deleted and not handled by the conntrack event monitor yet. In other words, the
+            // rule has not been deleted from the BPF map yet. Deleting a non-existent entry may
+            // happen during the conntrack timeout refreshing iteration. Note that ENOENT may be
+            // a real error but is hard to distinguish.
+            // TODO: Figure out a better way to handle this.
+            final String errMsg = "Failed to update conntrack entry ("
                     + "proto: " + proto + ", "
                     + "src4: " + src4 + ", "
                     + "srcPort: " + Short.toUnsignedInt(srcPort) + ", "
                     + "dst4: " + dst4 + ", "
                     + "dstPort: " + Short.toUnsignedInt(dstPort) + "), "
                     + "msg: " + NetlinkConstants.hexify(msg) + ", "
-                    + "e: " + e);
+                    + "e: " + e;
+            if (OsConstants.ENOENT == e.errno) {
+                mLog.w(errMsg);
+            } else {
+                mLog.e(errMsg);
+            }
         }
     }
 
-    private void maybeRefreshConntrackTimeout() {
+    private void refreshAllConntrackTimeouts() {
         final long now = mDeps.elapsedRealtimeNanos();
 
-        // Reverse the source and destination {address, port} from downstream value because
-        // #updateConntrackTimeout refresh the timeout of netlink attribute CTA_TUPLE_ORIG
-        // which is opposite direction for downstream map value.
-        mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
-            if ((now - v.lastUsed) / 1_000_000 < POLLING_CONNTRACK_TIMEOUT_MS) {
-                updateConntrackTimeout((byte) k.l4proto,
-                        ipv4MappedAddressBytesToIpv4Address(v.dst46), (short) v.dstPort,
-                        ipv4MappedAddressBytesToIpv4Address(v.src46), (short) v.srcPort);
-            }
-        });
-
         // TODO: Consider ignoring TCP traffic on upstream and monitor on downstream only
         // because TCP is a bidirectional traffic. Probably don't need to extend timeout by
         // both directions for TCP.
         mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
-            if ((now - v.lastUsed) / 1_000_000 < POLLING_CONNTRACK_TIMEOUT_MS) {
-                updateConntrackTimeout((byte) k.l4proto, parseIPv4Address(k.src4),
-                        (short) k.srcPort, parseIPv4Address(k.dst4), (short) k.dstPort);
+            if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
+                updateConntrackTimeout((byte) k.l4proto,
+                        parseIPv4Address(k.src4), (short) k.srcPort,
+                        parseIPv4Address(k.dst4), (short) k.dstPort);
+            }
+        });
+
+        // Reverse the source and destination {address, port} from downstream value because
+        // #updateConntrackTimeout refresh the timeout of netlink attribute CTA_TUPLE_ORIG
+        // which is opposite direction for downstream map value.
+        mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
+            if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
+                updateConntrackTimeout((byte) k.l4proto,
+                        parseIPv4Address(v.dst46), (short) v.dstPort,
+                        parseIPv4Address(v.src46), (short) v.srcPort);
             }
         });
     }
@@ -1937,14 +1946,15 @@
         mHandler.postDelayed(mScheduledPollingStats, getPollingInterval());
     }
 
-    private void maybeSchedulePollingConntrackTimeout() {
+    private void maybeScheduleConntrackTimeoutUpdate() {
         if (!mPollingStarted) return;
 
-        if (mHandler.hasCallbacks(mScheduledPollingConntrackTimeout)) {
-            mHandler.removeCallbacks(mScheduledPollingConntrackTimeout);
+        if (mHandler.hasCallbacks(mScheduledConntrackTimeoutUpdate)) {
+            mHandler.removeCallbacks(mScheduledConntrackTimeoutUpdate);
         }
 
-        mHandler.postDelayed(mScheduledPollingConntrackTimeout, POLLING_CONNTRACK_TIMEOUT_MS);
+        mHandler.postDelayed(mScheduledConntrackTimeoutUpdate,
+                CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
     }
 
     // Return forwarding rule map. This is used for testing only.
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index c39fe3e..08170f9 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -2354,6 +2354,9 @@
         pw.println("Tethering:");
         pw.increaseIndent();
 
+        pw.println("Callbacks registered: "
+                + mTetheringEventCallbacks.getRegisteredCallbackCount());
+
         pw.println("Configuration:");
         pw.increaseIndent();
         final TetheringConfiguration cfg = mConfig;
diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
index 69471a1..5584db2 100644
--- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -49,7 +49,6 @@
 import com.android.internal.util.StateMachine;
 import com.android.networkstack.apishim.ConnectivityManagerShimImpl;
 import com.android.networkstack.apishim.common.ConnectivityManagerShim;
-import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -162,12 +161,7 @@
         }
         ConnectivityManagerShim mCmShim = ConnectivityManagerShimImpl.newInstance(mContext);
         mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
-        try {
-            mCmShim.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
-        } catch (UnsupportedApiLevelException e) {
-            Log.wtf(TAG, "registerSystemDefaultNetworkCallback is not supported");
-            return;
-        }
+        mCmShim.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
         if (mEntitlementMgr == null) {
             mEntitlementMgr = entitle;
         }
diff --git a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
index a933e1b..23d9055 100644
--- a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
+++ b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
@@ -31,6 +31,7 @@
 import android.net.MacAddress;
 import android.net.util.InterfaceParams;
 import android.net.util.TetheringUtils;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -38,8 +39,9 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
 import com.android.testutils.TapPacketReader;
 import com.android.testutils.TapPacketReaderRule;
 
@@ -54,7 +56,8 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(DevSdkIgnoreRunner.class)
+@IgnoreUpTo(Build.VERSION_CODES.R)
 @SmallTest
 public class DadProxyTest {
     private static final int DATA_BUFFER_LEN = 4096;
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
index 830729d..0deb177 100644
--- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
+++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
@@ -31,9 +31,8 @@
 import android.system.OsConstants;
 import android.util.ArrayMap;
 
-import androidx.test.runner.AndroidJUnit4;
-
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
 
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -45,7 +44,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(DevSdkIgnoreRunner.class)
 @IgnoreUpTo(Build.VERSION_CODES.R)
 public final class BpfMapTest {
     // Sync from packages/modules/Connectivity/Tethering/bpf_progs/offload.c.
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index 436a436..7e9e34f 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -40,9 +40,9 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker;
+import static com.android.networkstack.tethering.BpfCoordinator.CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS;
 import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED;
 import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_UDP_TIMEOUT_STREAM;
-import static com.android.networkstack.tethering.BpfCoordinator.POLLING_CONNTRACK_TIMEOUT_MS;
 import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
 import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
 import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID;
@@ -1544,14 +1544,14 @@
         // Timeline:
         // 0                                       60 (seconds)
         // +---+---+---+---+--...--+---+---+---+---+---+- ..
-        // |      POLLING_CONNTRACK_TIMEOUT_MS     |
+        // | CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS  |
         // +---+---+---+---+--...--+---+---+---+---+---+- ..
         // |<-          valid diff           ->|
         // |<-          expired diff                 ->|
         // ^                                   ^       ^
         // last used time      elapsed time (valid)    elapsed time (expired)
-        final long validTime = (POLLING_CONNTRACK_TIMEOUT_MS - 1) * 1_000_000L;
-        final long expiredTime = (POLLING_CONNTRACK_TIMEOUT_MS + 1) * 1_000_000L;
+        final long validTime = (CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS - 1) * 1_000_000L;
+        final long expiredTime = (CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS + 1) * 1_000_000L;
 
         // Static mocking for NetlinkSocket.
         MockitoSession mockSession = ExtendedMockito.mockitoSession()
@@ -1565,14 +1565,14 @@
 
             // [1] Don't refresh contrack timeout.
             setElapsedRealtimeNanos(expiredTime);
-            mTestLooper.moveTimeForward(POLLING_CONNTRACK_TIMEOUT_MS);
+            mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
             waitForIdle();
             ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class));
             ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class));
 
             // [2] Refresh contrack timeout.
             setElapsedRealtimeNanos(validTime);
-            mTestLooper.moveTimeForward(POLLING_CONNTRACK_TIMEOUT_MS);
+            mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
             waitForIdle();
             final byte[] expectedNetlinkTcp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
                     IPPROTO_TCP, PRIVATE_ADDR, (int) PRIVATE_PORT, REMOTE_ADDR,
@@ -1589,7 +1589,7 @@
 
             // [3] Don't refresh contrack timeout if polling stopped.
             coordinator.stopPolling();
-            mTestLooper.moveTimeForward(POLLING_CONNTRACK_TIMEOUT_MS);
+            mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
             waitForIdle();
             ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class));
             ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class));
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
index 071a290..4865e03 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
@@ -25,12 +25,14 @@
 import android.net.ITetheringConnector;
 import android.os.Binder;
 import android.os.IBinder;
+import android.util.ArrayMap;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 public class MockTetheringService extends TetheringService {
     private final Tethering mTethering = mock(Tethering.class);
+    private final ArrayMap<String, Integer> mMockedPermissions = new ArrayMap<>();
 
     @Override
     public IBinder onBind(Intent intent) {
@@ -51,6 +53,15 @@
         return context.checkCallingOrSelfPermission(WRITE_SETTINGS) == PERMISSION_GRANTED;
     }
 
+    @Override
+    public int checkCallingOrSelfPermission(String permission) {
+        final Integer mocked = mMockedPermissions.getOrDefault(permission, null);
+        if (mocked != null) {
+            return mocked;
+        }
+        return super.checkCallingOrSelfPermission(permission);
+    }
+
     public Tethering getTethering() {
         return mTethering;
     }
@@ -68,5 +79,18 @@
         public MockTetheringService getService() {
             return MockTetheringService.this;
         }
+
+        /**
+         * Mock a permission
+         * @param permission Permission to mock
+         * @param granted One of PackageManager.PERMISSION_*, or null to reset to default behavior
+         */
+        public void setPermission(String permission, Integer granted) {
+            if (granted == null) {
+                mMockedPermissions.remove(permission);
+            } else {
+                mMockedPermissions.put(permission, granted);
+            }
+        }
     }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
index d800816..fc34585 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
@@ -26,6 +26,7 @@
 import static android.net.RouteInfo.RTN_UNICAST;
 import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
 
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
 import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE;
 import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID;
 import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
@@ -66,6 +67,7 @@
 import android.net.RouteInfo;
 import android.net.netstats.provider.NetworkStatsProvider;
 import android.net.util.SharedLog;
+import android.os.Build;
 import android.os.Handler;
 import android.os.test.TestLooper;
 import android.provider.Settings;
@@ -76,10 +78,13 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 import com.android.testutils.TestableNetworkStatsProviderCbBinder;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -95,6 +100,9 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class OffloadControllerTest {
+    @Rule
+    public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
     private static final String RNDIS0 = "test_rndis0";
     private static final String RMNET0 = "test_rmnet_data0";
     private static final String WLAN0 = "test_wlan0";
@@ -511,8 +519,8 @@
     public void testSetDataWarningAndLimit() throws Exception {
         // Verify the OffloadController is called by R framework, where the framework doesn't send
         // warning.
+        // R only uses HAL 1.0.
         checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_1_0);
-        checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_1_1);
         // Verify the OffloadController is called by S+ framework, where the framework sends
         // warning along with limit.
         checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_1_0);
@@ -650,17 +658,26 @@
     }
 
     @Test
-    public void testDataWarningAndLimitCallback() throws Exception {
+    public void testDataWarningAndLimitCallback_LimitReached() throws Exception {
         enableOffload();
         startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
 
-        OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
+        final OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
         callback.onStoppedLimitReached();
         mTetherStatsProviderCb.expectNotifyStatsUpdated();
-        mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
 
+        if (isAtLeastS()) {
+            mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
+        } else {
+            mTetherStatsProviderCb.expectLegacyNotifyLimitReached();
+        }
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.R)  // HAL 1.1 is only supported from S
+    public void testDataWarningAndLimitCallback_WarningReached() throws Exception {
         startOffloadController(OFFLOAD_HAL_VERSION_1_1, true /*expectStart*/);
-        callback = mControlCallbackCaptor.getValue();
+        final OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
         callback.onWarningReached();
         mTetherStatsProviderCb.expectNotifyStatsUpdated();
         mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
index b8389ea..e692015 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
@@ -20,6 +20,8 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 
+import static com.android.networkstack.apishim.common.ShimUtils.isAtLeastS;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
@@ -68,10 +70,10 @@
     public static final boolean BROADCAST_FIRST = false;
     public static final boolean CALLBACKS_FIRST = true;
 
-    final Map<NetworkCallback, NetworkCallbackInfo> mAllCallbacks = new ArrayMap<>();
+    final Map<NetworkCallback, Handler> mAllCallbacks = new ArrayMap<>();
     // This contains the callbacks tracking the system default network, whether it's registered
     // with registerSystemDefaultNetworkCallback (S+) or with a custom request (R-).
-    final Map<NetworkCallback, NetworkCallbackInfo> mTrackingDefault = new ArrayMap<>();
+    final Map<NetworkCallback, Handler> mTrackingDefault = new ArrayMap<>();
     final Map<NetworkCallback, NetworkRequestInfo> mListening = new ArrayMap<>();
     final Map<NetworkCallback, NetworkRequestInfo> mRequested = new ArrayMap<>();
     final Map<NetworkCallback, Integer> mLegacyTypeMap = new ArrayMap<>();
@@ -92,18 +94,12 @@
         mContext = ctx;
     }
 
-    static class NetworkCallbackInfo {
-        public final Handler handler;
-        NetworkCallbackInfo(Handler h) {
-            handler = h;
-        }
-    }
-
-    static class NetworkRequestInfo extends NetworkCallbackInfo {
+    static class NetworkRequestInfo {
         public final NetworkRequest request;
+        public final Handler handler;
         NetworkRequestInfo(NetworkRequest r, Handler h) {
-            super(h);
             request = r;
+            handler = h;
         }
     }
 
@@ -152,15 +148,15 @@
     private void sendDefaultNetworkCallbacks(TestNetworkAgent formerDefault,
             TestNetworkAgent defaultNetwork) {
         for (NetworkCallback cb : mTrackingDefault.keySet()) {
-            final NetworkCallbackInfo nri = mTrackingDefault.get(cb);
+            final Handler handler = mTrackingDefault.get(cb);
             if (defaultNetwork != null) {
-                nri.handler.post(() -> cb.onAvailable(defaultNetwork.networkId));
-                nri.handler.post(() -> cb.onCapabilitiesChanged(
+                handler.post(() -> cb.onAvailable(defaultNetwork.networkId));
+                handler.post(() -> cb.onCapabilitiesChanged(
                         defaultNetwork.networkId, defaultNetwork.networkCapabilities));
-                nri.handler.post(() -> cb.onLinkPropertiesChanged(
+                handler.post(() -> cb.onLinkPropertiesChanged(
                         defaultNetwork.networkId, defaultNetwork.linkProperties));
             } else if (formerDefault != null) {
-                nri.handler.post(() -> cb.onLost(formerDefault.networkId));
+                handler.post(() -> cb.onLost(formerDefault.networkId));
             }
         }
     }
@@ -201,10 +197,11 @@
         // For R- devices, Tethering will invoke this function in 2 cases, one is to request mobile
         // network, the other is to track system default network.
         if (looksLikeDefaultRequest(req)) {
-            registerSystemDefaultNetworkCallback(cb, h);
+            assertFalse(isAtLeastS());
+            addTrackDefaultCallback(cb, h);
         } else {
             assertFalse(mAllCallbacks.containsKey(cb));
-            mAllCallbacks.put(cb, new NetworkRequestInfo(req, h));
+            mAllCallbacks.put(cb, h);
             assertFalse(mRequested.containsKey(cb));
             mRequested.put(cb, new NetworkRequestInfo(req, h));
         }
@@ -213,10 +210,14 @@
     @Override
     public void registerSystemDefaultNetworkCallback(
             @NonNull NetworkCallback cb, @NonNull Handler h) {
+        addTrackDefaultCallback(cb, h);
+    }
+
+    private void addTrackDefaultCallback(@NonNull NetworkCallback cb, @NonNull Handler h) {
         assertFalse(mAllCallbacks.containsKey(cb));
-        mAllCallbacks.put(cb, new NetworkCallbackInfo(h));
+        mAllCallbacks.put(cb, h);
         assertFalse(mTrackingDefault.containsKey(cb));
-        mTrackingDefault.put(cb, new NetworkCallbackInfo(h));
+        mTrackingDefault.put(cb, h);
     }
 
     @Override
@@ -230,7 +231,7 @@
         assertFalse(mAllCallbacks.containsKey(cb));
         NetworkRequest newReq = new NetworkRequest(req.networkCapabilities, legacyType,
                 -1 /** testId */, req.type);
-        mAllCallbacks.put(cb, new NetworkRequestInfo(newReq, h));
+        mAllCallbacks.put(cb, h);
         assertFalse(mRequested.containsKey(cb));
         mRequested.put(cb, new NetworkRequestInfo(newReq, h));
         assertFalse(mLegacyTypeMap.containsKey(cb));
@@ -242,7 +243,7 @@
     @Override
     public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
         assertFalse(mAllCallbacks.containsKey(cb));
-        mAllCallbacks.put(cb, new NetworkRequestInfo(req, h));
+        mAllCallbacks.put(cb, h);
         assertFalse(mListening.containsKey(cb));
         mListening.put(cb, new NetworkRequestInfo(req, h));
     }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 941cd78..1b52f6e 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
 import static android.Manifest.permission.TETHER_PRIVILEGED;
 import static android.Manifest.permission.WRITE_SETTINGS;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
@@ -50,6 +51,7 @@
 import androidx.test.rule.ServiceTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.net.module.util.CollectionUtils;
 import com.android.networkstack.tethering.MockTetheringService.MockTetheringConnector;
 
 import org.junit.After;
@@ -70,6 +72,7 @@
     @Rule public ServiceTestRule mServiceTestRule;
     private Tethering mTethering;
     private Intent mMockServiceIntent;
+    private MockTetheringConnector mMockConnector;
     private ITetheringConnector mTetheringConnector;
     private UiAutomation mUiAutomation;
 
@@ -109,10 +112,9 @@
         mMockServiceIntent = new Intent(
                 InstrumentationRegistry.getTargetContext(),
                 MockTetheringService.class);
-        final MockTetheringConnector mockConnector =
-                (MockTetheringConnector) mServiceTestRule.bindService(mMockServiceIntent);
-        mTetheringConnector = mockConnector.getTetheringConnector();
-        final MockTetheringService service = mockConnector.getService();
+        mMockConnector = (MockTetheringConnector) mServiceTestRule.bindService(mMockServiceIntent);
+        mTetheringConnector = mMockConnector.getTetheringConnector();
+        final MockTetheringService service = mMockConnector.getService();
         mTethering = service.getTethering();
     }
 
@@ -144,12 +146,18 @@
 
     private void runTetheringCall(final TestTetheringCall test, String... permissions)
             throws Exception {
+        // Allow the test to run even if ACCESS_NETWORK_STATE was granted at the APK level
+        if (!CollectionUtils.contains(permissions, ACCESS_NETWORK_STATE)) {
+            mMockConnector.setPermission(ACCESS_NETWORK_STATE, PERMISSION_DENIED);
+        }
+
         if (permissions.length > 0) mUiAutomation.adoptShellPermissionIdentity(permissions);
         try {
             when(mTethering.isTetheringSupported()).thenReturn(true);
             test.runTetheringCall(new TestTetheringResult());
         } finally {
             mUiAutomation.dropShellPermissionIdentity();
+            mMockConnector.setPermission(ACCESS_NETWORK_STATE, null);
         }
     }
 
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index f999dfa..f45768f 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -178,10 +178,10 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.net.module.util.CollectionUtils;
 import com.android.networkstack.tethering.TestConnectivityManager.TestNetworkAgent;
 import com.android.testutils.MiscAsserts;
 
@@ -365,7 +365,8 @@
             final String[] ifaces = new String[] {
                     TEST_RNDIS_IFNAME, TEST_WLAN_IFNAME, TEST_WIFI_IFNAME, TEST_MOBILE_IFNAME,
                     TEST_DUN_IFNAME, TEST_P2P_IFNAME, TEST_NCM_IFNAME, TEST_ETH_IFNAME};
-            return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
+            return new InterfaceParams(ifName,
+                    CollectionUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
                     MacAddress.ALL_ZEROS_ADDRESS);
         }
 
diff --git a/framework/src/android/net/util/MultinetworkPolicyTracker.java b/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 9791cbf..3e7cb80 100644
--- a/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -180,7 +180,7 @@
      * The value works when the time set is more than {@link System.currentTimeMillis()}.
      */
     public void setTestAllowBadWifiUntil(long timeMs) {
-        Log.d(TAG, "setTestAllowBadWifiUntil: " + mTestAllowBadWifiUntilMs);
+        Log.d(TAG, "setTestAllowBadWifiUntil: " + timeMs);
         mTestAllowBadWifiUntilMs = timeMs;
         reevaluateInternal();
     }
diff --git a/service/Android.bp b/service/Android.bp
index 7fe0e2b..abaeeb3 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -53,8 +53,8 @@
         "src/**/*.java",
         ":framework-connectivity-shared-srcs",
         ":services-connectivity-shared-srcs",
-        // TODO: move to net-utils-device-common, enable shrink optimization to avoid extra classes
-        ":net-module-utils-srcs",
+        // TODO: move to net-utils-device-common
+        ":connectivity-module-utils-srcs",
     ],
     libs: [
         "framework-annotations-lib",
@@ -66,6 +66,7 @@
     ],
     static_libs: [
         "dnsresolver_aidl_interface-V8-java",
+        "modules-utils-build",
         "modules-utils-os",
         "net-utils-device-common",
         "net-utils-framework-common",
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index 2cd0220..4ba6837 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -2,12 +2,17 @@
 rule com.android.net.module.util.** com.android.connectivity.@0
 rule com.android.modules.utils.** com.android.connectivity.@0
 
-# internal util classes
+# internal util classes from framework-connectivity-shared-srcs
 rule android.util.LocalLog* com.android.connectivity.@0
 # android.util.IndentingPrintWriter* should use a different package name from
 # the one in com.android.internal.util
 rule android.util.IndentingPrintWriter* com.android.connectivity.@0
-rule com.android.internal.util.** com.android.connectivity.@0
+rule com.android.internal.util.IndentingPrintWriter* com.android.connectivity.@0
+rule com.android.internal.util.IState* com.android.connectivity.@0
+rule com.android.internal.util.MessageUtils* com.android.connectivity.@0
+rule com.android.internal.util.State* com.android.connectivity.@0
+rule com.android.internal.util.StateMachine* com.android.connectivity.@0
+rule com.android.internal.util.WakeupMessage* com.android.connectivity.@0
 
 rule com.android.internal.messages.** com.android.connectivity.@0
 rule com.google.protobuf.** com.android.connectivity.@0
@@ -26,7 +31,10 @@
 
 # From netd-client (newer AIDLs should go to android.net.netd.aidl)
 rule android.net.netd.aidl.** com.android.connectivity.@0
-rule android.net.INetd* com.android.connectivity.@0
+# Avoid including android.net.INetdEventCallback, used in tests but not part of the module
+rule android.net.INetd com.android.connectivity.@0
+rule android.net.INetd$* com.android.connectivity.@0
+rule android.net.INetdUnsolicitedEventListener* com.android.connectivity.@0
 rule android.net.InterfaceConfigurationParcel* com.android.connectivity.@0
 rule android.net.MarkMaskParcel* com.android.connectivity.@0
 rule android.net.NativeNetworkConfig* com.android.connectivity.@0
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index c8a0b7f..b126791 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -56,6 +56,7 @@
 import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_SKIPPED;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
@@ -403,44 +404,44 @@
 
     /**
      * For per-app preferences, requests contain an int to signify which request
-     * should have priority. The priority is passed to netd which will use it
-     * together with UID ranges to generate the corresponding IP rule. This serves
-     * to direct device-originated data traffic of the specific UIDs to the correct
+     * should have priority. The order is passed to netd which will use it together
+     * with UID ranges to generate the corresponding IP rule. This serves to
+     * direct device-originated data traffic of the specific UIDs to the correct
      * default network for each app.
-     * Priorities passed to netd must be in the 0~999 range. Larger values code for
+     * Order ints passed to netd must be in the 0~999 range. Larger values code for
      * a lower priority, {@see NativeUidRangeConfig}
      *
-     * Requests that don't code for a per-app preference use PREFERENCE_PRIORITY_INVALID.
-     * The default request uses PREFERENCE_PRIORITY_DEFAULT.
+     * Requests that don't code for a per-app preference use PREFERENCE_ORDER_INVALID.
+     * The default request uses PREFERENCE_ORDER_DEFAULT.
      */
-    // Bound for the lowest valid priority.
-    static final int PREFERENCE_PRIORITY_LOWEST = 999;
-    // Used when sending to netd to code for "no priority".
-    static final int PREFERENCE_PRIORITY_NONE = 0;
-    // Priority for requests that don't code for a per-app preference. As it is
-    // out of the valid range, the corresponding priority should be
-    // PREFERENCE_PRIORITY_NONE when sending to netd.
+    // Bound for the lowest valid preference order.
+    static final int PREFERENCE_ORDER_LOWEST = 999;
+    // Used when sending to netd to code for "no order".
+    static final int PREFERENCE_ORDER_NONE = 0;
+    // Order for requests that don't code for a per-app preference. As it is
+    // out of the valid range, the corresponding order should be
+    // PREFERENCE_ORDER_NONE when sending to netd.
     @VisibleForTesting
-    static final int PREFERENCE_PRIORITY_INVALID = Integer.MAX_VALUE;
-    // Priority for the default internet request. Since this must always have the
+    static final int PREFERENCE_ORDER_INVALID = Integer.MAX_VALUE;
+    // Order for the default internet request. Since this must always have the
     // lowest priority, its value is larger than the largest acceptable value. As
-    // it is out of the valid range, the corresponding priority should be
-    // PREFERENCE_PRIORITY_NONE when sending to netd.
-    static final int PREFERENCE_PRIORITY_DEFAULT = 1000;
+    // it is out of the valid range, the corresponding order should be
+    // PREFERENCE_ORDER_NONE when sending to netd.
+    static final int PREFERENCE_ORDER_DEFAULT = 1000;
     // As a security feature, VPNs have the top priority.
-    static final int PREFERENCE_PRIORITY_VPN = 0; // Netd supports only 0 for VPN.
-    // Priority of per-app OEM preference. See {@link #setOemNetworkPreference}.
+    static final int PREFERENCE_ORDER_VPN = 0; // Netd supports only 0 for VPN.
+    // Order of per-app OEM preference. See {@link #setOemNetworkPreference}.
     @VisibleForTesting
-    static final int PREFERENCE_PRIORITY_OEM = 10;
-    // Priority of per-profile preference, such as used by enterprise networks.
+    static final int PREFERENCE_ORDER_OEM = 10;
+    // Order of per-profile preference, such as used by enterprise networks.
     // See {@link #setProfileNetworkPreference}.
     @VisibleForTesting
-    static final int PREFERENCE_PRIORITY_PROFILE = 20;
-    // Priority of user setting to prefer mobile data even when networks with
+    static final int PREFERENCE_ORDER_PROFILE = 20;
+    // Order of user setting to prefer mobile data even when networks with
     // better scores are connected.
     // See {@link ConnectivitySettingsManager#setMobileDataPreferredUids}
     @VisibleForTesting
-    static final int PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED = 30;
+    static final int PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED = 30;
 
     /**
      * used internally to clear a wakelock when transitioning
@@ -558,9 +559,9 @@
     private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
 
     /**
-     * used to trigger revalidation of a network.
+     * used to handle reported network connectivity. May trigger revalidation of a network.
      */
-    private static final int EVENT_REVALIDATE_NETWORK = 36;
+    private static final int EVENT_REPORT_NETWORK_CONNECTIVITY = 36;
 
     // Handle changes in Private DNS settings.
     private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37;
@@ -3169,7 +3170,18 @@
     }
 
     private void dumpNetworkRequests(IndentingPrintWriter pw) {
-        for (NetworkRequestInfo nri : requestsSortedById()) {
+        NetworkRequestInfo[] infos = null;
+        while (infos == null) {
+            try {
+                infos = requestsSortedById();
+            } catch (ConcurrentModificationException e) {
+                // mNetworkRequests should only be accessed from handler thread, except dump().
+                // As dump() is never called in normal usage, it would be needlessly expensive
+                // to lock the collection only for its benefit. Instead, retry getting the
+                // requests if ConcurrentModificationException is thrown during dump().
+            }
+        }
+        for (NetworkRequestInfo nri : infos) {
             pw.println(nri.toString());
         }
     }
@@ -3560,8 +3572,14 @@
             final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(mNetId);
             if (nai == null) return;
 
+            // NetworkMonitor reports the network validation result as a bitmask while
+            // ConnectivityDiagnostics treats this value as an int. Convert the result to a single
+            // logical value for ConnectivityDiagnostics.
+            final int validationResult = networkMonitorValidationResultToConnDiagsValidationResult(
+                    p.result);
+
             final PersistableBundle extras = new PersistableBundle();
-            extras.putInt(KEY_NETWORK_VALIDATION_RESULT, p.result);
+            extras.putInt(KEY_NETWORK_VALIDATION_RESULT, validationResult);
             extras.putInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, p.probesSucceeded);
             extras.putInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK, p.probesAttempted);
 
@@ -3637,6 +3655,22 @@
         }
     }
 
+    /**
+     * Converts the given NetworkMonitor-specific validation result bitmask to a
+     * ConnectivityDiagnostics-specific validation result int.
+     */
+    private int networkMonitorValidationResultToConnDiagsValidationResult(int validationResult) {
+        if ((validationResult & NETWORK_VALIDATION_RESULT_SKIPPED) != 0) {
+            return ConnectivityReport.NETWORK_VALIDATION_RESULT_SKIPPED;
+        }
+        if ((validationResult & NETWORK_VALIDATION_RESULT_VALID) == 0) {
+            return ConnectivityReport.NETWORK_VALIDATION_RESULT_INVALID;
+        }
+        return (validationResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0
+                ? ConnectivityReport.NETWORK_VALIDATION_RESULT_PARTIALLY_VALID
+                : ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID;
+    }
+
     private void notifyDataStallSuspected(DataStallReportParcelable p, int netId) {
         log("Data stall detected with methods: " + p.detectionMethod);
 
@@ -4230,7 +4264,7 @@
                     mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                             satisfier.network.getNetId(),
                             toUidRangeStableParcels(nri.getUids()),
-                            nri.getPriorityForNetd()));
+                            nri.getPreferenceOrderForNetd()));
                 } catch (RemoteException e) {
                     loge("Exception setting network preference default network", e);
                 }
@@ -4889,8 +4923,9 @@
                     mKeepaliveTracker.handleStopKeepalive(nai, slot, reason);
                     break;
                 }
-                case EVENT_REVALIDATE_NETWORK: {
-                    handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2));
+                case EVENT_REPORT_NETWORK_CONNECTIVITY: {
+                    handleReportNetworkConnectivity((NetworkAgentInfo) msg.obj, msg.arg1,
+                            toBool(msg.arg2));
                     break;
                 }
                 case EVENT_PRIVATE_DNS_SETTINGS_CHANGED:
@@ -5053,41 +5088,32 @@
         final int uid = mDeps.getCallingUid();
         final int connectivityInfo = encodeBool(hasConnectivity);
 
-        // Handle ConnectivityDiagnostics event before attempting to revalidate the network. This
-        // forces an ordering of ConnectivityDiagnostics events in the case where hasConnectivity
-        // does not match the known connectivity of the network - this causes NetworkMonitor to
-        // revalidate the network and generate a ConnectivityDiagnostics ConnectivityReport event.
         final NetworkAgentInfo nai;
         if (network == null) {
             nai = getDefaultNetwork();
         } else {
             nai = getNetworkAgentInfoForNetwork(network);
         }
-        if (nai != null) {
-            mConnectivityDiagnosticsHandler.sendMessage(
-                    mConnectivityDiagnosticsHandler.obtainMessage(
-                            ConnectivityDiagnosticsHandler.EVENT_NETWORK_CONNECTIVITY_REPORTED,
-                            connectivityInfo, 0, nai));
-        }
 
         mHandler.sendMessage(
-                mHandler.obtainMessage(EVENT_REVALIDATE_NETWORK, uid, connectivityInfo, network));
+                mHandler.obtainMessage(
+                        EVENT_REPORT_NETWORK_CONNECTIVITY, uid, connectivityInfo, nai));
     }
 
     private void handleReportNetworkConnectivity(
-            Network network, int uid, boolean hasConnectivity) {
-        final NetworkAgentInfo nai;
-        if (network == null) {
-            nai = getDefaultNetwork();
-        } else {
-            nai = getNetworkAgentInfoForNetwork(network);
-        }
-        if (nai == null || nai.networkInfo.getState() == NetworkInfo.State.DISCONNECTING ||
-            nai.networkInfo.getState() == NetworkInfo.State.DISCONNECTED) {
+            @Nullable NetworkAgentInfo nai, int uid, boolean hasConnectivity) {
+        if (nai == null
+                || nai != getNetworkAgentInfoForNetwork(nai.network)
+                || nai.networkInfo.getState() == NetworkInfo.State.DISCONNECTED) {
             return;
         }
         // Revalidate if the app report does not match our current validated state.
         if (hasConnectivity == nai.lastValidated) {
+            mConnectivityDiagnosticsHandler.sendMessage(
+                    mConnectivityDiagnosticsHandler.obtainMessage(
+                            ConnectivityDiagnosticsHandler.EVENT_NETWORK_CONNECTIVITY_REPORTED,
+                            new ReportedNetworkConnectivityInfo(
+                                    hasConnectivity, false /* isNetworkRevalidating */, uid, nai)));
             return;
         }
         if (DBG) {
@@ -5103,6 +5129,16 @@
         if (isNetworkWithCapabilitiesBlocked(nc, uid, false)) {
             return;
         }
+
+        // Send CONNECTIVITY_REPORTED event before re-validating the Network to force an ordering of
+        // ConnDiags events. This ensures that #onNetworkConnectivityReported() will be called
+        // before #onConnectivityReportAvailable(), which is called once Network evaluation is
+        // completed.
+        mConnectivityDiagnosticsHandler.sendMessage(
+                mConnectivityDiagnosticsHandler.obtainMessage(
+                        ConnectivityDiagnosticsHandler.EVENT_NETWORK_CONNECTIVITY_REPORTED,
+                        new ReportedNetworkConnectivityInfo(
+                                hasConnectivity, true /* isNetworkRevalidating */, uid, nai)));
         nai.networkMonitor().forceReevaluation(uid);
     }
 
@@ -5695,8 +5731,8 @@
         // maximum limit of registered callbacks per UID.
         final int mAsUid;
 
-        // Default network priority of this request.
-        final int mPreferencePriority;
+        // Preference order of this request.
+        final int mPreferenceOrder;
 
         // In order to preserve the mapping of NetworkRequest-to-callback when apps register
         // callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
@@ -5728,12 +5764,12 @@
         NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
                 @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
             this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag,
-                    PREFERENCE_PRIORITY_INVALID);
+                    PREFERENCE_ORDER_INVALID);
         }
 
         NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
                 @NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
-                @Nullable String callingAttributionTag, final int preferencePriority) {
+                @Nullable String callingAttributionTag, final int preferenceOrder) {
             ensureAllNetworkRequestsHaveType(r);
             mRequests = initializeRequests(r);
             mNetworkRequestForCallback = requestForCallback;
@@ -5751,7 +5787,7 @@
              */
             mCallbackFlags = NetworkCallback.FLAG_NONE;
             mCallingAttributionTag = callingAttributionTag;
-            mPreferencePriority = preferencePriority;
+            mPreferenceOrder = preferenceOrder;
         }
 
         NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
@@ -5781,7 +5817,7 @@
             mPerUidCounter.incrementCountOrThrow(mUid);
             mCallbackFlags = callbackFlags;
             mCallingAttributionTag = callingAttributionTag;
-            mPreferencePriority = PREFERENCE_PRIORITY_INVALID;
+            mPreferenceOrder = PREFERENCE_ORDER_INVALID;
             linkDeathRecipient();
         }
 
@@ -5821,18 +5857,18 @@
             mPerUidCounter.incrementCountOrThrow(mUid);
             mCallbackFlags = nri.mCallbackFlags;
             mCallingAttributionTag = nri.mCallingAttributionTag;
-            mPreferencePriority = PREFERENCE_PRIORITY_INVALID;
+            mPreferenceOrder = PREFERENCE_ORDER_INVALID;
             linkDeathRecipient();
         }
 
         NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
-            this(asUid, Collections.singletonList(r), PREFERENCE_PRIORITY_INVALID);
+            this(asUid, Collections.singletonList(r), PREFERENCE_ORDER_INVALID);
         }
 
         NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
-                final int preferencePriority) {
+                final int preferenceOrder) {
             this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */,
-                    preferencePriority);
+                    preferenceOrder);
         }
 
         // True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -5873,17 +5909,17 @@
             }
         }
 
-        boolean hasHigherPriorityThan(@NonNull final NetworkRequestInfo target) {
-            // Compare two priorities, larger value means lower priority.
-            return mPreferencePriority < target.mPreferencePriority;
+        boolean hasHigherOrderThan(@NonNull final NetworkRequestInfo target) {
+            // Compare two preference orders.
+            return mPreferenceOrder < target.mPreferenceOrder;
         }
 
-        int getPriorityForNetd() {
-            if (mPreferencePriority >= PREFERENCE_PRIORITY_NONE
-                    && mPreferencePriority <= PREFERENCE_PRIORITY_LOWEST) {
-                return mPreferencePriority;
+        int getPreferenceOrderForNetd() {
+            if (mPreferenceOrder >= PREFERENCE_ORDER_NONE
+                    && mPreferenceOrder <= PREFERENCE_ORDER_LOWEST) {
+                return mPreferenceOrder;
             }
-            return PREFERENCE_PRIORITY_NONE;
+            return PREFERENCE_ORDER_NONE;
         }
 
         @Override
@@ -5909,7 +5945,7 @@
                     + " " + mRequests
                     + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
                     + " callback flags: " + mCallbackFlags
-                    + " priority: " + mPreferencePriority;
+                    + " order: " + mPreferenceOrder;
         }
     }
 
@@ -6501,7 +6537,7 @@
             // than one request and for multilayer, all requests will track the same uids.
             if (nri.mRequests.get(0).networkCapabilities.appliesToUid(uid)) {
                 // Find out the highest priority request.
-                if (nri.hasHigherPriorityThan(highestPriorityNri)) {
+                if (nri.hasHigherOrderThan(highestPriorityNri)) {
                     highestPriorityNri = nri;
                 }
             }
@@ -6646,7 +6682,7 @@
             }
             for (final UidRange range : uids) {
                 if (range.contains(uid)) {
-                    if (nri.hasHigherPriorityThan(highestPriorityNri)) {
+                    if (nri.hasHigherOrderThan(highestPriorityNri)) {
                         highestPriorityNri = nri;
                     }
                 }
@@ -7502,10 +7538,10 @@
         try {
             if (add) {
                 mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
-                        nai.network.netId, ranges, PREFERENCE_PRIORITY_VPN));
+                        nai.network.netId, ranges, PREFERENCE_ORDER_VPN));
             } else {
                 mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
-                        nai.network.netId, ranges, PREFERENCE_PRIORITY_VPN));
+                        nai.network.netId, ranges, PREFERENCE_ORDER_VPN));
             }
         } catch (Exception e) {
             loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges +
@@ -7850,13 +7886,13 @@
                 mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
                         newDefaultNetwork.network.getNetId(),
                         toUidRangeStableParcels(nri.getUids()),
-                        nri.getPriorityForNetd()));
+                        nri.getPreferenceOrderForNetd()));
             }
             if (null != oldDefaultNetwork) {
                 mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                         oldDefaultNetwork.network.getNetId(),
                         toUidRangeStableParcels(nri.getUids()),
-                        nri.getPriorityForNetd()));
+                        nri.getPreferenceOrderForNetd()));
             }
         } catch (RemoteException | ServiceSpecificException e) {
             loge("Exception setting app default network", e);
@@ -9063,8 +9099,7 @@
          * the platform. This event will invoke {@link
          * IConnectivityDiagnosticsCallback#onNetworkConnectivityReported} for permissioned
          * callbacks.
-         * obj = Network that was reported on
-         * arg1 = boolint for the quality reported
+         * obj = ReportedNetworkConnectivityInfo with info on reported Network connectivity.
          */
         private static final int EVENT_NETWORK_CONNECTIVITY_REPORTED = 5;
 
@@ -9102,7 +9137,7 @@
                     break;
                 }
                 case EVENT_NETWORK_CONNECTIVITY_REPORTED: {
-                    handleNetworkConnectivityReported((NetworkAgentInfo) msg.obj, toBool(msg.arg1));
+                    handleNetworkConnectivityReported((ReportedNetworkConnectivityInfo) msg.obj);
                     break;
                 }
                 default: {
@@ -9172,6 +9207,28 @@
         }
     }
 
+    /**
+     * Class used for sending info for a call to {@link #reportNetworkConnectivity()} to {@link
+     * ConnectivityDiagnosticsHandler}.
+     */
+    private static class ReportedNetworkConnectivityInfo {
+        public final boolean hasConnectivity;
+        public final boolean isNetworkRevalidating;
+        public final int reporterUid;
+        @NonNull public final NetworkAgentInfo nai;
+
+        private ReportedNetworkConnectivityInfo(
+                boolean hasConnectivity,
+                boolean isNetworkRevalidating,
+                int reporterUid,
+                @NonNull NetworkAgentInfo nai) {
+            this.hasConnectivity = hasConnectivity;
+            this.isNetworkRevalidating = isNetworkRevalidating;
+            this.reporterUid = reporterUid;
+            this.nai = nai;
+        }
+    }
+
     private void handleRegisterConnectivityDiagnosticsCallback(
             @NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) {
         ensureRunningOnConnectivityServiceThread();
@@ -9279,13 +9336,14 @@
                         networkCapabilities,
                         extras);
         nai.setConnectivityReport(report);
+
         final List<IConnectivityDiagnosticsCallback> results =
-                getMatchingPermissionedCallbacks(nai);
+                getMatchingPermissionedCallbacks(nai, Process.INVALID_UID);
         for (final IConnectivityDiagnosticsCallback cb : results) {
             try {
                 cb.onConnectivityReportAvailable(report);
             } catch (RemoteException ex) {
-                loge("Error invoking onConnectivityReport", ex);
+                loge("Error invoking onConnectivityReportAvailable", ex);
             }
         }
     }
@@ -9304,7 +9362,7 @@
                         networkCapabilities,
                         extras);
         final List<IConnectivityDiagnosticsCallback> results =
-                getMatchingPermissionedCallbacks(nai);
+                getMatchingPermissionedCallbacks(nai, Process.INVALID_UID);
         for (final IConnectivityDiagnosticsCallback cb : results) {
             try {
                 cb.onDataStallSuspected(report);
@@ -9315,15 +9373,39 @@
     }
 
     private void handleNetworkConnectivityReported(
-            @NonNull NetworkAgentInfo nai, boolean connectivity) {
+            @NonNull ReportedNetworkConnectivityInfo reportedNetworkConnectivityInfo) {
+        final NetworkAgentInfo nai = reportedNetworkConnectivityInfo.nai;
+        final ConnectivityReport cachedReport = nai.getConnectivityReport();
+
+        // If the Network is being re-validated as a result of this call to
+        // reportNetworkConnectivity(), notify all permissioned callbacks. Otherwise, only notify
+        // permissioned callbacks registered by the reporter.
         final List<IConnectivityDiagnosticsCallback> results =
-                getMatchingPermissionedCallbacks(nai);
+                getMatchingPermissionedCallbacks(
+                        nai,
+                        reportedNetworkConnectivityInfo.isNetworkRevalidating
+                                ? Process.INVALID_UID
+                                : reportedNetworkConnectivityInfo.reporterUid);
+
         for (final IConnectivityDiagnosticsCallback cb : results) {
             try {
-                cb.onNetworkConnectivityReported(nai.network, connectivity);
+                cb.onNetworkConnectivityReported(
+                        nai.network, reportedNetworkConnectivityInfo.hasConnectivity);
             } catch (RemoteException ex) {
                 loge("Error invoking onNetworkConnectivityReported", ex);
             }
+
+            // If the Network isn't re-validating, also provide the cached report. If there is no
+            // cached report, the Network is still being validated and a report will be sent once
+            // validation is complete. Note that networks which never undergo validation will still
+            // have a cached ConnectivityReport with RESULT_SKIPPED.
+            if (!reportedNetworkConnectivityInfo.isNetworkRevalidating && cachedReport != null) {
+                try {
+                    cb.onConnectivityReportAvailable(cachedReport);
+                } catch (RemoteException ex) {
+                    loge("Error invoking onConnectivityReportAvailable", ex);
+                }
+            }
         }
     }
 
@@ -9336,20 +9418,38 @@
         return sanitized;
     }
 
+    /**
+     * Gets a list of ConnectivityDiagnostics callbacks that match the specified Network and uid.
+     *
+     * <p>If Process.INVALID_UID is specified, all matching callbacks will be returned.
+     */
     private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks(
-            @NonNull NetworkAgentInfo nai) {
+            @NonNull NetworkAgentInfo nai, int uid) {
         final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>();
         for (Entry<IBinder, ConnectivityDiagnosticsCallbackInfo> entry :
                 mConnectivityDiagnosticsCallbacks.entrySet()) {
             final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue();
             final NetworkRequestInfo nri = cbInfo.mRequestInfo;
+
             // Connectivity Diagnostics rejects multilayer requests at registration hence get(0).
-            if (nai.satisfies(nri.mRequests.get(0))) {
-                if (checkConnectivityDiagnosticsPermissions(
-                        nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
-                    results.add(entry.getValue().mCb);
-                }
+            if (!nai.satisfies(nri.mRequests.get(0))) {
+                continue;
             }
+
+            // UID for this callback must either be:
+            //  - INVALID_UID (which sends callbacks to all UIDs), or
+            //  - The callback's owner (the owner called reportNetworkConnectivity() and is being
+            //    notified as a result)
+            if (uid != Process.INVALID_UID && uid != nri.mUid) {
+                continue;
+            }
+
+            if (!checkConnectivityDiagnosticsPermissions(
+                    nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
+                continue;
+            }
+
+            results.add(entry.getValue().mCb);
         }
         return results;
     }
@@ -9892,7 +9992,7 @@
                     TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
             setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
             final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs,
-                    PREFERENCE_PRIORITY_PROFILE);
+                    PREFERENCE_ORDER_PROFILE);
             result.add(nri);
         }
         return result;
@@ -9909,7 +10009,7 @@
                 () -> {
                     final ArraySet<NetworkRequestInfo> nris =
                             createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences);
-                    replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_PRIORITY_PROFILE);
+                    replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_ORDER_PROFILE);
                 });
         // Finally, rematch.
         rematchAllNetworksAndRequests();
@@ -9949,7 +10049,7 @@
         }
         setNetworkRequestUids(requests, ranges);
         nris.add(new NetworkRequestInfo(Process.myUid(), requests,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED));
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED));
         return nris;
     }
 
@@ -9961,7 +10061,7 @@
                     final ArraySet<NetworkRequestInfo> nris =
                             createNrisFromMobileDataPreferredUids(mMobileDataPreferredUids);
                     replaceDefaultNetworkRequestsForPreference(nris,
-                            PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                            PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
                 });
         // Finally, rematch.
         rematchAllNetworksAndRequests();
@@ -10059,7 +10159,7 @@
                     final ArraySet<NetworkRequestInfo> nris =
                             new OemNetworkRequestFactory()
                                     .createNrisFromOemNetworkPreferences(preference);
-                    replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_PRIORITY_OEM);
+                    replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_ORDER_OEM);
                 });
         mOemNetworkPreferences = preference;
 
@@ -10073,11 +10173,11 @@
     }
 
     private void replaceDefaultNetworkRequestsForPreference(
-            @NonNull final Set<NetworkRequestInfo> nris, final int preferencePriority) {
+            @NonNull final Set<NetworkRequestInfo> nris, final int preferenceOrder) {
         // Skip the requests which are set by other network preference. Because the uid range rules
         // should stay in netd.
         final Set<NetworkRequestInfo> requests = new ArraySet<>(mDefaultNetworkRequests);
-        requests.removeIf(request -> request.mPreferencePriority != preferencePriority);
+        requests.removeIf(request -> request.mPreferenceOrder != preferenceOrder);
         handleRemoveNetworkRequests(requests);
         addPerAppDefaultNetworkRequests(nris);
     }
@@ -10272,7 +10372,7 @@
                 ranges.add(new UidRange(uid, uid));
             }
             setNetworkRequestUids(requests, ranges);
-            return new NetworkRequestInfo(Process.myUid(), requests, PREFERENCE_PRIORITY_OEM);
+            return new NetworkRequestInfo(Process.myUid(), requests, PREFERENCE_ORDER_OEM);
         }
 
         private NetworkRequest createUnmeteredNetworkRequest() {
diff --git a/tests/OWNERS b/tests/OWNERS
deleted file mode 100644
index d3836d4..0000000
--- a/tests/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index 9537786..493a201 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -42,6 +42,7 @@
 import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.NetworkCapabilities.TRANSPORT_USB;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
@@ -49,7 +50,6 @@
 
 import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
 import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
-import static com.android.net.module.util.NetworkCapabilitiesUtils.TRANSPORT_USB;
 import static com.android.testutils.MiscAsserts.assertEmpty;
 import static com.android.testutils.MiscAsserts.assertThrows;
 import static com.android.testutils.ParcelUtils.assertParcelSane;
diff --git a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java
index cdb66e3..8d68c5f 100644
--- a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java
+++ b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java
@@ -57,7 +57,8 @@
     /**
      * Tests reporting of connectivity changed.
      */
-    public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() {
+    public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent()
+            throws Exception {
         if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi");
             return;
@@ -75,7 +76,7 @@
     }
 
     public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent()
-            throws InterruptedException {
+            throws Exception {
         if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot"
                     + "execute unless device supports WiFi");
@@ -94,7 +95,7 @@
                 getConnectivityCount, SEND_BROADCAST_TIMEOUT));
     }
 
-    public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() {
+    public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() throws Exception {
         if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi");
             return;
diff --git a/tests/cts/net/jni/Android.bp b/tests/cts/net/jni/Android.bp
index 13f38d7..8f0d78f 100644
--- a/tests/cts/net/jni/Android.bp
+++ b/tests/cts/net/jni/Android.bp
@@ -16,35 +16,14 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_shared {
-    name: "libnativedns_jni",
+cc_defaults {
+    name: "net_jni_defaults",
 
-    srcs: ["NativeDnsJni.c"],
-    sdk_version: "current",
-
-    shared_libs: [
-        "libnativehelper_compat_libc++",
-        "liblog",
-    ],
-    stl: "libc++_static",
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
-
-}
-
-cc_library_shared {
-    name: "libnativemultinetwork_jni",
-
-    srcs: ["NativeMultinetworkJni.cpp"],
-    sdk_version: "current",
     cflags: [
         "-Wall",
         "-Werror",
         "-Wno-format",
+        "-Wno-unused-parameter",
     ],
     shared_libs: [
         "libandroid",
@@ -52,4 +31,19 @@
         "liblog",
     ],
     stl: "libc++_static",
+    // To be compatible with Q devices, the min_sdk_version must be 29.
+    sdk_version: "current",
+    min_sdk_version: "29",
+}
+
+cc_library_shared {
+    name: "libnativedns_jni",
+    defaults: ["net_jni_defaults"],
+    srcs: ["NativeDnsJni.c"],
+}
+
+cc_library_shared {
+    name: "libnativemultinetwork_jni",
+    defaults: ["net_jni_defaults"],
+    srcs: ["NativeMultinetworkJni.cpp"],
 }
diff --git a/tests/cts/net/native/Android.bp b/tests/cts/net/native/Android.bp
index fa32e44..1d1c18e 100644
--- a/tests/cts/net/native/Android.bp
+++ b/tests/cts/net/native/Android.bp
@@ -33,19 +33,16 @@
 
     srcs: [
         "src/BpfCompatTest.cpp",
-        "src/NativeQtaguidTest.cpp",
     ],
 
     shared_libs: [
         "libbase",
         "liblog",
-        "libutils",
     ],
 
     static_libs: [
         "libbpf_android",
         "libgtest",
-        "libqtaguid",
     ],
 
     // Tag this module as a cts test artifact
diff --git a/tests/cts/net/native/AndroidTest.xml b/tests/cts/net/native/AndroidTest.xml
index fa4b2cf..70d788a 100644
--- a/tests/cts/net/native/AndroidTest.xml
+++ b/tests/cts/net/native/AndroidTest.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Native Network xt_qtaguid test cases">
+<configuration description="Config for CTS Native Network test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="networking" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
diff --git a/tests/cts/net/native/dns/Android.bp b/tests/cts/net/native/dns/Android.bp
index 5e9af8e..434e529 100644
--- a/tests/cts/net/native/dns/Android.bp
+++ b/tests/cts/net/native/dns/Android.bp
@@ -24,6 +24,8 @@
         "liblog",
         "libutils",
     ],
+    // To be compatible with Q devices, the min_sdk_version must be 29.
+    min_sdk_version: "29",
 }
 
 cc_test {
diff --git a/tests/cts/net/native/src/BpfCompatTest.cpp b/tests/cts/net/native/src/BpfCompatTest.cpp
index 09d7e62..874bad4 100644
--- a/tests/cts/net/native/src/BpfCompatTest.cpp
+++ b/tests/cts/net/native/src/BpfCompatTest.cpp
@@ -25,8 +25,6 @@
 
 using namespace android::bpf;
 
-namespace android {
-
 void doBpfStructSizeTest(const char *elfPath) {
   std::ifstream elfFile(elfPath, std::ios::in | std::ios::binary);
   ASSERT_TRUE(elfFile.is_open());
@@ -40,4 +38,7 @@
   doBpfStructSizeTest("/system/etc/bpf/clatd.o");
 }
 
-}  // namespace android
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tests/cts/net/native/src/NativeQtaguidTest.cpp b/tests/cts/net/native/src/NativeQtaguidTest.cpp
deleted file mode 100644
index 7dc6240..0000000
--- a/tests/cts/net/native/src/NativeQtaguidTest.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <arpa/inet.h>
-#include <error.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/socket.h>
-
-#include <gtest/gtest.h>
-#include <qtaguid/qtaguid.h>
-
-int canAccessQtaguidFile() {
-    int fd = open("/proc/net/xt_qtaguid/ctrl", O_RDONLY | O_CLOEXEC);
-    close(fd);
-    return fd != -1;
-}
-
-#define SKIP_IF_QTAGUID_NOT_SUPPORTED()                                                       \
-  do {                                                                                        \
-    int res = canAccessQtaguidFile();                                                      \
-    ASSERT_LE(0, res);                                                                        \
-    if (!res) {                                                                               \
-          GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n";  \
-          return;                                                                             \
-    }                                                                                         \
-  } while (0)
-
-int getCtrlSkInfo(int tag, uid_t uid, uint64_t* sk_addr, int* ref_cnt) {
-    FILE *fp;
-    fp = fopen("/proc/net/xt_qtaguid/ctrl", "r");
-    if (!fp)
-        return -ENOENT;
-    uint64_t full_tag = (uint64_t)tag << 32 | uid;
-    char pattern[40];
-    snprintf(pattern, sizeof(pattern), " tag=0x%" PRIx64 " (uid=%" PRIu32 ")", full_tag, uid);
-
-    size_t len;
-    char *line_buffer = NULL;
-    while(getline(&line_buffer, &len, fp) != -1) {
-        if (strstr(line_buffer, pattern) == NULL)
-            continue;
-        int res;
-        pid_t dummy_pid;
-        uint64_t k_tag;
-        uint32_t k_uid;
-        const int TOTAL_PARAM = 5;
-        res = sscanf(line_buffer, "sock=%" PRIx64 " tag=0x%" PRIx64 " (uid=%" PRIu32 ") "
-                     "pid=%u f_count=%u", sk_addr, &k_tag, &k_uid,
-                     &dummy_pid, ref_cnt);
-        if (!(res == TOTAL_PARAM && k_tag == full_tag && k_uid == uid))
-            return -EINVAL;
-        free(line_buffer);
-        return 0;
-    }
-    free(line_buffer);
-    return -ENOENT;
-}
-
-void checkNoSocketPointerLeaks(int family) {
-    int sockfd = socket(family, SOCK_STREAM, 0);
-    uid_t uid = getuid();
-    int tag = arc4random();
-    int ref_cnt;
-    uint64_t sk_addr;
-    uint64_t expect_addr = 0;
-
-    EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
-    EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt));
-    EXPECT_EQ(expect_addr, sk_addr);
-    close(sockfd);
-    EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt));
-}
-
-TEST (NativeQtaguidTest, close_socket_without_untag) {
-    SKIP_IF_QTAGUID_NOT_SUPPORTED();
-
-    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
-    uid_t uid = getuid();
-    int tag = arc4random();
-    int ref_cnt;
-    uint64_t dummy_sk;
-    EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
-    EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
-    EXPECT_EQ(2, ref_cnt);
-    close(sockfd);
-    EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
-}
-
-TEST (NativeQtaguidTest, close_socket_without_untag_ipv6) {
-    SKIP_IF_QTAGUID_NOT_SUPPORTED();
-
-    int sockfd = socket(AF_INET6, SOCK_STREAM, 0);
-    uid_t uid = getuid();
-    int tag = arc4random();
-    int ref_cnt;
-    uint64_t dummy_sk;
-    EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
-    EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
-    EXPECT_EQ(2, ref_cnt);
-    close(sockfd);
-    EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
-}
-
-TEST (NativeQtaguidTest, no_socket_addr_leak) {
-  SKIP_IF_QTAGUID_NOT_SUPPORTED();
-
-  checkNoSocketPointerLeaks(AF_INET);
-  checkNoSocketPointerLeaks(AF_INET6);
-}
-
-int main(int argc, char **argv) {
-      testing::InitGoogleTest(&argc, argv);
-      return RUN_ALL_TESTS();
-}
diff --git a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
index dfb03c7..4d60279 100644
--- a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
@@ -38,6 +38,7 @@
 import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 
+import androidx.test.filters.SdkSuppress;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.testutils.DevSdkIgnoreRule;
@@ -58,6 +59,7 @@
  * Test for BatteryStatsManager.
  */
 @RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R) // BatteryStatsManager did not exist on Q
 public class BatteryStatsManagerTest{
     @Rule
     public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
index ccbdbd3..a40c92d 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
@@ -22,6 +22,7 @@
 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_SKIPPED;
 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID;
 import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS;
@@ -78,6 +79,7 @@
 
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.util.ArrayUtils;
+import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.ArrayTrackRecord;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 import com.android.testutils.DevSdkIgnoreRunner;
@@ -292,7 +294,7 @@
         final String interfaceName =
                 mConnectivityManager.getLinkProperties(network).getInterfaceName();
         connDiagsCallback.expectOnConnectivityReportAvailable(
-                network, interfaceName, TRANSPORT_CELLULAR);
+                network, interfaceName, TRANSPORT_CELLULAR, NETWORK_VALIDATION_RESULT_VALID);
         connDiagsCallback.assertNoCallback();
     }
 
@@ -423,9 +425,10 @@
 
         cb.expectOnNetworkConnectivityReported(mTestNetwork, hasConnectivity);
 
-        // if hasConnectivity does not match the network's known connectivity, it will be
-        // revalidated which will trigger another onConnectivityReportAvailable callback.
-        if (!hasConnectivity) {
+        // All calls to #onNetworkConnectivityReported are expected to be accompanied by a call to
+        // #onConnectivityReportAvailable for S+ (for R, ConnectivityReports were only sent when the
+        // Network was re-validated - when reported connectivity != known connectivity).
+        if (SdkLevel.isAtLeastS() || !hasConnectivity) {
             cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName);
         }
 
@@ -479,11 +482,19 @@
 
         public void expectOnConnectivityReportAvailable(
                 @NonNull Network network, @NonNull String interfaceName) {
-            expectOnConnectivityReportAvailable(network, interfaceName, TRANSPORT_TEST);
+            // Test Networks both do not require validation and are not tested for validation. This
+            // results in the validation result being reported as SKIPPED for S+ (for R, the
+            // platform marked these Networks as VALID).
+            final int expectedNetworkValidationResult =
+                    SdkLevel.isAtLeastS()
+                            ? NETWORK_VALIDATION_RESULT_SKIPPED
+                            : NETWORK_VALIDATION_RESULT_VALID;
+            expectOnConnectivityReportAvailable(
+                    network, interfaceName, TRANSPORT_TEST, expectedNetworkValidationResult);
         }
 
-        public void expectOnConnectivityReportAvailable(
-                @NonNull Network network, @NonNull String interfaceName, int transportType) {
+        public void expectOnConnectivityReportAvailable(@NonNull Network network,
+                @NonNull String interfaceName, int transportType, int expectedValidationResult) {
             final ConnectivityReport result =
                     (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true);
             assertEquals(network, result.getNetwork());
@@ -496,9 +507,9 @@
 
             final PersistableBundle extras = result.getAdditionalInfo();
             assertTrue(extras.containsKey(KEY_NETWORK_VALIDATION_RESULT));
-            final int validationResult = extras.getInt(KEY_NETWORK_VALIDATION_RESULT);
-            assertEquals("Network validation result is not 'valid'",
-                    NETWORK_VALIDATION_RESULT_VALID, validationResult);
+            final int actualValidationResult = extras.getInt(KEY_NETWORK_VALIDATION_RESULT);
+            assertEquals("Network validation result is incorrect",
+                    expectedValidationResult, actualValidationResult);
 
             assertTrue(extras.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK));
             final int probesSucceeded = extras.getInt(KEY_NETWORK_VALIDATION_RESULT);
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 9be7855..ee13619 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -1043,7 +1043,7 @@
      */
     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     @Test
-    public void testToggleWifiConnectivityAction() {
+    public void testToggleWifiConnectivityAction() throws Exception {
         // toggleWifi calls connectToWifi and disconnectFromWifi, which both wait for
         // CONNECTIVITY_ACTION broadcasts.
         mCtsNetUtils.toggleWifi();
@@ -1102,10 +1102,10 @@
         }
     }
 
-    private void waitForActiveNetworkMetered(final int targetTransportType,
+    private Network waitForActiveNetworkMetered(final int targetTransportType,
             final boolean requestedMeteredness, final boolean useSystemDefault)
             throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
+        final CompletableFuture<Network> networkFuture = new CompletableFuture<>();
         final NetworkCallback networkCallback = new NetworkCallback() {
             @Override
             public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
@@ -1113,7 +1113,7 @@
 
                 final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
                 if (metered == requestedMeteredness) {
-                    latch.countDown();
+                    networkFuture.complete(network);
                 }
             }
         };
@@ -1133,18 +1133,20 @@
 
             // Changing meteredness on wifi involves reconnecting, which can take several seconds
             // (involves re-associating, DHCP...).
-            if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                fail("Timed out waiting for active network metered status to change to "
-                        + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
-            }
+            return networkFuture.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (TimeoutException e) {
+            throw new AssertionError("Timed out waiting for active network metered status to "
+                    + "change to " + requestedMeteredness + " ; network = "
+                    + mCm.getActiveNetwork(), e);
         } finally {
             mCm.unregisterNetworkCallback(networkCallback);
         }
     }
 
-    private void setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
+    private Network setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
         setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
-        waitForActiveNetworkMetered(TRANSPORT_WIFI,
+        mCtsNetUtils.ensureWifiConnected();
+        return waitForActiveNetworkMetered(TRANSPORT_WIFI,
                 isMetered /* requestedMeteredness */,
                 true /* useSystemDefault */);
     }
@@ -1210,8 +1212,7 @@
                     Integer.toString(newMeteredPreference));
             // Wifi meterness changes from unmetered to metered will disconnect and reconnect since
             // R.
-            setWifiMeteredStatusAndWait(ssid, true);
-            final Network network = mCtsNetUtils.ensureWifiConnected();
+            final Network network = setWifiMeteredStatusAndWait(ssid, true);
             assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
                     NET_CAPABILITY_NOT_METERED), false);
@@ -1824,8 +1825,15 @@
         // Verify that networks are available as expected if wifi or cell is supported. Continue the
         // test if none of them are supported since test should still able to verify the permission
         // mechanism.
-        if (supportWifi) requestAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
-        if (supportTelephony) requestAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb);
+        if (supportWifi) {
+            mCtsNetUtils.ensureWifiConnected();
+            registerCallbackAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
+        }
+        if (supportTelephony) {
+            // connectToCell needs to be followed by disconnectFromCell, which is called in tearDown
+            mCtsNetUtils.connectToCell();
+            registerCallbackAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb);
+        }
 
         try {
             // Verify we cannot set Airplane Mode without correct permission:
@@ -1862,6 +1870,8 @@
                         + "called whilst holding the NETWORK_AIRPLANE_MODE permission.");
             }
             // Verify that turning airplane mode off takes effect as expected.
+            // connectToCell only registers a request, it cannot / does not need to be called twice
+            mCtsNetUtils.ensureWifiConnected();
             if (supportWifi) waitForAvailable(wifiCb);
             if (supportTelephony) waitForAvailable(telephonyCb);
         } finally {
@@ -1874,7 +1884,7 @@
         }
     }
 
-    private void requestAndWaitForAvailable(@NonNull final NetworkRequest request,
+    private void registerCallbackAndWaitForAvailable(@NonNull final NetworkRequest request,
             @NonNull final TestableNetworkCallback cb) {
         mCm.registerNetworkCallback(request, cb);
         waitForAvailable(cb);
@@ -2102,6 +2112,10 @@
         public void onBlockedStatusChanged(Network network, int blockedReasons) {
             getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
         }
+        private void assertNoBlockedStatusCallback() {
+            super.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS,
+                    c -> c instanceof CallbackEntry.BlockedStatus);
+        }
     }
 
     private void setRequireVpnForUids(boolean requireVpn, Collection<Range<Integer>> ranges)
@@ -2138,24 +2152,24 @@
 
         setRequireVpnForUids(true, List.of(myUidRange));
         myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN);
-        otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
+        otherUidCallback.assertNoBlockedStatusCallback();
 
         setRequireVpnForUids(true, List.of(myUidRange, otherUidRange));
-        myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
+        myUidCallback.assertNoBlockedStatusCallback();
         otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN);
 
         // setRequireVpnForUids does no deduplication or refcounting. Removing myUidRange does not
         // unblock myUid because it was added to the blocked ranges twice.
         setRequireVpnForUids(false, List.of(myUidRange));
-        myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
-        otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
+        myUidCallback.assertNoBlockedStatusCallback();
+        otherUidCallback.assertNoBlockedStatusCallback();
 
         setRequireVpnForUids(false, List.of(myUidRange, otherUidRange));
         myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
         otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
 
-        myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
-        otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
+        myUidCallback.assertNoBlockedStatusCallback();
+        otherUidCallback.assertNoBlockedStatusCallback();
     }
 
     @Test
@@ -2640,8 +2654,9 @@
             // Default network should be updated to validated cellular network.
             defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
                     entry -> cellNetwork.equals(entry.getNetwork()));
-            // No update on wifi callback.
-            wifiCb.assertNoCallback();
+            // No callback except LinkPropertiesChanged which may be triggered randomly from network
+            wifiCb.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS,
+                    c -> !(c instanceof CallbackEntry.LinkPropertiesChanged));
         } finally {
             mCm.unregisterNetworkCallback(wifiCb);
             mCm.unregisterNetworkCallback(defaultCb);
@@ -2844,22 +2859,13 @@
         }
     }
 
-    /** Wait for assigned time. */
-    private void waitForMs(long ms) {
-        try {
-            Thread.sleep(ms);
-        } catch (InterruptedException e) {
-            fail("Thread was interrupted");
-        }
-    }
-
     private void assertBindSocketToNetworkSuccess(final Network network) throws Exception {
         final CompletableFuture<Boolean> future = new CompletableFuture<>();
         final ExecutorService executor = Executors.newSingleThreadExecutor();
         try {
             executor.execute(() -> {
-                for (int i = 0; i < 30; i++) {
-                    waitForMs(100);
+                for (int i = 0; i < 300; i++) {
+                    SystemClock.sleep(10);
 
                     try (Socket socket = new Socket()) {
                         network.bindSocket(socket);
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index bce9880..fd0cd18 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -28,7 +28,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -55,7 +54,9 @@
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Build;
+import android.os.ConditionVariable;
 import android.os.IBinder;
+import android.os.SystemClock;
 import android.system.Os;
 import android.system.OsConstants;
 import android.text.TextUtils;
@@ -73,11 +74,13 @@
 import java.net.Socket;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 
 public final class CtsNetUtils {
     private static final String TAG = CtsNetUtils.class.getSimpleName();
@@ -86,6 +89,13 @@
 
     private static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 10_000;
     private static final int CONNECTIVITY_CHANGE_TIMEOUT_SECS = 30;
+    private static final int MAX_WIFI_CONNECT_RETRIES = 10;
+    private static final int WIFI_CONNECT_INTERVAL_MS = 500;
+
+    // Constants used by WifiManager.ActionListener#onFailure. Although onFailure is SystemApi,
+    // the error code constants are not (they probably should be ?)
+    private static final int WIFI_ERROR_IN_PROGRESS = 1;
+    private static final int WIFI_ERROR_BUSY = 2;
     private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
     private static final String PRIVATE_DNS_MODE_STRICT = "hostname";
     public static final int HTTP_PORT = 80;
@@ -159,18 +169,44 @@
     }
 
     // Toggle WiFi twice, leaving it in the state it started in
-    public void toggleWifi() {
+    public void toggleWifi() throws Exception {
         if (mWifiManager.isWifiEnabled()) {
             Network wifiNetwork = getWifiNetwork();
+            // Ensure system default network is WIFI because it's expected in disconnectFromWifi()
+            expectNetworkIsSystemDefault(wifiNetwork);
             disconnectFromWifi(wifiNetwork);
             connectToWifi();
         } else {
             connectToWifi();
             Network wifiNetwork = getWifiNetwork();
+            // Ensure system default network is WIFI because it's expected in disconnectFromWifi()
+            expectNetworkIsSystemDefault(wifiNetwork);
             disconnectFromWifi(wifiNetwork);
         }
     }
 
+    private Network expectNetworkIsSystemDefault(Network network)
+            throws Exception {
+        final CompletableFuture<Network> future = new CompletableFuture();
+        final NetworkCallback cb = new NetworkCallback() {
+            @Override
+            public void onAvailable(Network n) {
+                if (n.equals(network)) future.complete(network);
+            }
+        };
+
+        try {
+            mCm.registerDefaultNetworkCallback(cb);
+            return future.get(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS);
+        } catch (TimeoutException e) {
+            throw new AssertionError("Timed out waiting for system default network to switch"
+                    + " to network " + network + ". Current default network is network "
+                    + mCm.getActiveNetwork(), e);
+        } finally {
+            mCm.unregisterNetworkCallback(cb);
+        }
+    }
+
     /**
      * Enable WiFi and wait for it to become connected to a network.
      *
@@ -211,32 +247,21 @@
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mContext.registerReceiver(receiver, filter);
 
-        boolean connected = false;
-        final String err = "Wifi must be configured to connect to an access point for this test";
         try {
-            clearWifiBlacklist();
+            // Clear the wifi config blocklist (not the BSSID blocklist)
+            clearWifiBlocklist();
             SystemUtil.runShellCommand("svc wifi enable");
-            final WifiConfiguration config = maybeAddVirtualWifiConfiguration();
-            if (config == null) {
-                // TODO: this may not clear the BSSID blacklist, as opposed to
-                // mWifiManager.connect(config)
-                assertTrue("Error reconnecting wifi", runAsShell(NETWORK_SETTINGS,
-                        mWifiManager::reconnect));
-            } else {
-                // When running CTS, devices are expected to have wifi networks pre-configured.
-                // This condition is only hit on virtual devices.
-                final Integer error = runAsShell(NETWORK_SETTINGS, () -> {
-                    final ConnectWifiListener listener = new ConnectWifiListener();
-                    mWifiManager.connect(config, listener);
-                    return listener.connectFuture.get(
-                            CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS);
-                });
-                assertNull("Error connecting to wifi: " + error, error);
-            }
+            final WifiConfiguration config = getOrCreateWifiConfiguration();
+            connectToWifiConfig(config);
+
             // Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION.
             wifiNetwork = callback.waitForAvailable();
-            assertNotNull(err + ": onAvailable callback not received", wifiNetwork);
-            connected = !expectLegacyBroadcast || receiver.waitForState();
+            assertNotNull("onAvailable callback not received after connecting to " + config.SSID,
+                    wifiNetwork);
+            if (expectLegacyBroadcast) {
+                assertTrue("CONNECTIVITY_ACTION not received after connecting to " + config.SSID,
+                        receiver.waitForState());
+            }
         } catch (InterruptedException ex) {
             fail("connectToWifi was interrupted");
         } finally {
@@ -244,10 +269,33 @@
             mContext.unregisterReceiver(receiver);
         }
 
-        assertTrue(err + ": CONNECTIVITY_ACTION not received", connected);
         return wifiNetwork;
     }
 
+    private void connectToWifiConfig(WifiConfiguration config) {
+        for (int i = 0; i < MAX_WIFI_CONNECT_RETRIES; i++) {
+            final Integer error = runAsShell(NETWORK_SETTINGS, () -> {
+                final ConnectWifiListener listener = new ConnectWifiListener();
+                mWifiManager.connect(config, listener);
+                return listener.connectFuture.get(
+                        CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS);
+            });
+
+            if (error == null) return;
+
+            // Only retry for IN_PROGRESS and BUSY
+            if (error != WIFI_ERROR_IN_PROGRESS && error != WIFI_ERROR_BUSY) {
+                fail("Failed to connect to " + config.SSID + ": " + error);
+            }
+
+            Log.w(TAG, "connect failed with " + error + "; waiting before retry");
+            SystemClock.sleep(WIFI_CONNECT_INTERVAL_MS);
+        }
+
+        fail("Failed to connect to " + config.SSID
+                + " after " + MAX_WIFI_CONNECT_RETRIES + "retries");
+    }
+
     private static class ConnectWifiListener implements WifiManager.ActionListener {
         /**
          * Future completed when the connect process ends. Provides the error code or null if none.
@@ -264,7 +312,7 @@
         }
     }
 
-    private WifiConfiguration maybeAddVirtualWifiConfiguration() {
+    private WifiConfiguration getOrCreateWifiConfiguration() {
         final List<WifiConfiguration> configs = runAsShell(NETWORK_SETTINGS,
                 mWifiManager::getConfiguredNetworks);
         // If no network is configured, add a config for virtual access points if applicable
@@ -275,8 +323,24 @@
 
             return virtualConfig;
         }
-        // No need to add a configuration: there is already one
-        return null;
+        // No need to add a configuration: there is already one.
+        if (configs.size() > 1) {
+            // For convenience in case of local testing on devices with multiple saved configs,
+            // prefer the first configuration that is in range.
+            // In actual tests, there should only be one configuration, and it should be usable as
+            // assumed by WifiManagerTest.testConnect.
+            Log.w(TAG, "Multiple wifi configurations found: "
+                    + configs.stream().map(c -> c.SSID).collect(Collectors.joining(", ")));
+            final List<ScanResult> scanResultsList = getWifiScanResults();
+            Log.i(TAG, "Scan results: " + scanResultsList.stream().map(c ->
+                    c.SSID + " (" + c.level + ")").collect(Collectors.joining(", ")));
+            final Set<String> scanResults = scanResultsList.stream().map(
+                    s -> "\"" + s.SSID + "\"").collect(Collectors.toSet());
+
+            return configs.stream().filter(c -> scanResults.contains(c.SSID))
+                    .findFirst().orElse(configs.get(0));
+        }
+        return configs.get(0);
     }
 
     private List<ScanResult> getWifiScanResults() {
@@ -327,11 +391,11 @@
     }
 
     /**
-     * Re-enable wifi networks that were blacklisted, typically because no internet connection was
+     * Re-enable wifi networks that were blocklisted, typically because no internet connection was
      * detected the last time they were connected. This is necessary to make sure wifi can reconnect
      * to them.
      */
-    private void clearWifiBlacklist() {
+    private void clearWifiBlocklist() {
         runAsShell(NETWORK_SETTINGS, ACCESS_WIFI_STATE, () -> {
             for (WifiConfiguration cfg : mWifiManager.getConfiguredNetworks()) {
                 assertTrue(mWifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */));
@@ -662,16 +726,28 @@
      * {@code onAvailable}.
      */
     public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
-        private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
+        private final ConditionVariable mAvailableCv = new ConditionVariable(false);
         private final CountDownLatch mLostLatch = new CountDownLatch(1);
         private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
 
         public Network currentNetwork;
         public Network lastLostNetwork;
 
+        /**
+         * Wait for a network to be available.
+         *
+         * If onAvailable was previously called but was followed by onLost, this will wait for the
+         * next available network.
+         */
         public Network waitForAvailable() throws InterruptedException {
-            return mAvailableLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS)
-                    ? currentNetwork : null;
+            final long timeoutMs = TimeUnit.SECONDS.toMillis(CONNECTIVITY_CHANGE_TIMEOUT_SECS);
+            while (mAvailableCv.block(timeoutMs)) {
+                final Network n = currentNetwork;
+                if (n != null) return n;
+                Log.w(TAG, "onAvailable called but network was lost before it could be returned."
+                        + " Waiting for the next call to onAvailable.");
+            }
+            return null;
         }
 
         public Network waitForLost() throws InterruptedException {
@@ -683,17 +759,17 @@
             return mUnavailableLatch.await(2, TimeUnit.SECONDS);
         }
 
-
         @Override
         public void onAvailable(Network network) {
             currentNetwork = network;
-            mAvailableLatch.countDown();
+            mAvailableCv.open();
         }
 
         @Override
         public void onLost(Network network) {
             lastLostNetwork = network;
             if (network.equals(currentNetwork)) {
+                mAvailableCv.close();
                 currentNetwork = null;
             }
             mLostLatch.countDown();
diff --git a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
index ed4f61d..8498b6f 100644
--- a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
+++ b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
@@ -168,8 +168,8 @@
         assertEquals(resultData.tos, tos);
         assertEquals(resultData.ttl, ttl);
 
-        final String expected = ""
-                + "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
+        final String expected = TcpKeepalivePacketDataParcelable.class.getName()
+                + "{srcAddress: [10, 0, 0, 1],"
                 + " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
                 + " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
         assertEquals(expected, resultData.toString());
diff --git a/tests/unit/java/com/android/internal/util/BitUtilsTest.java b/tests/unit/java/com/android/internal/util/BitUtilsTest.java
deleted file mode 100644
index aab1268..0000000
--- a/tests/unit/java/com/android/internal/util/BitUtilsTest.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.android.internal.util;
-
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.bytesToLEInt;
-import static com.android.internal.util.BitUtils.getUint16;
-import static com.android.internal.util.BitUtils.getUint32;
-import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.packBits;
-import static com.android.internal.util.BitUtils.uint16;
-import static com.android.internal.util.BitUtils.uint32;
-import static com.android.internal.util.BitUtils.uint8;
-import static com.android.internal.util.BitUtils.unpackBits;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRunner;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Random;
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner.class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-public class BitUtilsTest {
-
-    @Test
-    public void testUnsignedByteWideningConversions() {
-        byte b0 = 0;
-        byte b1 = 1;
-        byte bm1 = -1;
-        assertEquals(0, uint8(b0));
-        assertEquals(1, uint8(b1));
-        assertEquals(127, uint8(Byte.MAX_VALUE));
-        assertEquals(128, uint8(Byte.MIN_VALUE));
-        assertEquals(255, uint8(bm1));
-        assertEquals(255, uint8((byte)255));
-    }
-
-    @Test
-    public void testUnsignedShortWideningConversions() {
-        short s0 = 0;
-        short s1 = 1;
-        short sm1 = -1;
-        assertEquals(0, uint16(s0));
-        assertEquals(1, uint16(s1));
-        assertEquals(32767, uint16(Short.MAX_VALUE));
-        assertEquals(32768, uint16(Short.MIN_VALUE));
-        assertEquals(65535, uint16(sm1));
-        assertEquals(65535, uint16((short)65535));
-    }
-
-    @Test
-    public void testUnsignedShortComposition() {
-        byte b0 = 0;
-        byte b1 = 1;
-        byte b2 = 2;
-        byte b10 = 10;
-        byte b16 = 16;
-        byte b128 = -128;
-        byte b224 = -32;
-        byte b255 = -1;
-        assertEquals(0x0000, uint16(b0, b0));
-        assertEquals(0xffff, uint16(b255, b255));
-        assertEquals(0x0a01, uint16(b10, b1));
-        assertEquals(0x8002, uint16(b128, b2));
-        assertEquals(0x01ff, uint16(b1, b255));
-        assertEquals(0x80ff, uint16(b128, b255));
-        assertEquals(0xe010, uint16(b224, b16));
-    }
-
-    @Test
-    public void testUnsignedIntWideningConversions() {
-        assertEquals(0, uint32(0));
-        assertEquals(1, uint32(1));
-        assertEquals(2147483647L, uint32(Integer.MAX_VALUE));
-        assertEquals(2147483648L, uint32(Integer.MIN_VALUE));
-        assertEquals(4294967295L, uint32(-1));
-        assertEquals(4294967295L, uint32((int)4294967295L));
-    }
-
-    @Test
-    public void testBytesToInt() {
-        assertEquals(0x00000000, bytesToBEInt(bytes(0, 0, 0, 0)));
-        assertEquals(0xffffffff, bytesToBEInt(bytes(255, 255, 255, 255)));
-        assertEquals(0x0a000001, bytesToBEInt(bytes(10, 0, 0, 1)));
-        assertEquals(0x0a000002, bytesToBEInt(bytes(10, 0, 0, 2)));
-        assertEquals(0x0a001fff, bytesToBEInt(bytes(10, 0, 31, 255)));
-        assertEquals(0xe0000001, bytesToBEInt(bytes(224, 0, 0, 1)));
-
-        assertEquals(0x00000000, bytesToLEInt(bytes(0, 0, 0, 0)));
-        assertEquals(0x01020304, bytesToLEInt(bytes(4, 3, 2, 1)));
-        assertEquals(0xffff0000, bytesToLEInt(bytes(0, 0, 255, 255)));
-    }
-
-    @Test
-    public void testUnsignedGetters() {
-        ByteBuffer b = ByteBuffer.allocate(4);
-        b.putInt(0xffff);
-
-        assertEquals(0x0, getUint8(b, 0));
-        assertEquals(0x0, getUint8(b, 1));
-        assertEquals(0xff, getUint8(b, 2));
-        assertEquals(0xff, getUint8(b, 3));
-
-        assertEquals(0x0, getUint16(b, 0));
-        assertEquals(0xffff, getUint16(b, 2));
-
-        b.rewind();
-        b.putInt(0xffffffff);
-        assertEquals(0xffffffffL, getUint32(b, 0));
-    }
-
-    @Test
-    public void testBitsPacking() {
-        BitPackingTestCase[] testCases = {
-            new BitPackingTestCase(0, ints()),
-            new BitPackingTestCase(1, ints(0)),
-            new BitPackingTestCase(2, ints(1)),
-            new BitPackingTestCase(3, ints(0, 1)),
-            new BitPackingTestCase(4, ints(2)),
-            new BitPackingTestCase(6, ints(1, 2)),
-            new BitPackingTestCase(9, ints(0, 3)),
-            new BitPackingTestCase(~Long.MAX_VALUE, ints(63)),
-            new BitPackingTestCase(~Long.MAX_VALUE + 1, ints(0, 63)),
-            new BitPackingTestCase(~Long.MAX_VALUE + 2, ints(1, 63)),
-        };
-        for (BitPackingTestCase tc : testCases) {
-            int[] got = unpackBits(tc.packedBits);
-            assertTrue(
-                    "unpackBits("
-                            + tc.packedBits
-                            + "): expected "
-                            + Arrays.toString(tc.bits)
-                            + " but got "
-                            + Arrays.toString(got),
-                    Arrays.equals(tc.bits, got));
-        }
-        for (BitPackingTestCase tc : testCases) {
-            long got = packBits(tc.bits);
-            assertEquals(
-                    "packBits("
-                            + Arrays.toString(tc.bits)
-                            + "): expected "
-                            + tc.packedBits
-                            + " but got "
-                            + got,
-                    tc.packedBits,
-                    got);
-        }
-
-        long[] moreTestCases = {
-            0, 1, -1, 23895, -908235, Long.MAX_VALUE, Long.MIN_VALUE, new Random().nextLong(),
-        };
-        for (long l : moreTestCases) {
-            assertEquals(l, packBits(unpackBits(l)));
-        }
-    }
-
-    static byte[] bytes(int b1, int b2, int b3, int b4) {
-        return new byte[] {b(b1), b(b2), b(b3), b(b4)};
-    }
-
-    static byte b(int i) {
-        return (byte) i;
-    }
-
-    static int[] ints(int... array) {
-        return array;
-    }
-
-    static class BitPackingTestCase {
-        final int[] bits;
-        final long packedBits;
-
-        BitPackingTestCase(long packedBits, int[] bits) {
-            this.bits = bits;
-            this.packedBits = packedBits;
-        }
-    }
-}
diff --git a/tests/unit/java/com/android/internal/util/RingBufferTest.java b/tests/unit/java/com/android/internal/util/RingBufferTest.java
deleted file mode 100644
index 13cf840..0000000
--- a/tests/unit/java/com/android/internal/util/RingBufferTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.android.internal.util;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRunner;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner.class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-public class RingBufferTest {
-
-    @Test
-    public void testEmptyRingBuffer() {
-        RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
-
-        assertArrayEquals(new String[0], buffer.toArray());
-    }
-
-    @Test
-    public void testIncorrectConstructorArguments() {
-        try {
-            RingBuffer<String> buffer = new RingBuffer<>(String.class, -10);
-            fail("Should not be able to create a negative capacity RingBuffer");
-        } catch (IllegalArgumentException expected) {
-        }
-
-        try {
-            RingBuffer<String> buffer = new RingBuffer<>(String.class, 0);
-            fail("Should not be able to create a 0 capacity RingBuffer");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testRingBufferWithNoWrapping() {
-        RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
-
-        buffer.append("a");
-        buffer.append("b");
-        buffer.append("c");
-        buffer.append("d");
-        buffer.append("e");
-
-        String[] expected = {"a", "b", "c", "d", "e"};
-        assertArrayEquals(expected, buffer.toArray());
-    }
-
-    @Test
-    public void testRingBufferWithCapacity1() {
-        RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
-
-        buffer.append("a");
-        assertArrayEquals(new String[]{"a"}, buffer.toArray());
-
-        buffer.append("b");
-        assertArrayEquals(new String[]{"b"}, buffer.toArray());
-
-        buffer.append("c");
-        assertArrayEquals(new String[]{"c"}, buffer.toArray());
-
-        buffer.append("d");
-        assertArrayEquals(new String[]{"d"}, buffer.toArray());
-
-        buffer.append("e");
-        assertArrayEquals(new String[]{"e"}, buffer.toArray());
-    }
-
-    @Test
-    public void testRingBufferWithWrapping() {
-        int capacity = 100;
-        RingBuffer<String> buffer = new RingBuffer<>(String.class, capacity);
-
-        buffer.append("a");
-        buffer.append("b");
-        buffer.append("c");
-        buffer.append("d");
-        buffer.append("e");
-
-        String[] expected1 = {"a", "b", "c", "d", "e"};
-        assertArrayEquals(expected1, buffer.toArray());
-
-        String[] expected2 = new String[capacity];
-        int firstIndex = 0;
-        int lastIndex = capacity - 1;
-
-        expected2[firstIndex] = "e";
-        for (int i = 1; i < capacity; i++) {
-            buffer.append("x");
-            expected2[i] = "x";
-        }
-        assertArrayEquals(expected2, buffer.toArray());
-
-        buffer.append("x");
-        expected2[firstIndex] = "x";
-        assertArrayEquals(expected2, buffer.toArray());
-
-        for (int i = 0; i < 10; i++) {
-            for (String s : expected2) {
-                buffer.append(s);
-            }
-        }
-        assertArrayEquals(expected2, buffer.toArray());
-
-        buffer.append("a");
-        expected2[lastIndex] = "a";
-        assertArrayEquals(expected2, buffer.toArray());
-    }
-
-    @Test
-    public void testGetNextSlot() {
-        int capacity = 100;
-        RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
-
-        final DummyClass1[] actual = new DummyClass1[capacity];
-        final DummyClass1[] expected = new DummyClass1[capacity];
-        for (int i = 0; i < capacity; ++i) {
-            final DummyClass1 obj = buffer.getNextSlot();
-            obj.x = capacity * i;
-            actual[i] = obj;
-            expected[i] = new DummyClass1();
-            expected[i].x = capacity * i;
-        }
-        assertArrayEquals(expected, buffer.toArray());
-
-        for (int i = 0; i < capacity; ++i) {
-            if (actual[i] != buffer.getNextSlot()) {
-                fail("getNextSlot() should re-use objects if available");
-            }
-        }
-
-        RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
-        assertNull("getNextSlot() should return null if the object can't be initiated "
-                + "(No nullary constructor)", buffer2.getNextSlot());
-
-        RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
-        assertNull("getNextSlot() should return null if the object can't be initiated "
-                + "(Inaccessible class)", buffer3.getNextSlot());
-    }
-
-    public static final class DummyClass1 {
-        int x;
-
-        public boolean equals(Object o) {
-            if (o instanceof DummyClass1) {
-                final DummyClass1 other = (DummyClass1) o;
-                return other.x == this.x;
-            }
-            return false;
-        }
-    }
-
-    public static final class DummyClass2 {
-        public DummyClass2(int x) {}
-    }
-
-    private static final class DummyClass3 {}
-}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 0f0ac12..1b3496f 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -125,10 +125,10 @@
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
 
-import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED;
-import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_OEM;
-import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_PROFILE;
-import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_VPN;
+import static com.android.server.ConnectivityService.PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED;
+import static com.android.server.ConnectivityService.PREFERENCE_ORDER_OEM;
+import static com.android.server.ConnectivityService.PREFERENCE_ORDER_PROFILE;
+import static com.android.server.ConnectivityService.PREFERENCE_ORDER_VPN;
 import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
 import static com.android.testutils.ConcurrentUtils.await;
 import static com.android.testutils.ConcurrentUtils.durationOf;
@@ -176,6 +176,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import static java.util.Arrays.asList;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -310,7 +312,6 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
@@ -1172,20 +1173,14 @@
             assertEquals(count, getMyRequestCount());
         }
 
-        @Override
-        public void terminate() {
-            super.terminate();
-            // Make sure there are no remaining requests unaccounted for.
-            HandlerUtils.waitForIdle(mHandlerSendingRequests, TIMEOUT_MS);
-            assertNull(mRequestHistory.poll(0, r -> true));
-        }
-
         // Trigger releasing the request as unfulfillable
         public void triggerUnfulfillable(NetworkRequest r) {
             super.releaseRequestAsUnfulfillableByAnyFactory(r);
         }
 
         public void assertNoRequestChanged() {
+            // Make sure there are no remaining requests unaccounted for.
+            HandlerUtils.waitForIdle(mHandlerSendingRequests, TIMEOUT_MS);
             assertNull(mRequestHistory.poll(0, r -> true));
         }
     }
@@ -1303,10 +1298,10 @@
 
             verify(mMockNetd, times(1)).networkAddUidRangesParcel(
                     new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
-                            toUidRangeStableParcels(uids), PREFERENCE_PRIORITY_VPN));
+                            toUidRangeStableParcels(uids), PREFERENCE_ORDER_VPN));
             verify(mMockNetd, never()).networkRemoveUidRangesParcel(argThat(config ->
                     mMockVpn.getNetwork().getNetId() == config.netId
-                            && PREFERENCE_PRIORITY_VPN == config.subPriority));
+                            && PREFERENCE_ORDER_VPN == config.subPriority));
             mAgentRegistered = true;
             verify(mMockNetd).networkCreate(nativeNetworkConfigVpn(getNetwork().netId,
                     !mMockNetworkAgent.isBypassableVpn(), mVpnType));
@@ -1535,7 +1530,7 @@
     }
 
     private <T> T doAsUid(final int uid, @NonNull final Supplier<T> what) {
-        when(mDeps.getCallingUid()).thenReturn(uid);
+        doReturn(uid).when(mDeps).getCallingUid();
         try {
             return what.get();
         } finally {
@@ -1610,9 +1605,8 @@
 
         MockitoAnnotations.initMocks(this);
 
-        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
-        when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
-                Arrays.asList(PRIMARY_USER_HANDLE));
+        when(mUserManager.getAliveUsers()).thenReturn(asList(PRIMARY_USER_INFO));
+        when(mUserManager.getUserHandles(anyBoolean())).thenReturn(asList(PRIMARY_USER_HANDLE));
         when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
         // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
         // it was started from, i.e., PRIMARY_USER.
@@ -1820,7 +1814,7 @@
                 eq(UserHandle.getCallingUserId()))).thenReturn(myPackageInfo);
 
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
-                Arrays.asList(new PackageInfo[] {
+                asList(new PackageInfo[] {
                         buildPackageInfo(/* SYSTEM */ false, APP1_UID),
                         buildPackageInfo(/* SYSTEM */ false, APP2_UID),
                         buildPackageInfo(/* SYSTEM */ false, VPN_UID)
@@ -1837,7 +1831,7 @@
         ResolveInfo rInfo = new ResolveInfo();
         rInfo.serviceInfo = new ServiceInfo();
         rInfo.serviceInfo.metaData = new Bundle();
-        final List<ResolveInfo> services = Arrays.asList(new ResolveInfo[]{rInfo});
+        final List<ResolveInfo> services = asList(new ResolveInfo[]{rInfo});
         when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
                 eq(userId))).thenReturn(services);
         when(mPackageManager.getPackageUidAsUser(TEST_PACKAGE_NAME, userId))
@@ -3280,6 +3274,7 @@
         assertTrue(testFactory.getMyStartRequested());
 
         testFactory.terminate();
+        testFactory.assertNoRequestChanged();
         if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
         handlerThread.quit();
     }
@@ -3364,6 +3359,7 @@
 
             testFactory.setScoreFilter(42);
             testFactory.terminate();
+            testFactory.assertNoRequestChanged();
 
             if (i % 2 == 0) {
                 try {
@@ -4783,6 +4779,9 @@
             // and the test factory should see it now that it isn't hopelessly outscored.
             mCellNetworkAgent.disconnect();
             cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            // Wait for the network to be removed from internal structures before
+            // calling synchronous getter
+            waitForIdle();
             assertLength(1, mCm.getAllNetworks());
             testFactory.expectRequestAdd();
             testFactory.assertRequestCountEquals(1);
@@ -4793,6 +4792,7 @@
             mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
             mCellNetworkAgent.connect(true);
             cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+            waitForIdle();
             assertLength(2, mCm.getAllNetworks());
             testFactory.expectRequestRemove();
             testFactory.assertRequestCountEquals(0);
@@ -4804,8 +4804,9 @@
             cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
             waitForIdle();
             assertLength(1, mCm.getAllNetworks());
-        } finally {
             testFactory.terminate();
+            testFactory.assertNoRequestChanged();
+        } finally {
             mCm.unregisterNetworkCallback(cellNetworkCallback);
             handlerThread.quit();
         }
@@ -5004,8 +5005,8 @@
         final ContentResolver cr = mServiceContext.getContentResolver();
         final String settingName = ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
 
-        for (int config : Arrays.asList(0, 3, 2)) {
-            for (String setting: Arrays.asList(null, "0", "2", "1")) {
+        for (int config : asList(0, 3, 2)) {
+            for (String setting: asList(null, "0", "2", "1")) {
                 mPolicyTracker.mConfigMeteredMultipathPreference = config;
                 Settings.Global.putString(cr, settingName, setting);
                 mPolicyTracker.reevaluate();
@@ -6164,10 +6165,10 @@
         networkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, networkAgent);
         networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
         networkCallback.assertNoCallback();
-        checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
-                Arrays.asList(myIpv4DefaultRoute));
+        checkDirectlyConnectedRoutes(cbi.getLp(), asList(myIpv4Address),
+                asList(myIpv4DefaultRoute));
         checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
-                Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
+                asList(myIpv4Address), asList(myIpv4DefaultRoute));
 
         // Verify direct routes are added during subsequent link properties updates.
         LinkProperties newLp = new LinkProperties(lp);
@@ -6179,8 +6180,8 @@
         cbi = networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, networkAgent);
         networkCallback.assertNoCallback();
         checkDirectlyConnectedRoutes(cbi.getLp(),
-                Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
-                Arrays.asList(myIpv4DefaultRoute));
+                asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
+                asList(myIpv4DefaultRoute));
         mCm.unregisterNetworkCallback(networkCallback);
     }
 
@@ -6508,9 +6509,9 @@
                 mResolverParamsParcelCaptor.capture());
         ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
         assertEquals(1, resolvrParams.servers.length);
-        assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1"));
+        assertTrue(CollectionUtils.contains(resolvrParams.servers, "2001:db8::1"));
         // Opportunistic mode.
-        assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
+        assertTrue(CollectionUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
         reset(mMockDnsResolver);
 
         cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
@@ -6520,12 +6521,12 @@
                 mResolverParamsParcelCaptor.capture());
         resolvrParams = mResolverParamsParcelCaptor.getValue();
         assertEquals(2, resolvrParams.servers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
-                new String[]{"2001:db8::1", "192.0.2.1"}));
+        assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         // Opportunistic mode.
         assertEquals(2, resolvrParams.tlsServers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
-                new String[]{"2001:db8::1", "192.0.2.1"}));
+        assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         reset(mMockDnsResolver);
 
         final String TLS_SPECIFIER = "tls.example.com";
@@ -6540,8 +6541,8 @@
                 mResolverParamsParcelCaptor.capture());
         resolvrParams = mResolverParamsParcelCaptor.getValue();
         assertEquals(2, resolvrParams.servers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
-                new String[]{"2001:db8::1", "192.0.2.1"}));
+        assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         reset(mMockDnsResolver);
     }
 
@@ -6648,12 +6649,12 @@
                 mResolverParamsParcelCaptor.capture());
         ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
         assertEquals(2, resolvrParams.tlsServers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
-                new String[] { "2001:db8::1", "192.0.2.1" }));
+        assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         // Opportunistic mode.
         assertEquals(2, resolvrParams.tlsServers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
-                new String[] { "2001:db8::1", "192.0.2.1" }));
+        assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         reset(mMockDnsResolver);
         cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
         cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
@@ -6670,8 +6671,8 @@
                 mResolverParamsParcelCaptor.capture());
         resolvrParams = mResolverParamsParcelCaptor.getValue();
         assertEquals(2, resolvrParams.servers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
-                new String[] { "2001:db8::1", "192.0.2.1" }));
+        assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
 
@@ -6680,11 +6681,11 @@
                 mResolverParamsParcelCaptor.capture());
         resolvrParams = mResolverParamsParcelCaptor.getValue();
         assertEquals(2, resolvrParams.servers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
-                new String[] { "2001:db8::1", "192.0.2.1" }));
+        assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         assertEquals(2, resolvrParams.tlsServers.length);
-        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
-                new String[] { "2001:db8::1", "192.0.2.1" }));
+        assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+                asList("2001:db8::1", "192.0.2.1")));
         reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
 
@@ -7720,7 +7721,7 @@
         // Start the restricted profile, and check that the UID within it loses network access.
         when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
                 .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
-        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
+        when(mUserManager.getAliveUsers()).thenReturn(asList(PRIMARY_USER_INFO,
                 RESTRICTED_USER_INFO));
         // TODO: check that VPN app within restricted profile still has access, etc.
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
@@ -7731,7 +7732,7 @@
         assertNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Stop the restricted profile, and check that the UID within it has network access again.
-        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+        when(mUserManager.getAliveUsers()).thenReturn(asList(PRIMARY_USER_INFO));
 
         // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
@@ -8156,7 +8157,7 @@
     // networks, ConnectivityService does not guarantee the order in which callbacks are fired.
     private void assertBlockedCallbackInAnyOrder(TestNetworkCallback callback, boolean blocked,
             TestNetworkAgentWrapper... agents) {
-        final List<Network> expectedNetworks = Arrays.asList(agents).stream()
+        final List<Network> expectedNetworks = asList(agents).stream()
                 .map((agent) -> agent.getNetwork())
                 .collect(Collectors.toList());
 
@@ -8852,7 +8853,7 @@
                 mResolverParamsParcelCaptor.capture());
         ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
         assertEquals(1, resolvrParams.servers.length);
-        assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
+        assertTrue(CollectionUtils.contains(resolvrParams.servers, "8.8.8.8"));
 
         for (final LinkProperties stackedLp : stackedLpsAfterChange) {
             verify(mDeps).reportNetworkInterfaceForTransports(
@@ -9525,7 +9526,7 @@
         InOrder inOrder = inOrder(mMockNetd);
 
         // Update to new range which is old range minus APP1, i.e. only APP2
-        final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
+        final Set<UidRange> newRanges = new HashSet<>(asList(
                 new UidRange(vpnRange.start, APP1_UID - 1),
                 new UidRange(APP1_UID + 1, vpnRange.stop)));
         mMockVpn.setUids(newRanges);
@@ -10017,9 +10018,9 @@
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
 
         final UnderlyingNetworkInfo underlyingNetworkInfo =
-                new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
+                new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<>());
         mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
-        when(mDeps.getConnectionOwnerUid(anyInt(), any(), any())).thenReturn(42);
+        doReturn(42).when(mDeps).getConnectionOwnerUid(anyInt(), any(), any());
     }
 
     private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -10377,10 +10378,7 @@
         mService.registerConnectivityDiagnosticsCallback(
                 mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
 
-        // Block until all other events are done processing.
-        HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
-        verify(mConnectivityDiagnosticsCallback)
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
                 .onConnectivityReportAvailable(argThat(report -> {
                     return INTERFACE_NAME.equals(report.getLinkProperties().getInterfaceName())
                             && report.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR);
@@ -10414,13 +10412,13 @@
     }
 
     private boolean areConnDiagCapsRedacted(NetworkCapabilities nc) {
-        TestTransportInfo ti = (TestTransportInfo) nc.getTransportInfo();
+        TestTransportInfo ti = getTestTransportInfo(nc);
         return nc.getUids() == null
                 && nc.getAdministratorUids().length == 0
                 && nc.getOwnerUid() == Process.INVALID_UID
-                && getTestTransportInfo(nc).locationRedacted
-                && getTestTransportInfo(nc).localMacAddressRedacted
-                && getTestTransportInfo(nc).settingsRedacted;
+                && ti.locationRedacted
+                && ti.localMacAddressRedacted
+                && ti.settingsRedacted;
     }
 
     @Test
@@ -10428,12 +10426,10 @@
             throws Exception {
         setUpConnectivityDiagnosticsCallback();
 
-        // Block until all other events are done processing.
-        HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
         // Verify onConnectivityReport fired
-        verify(mConnectivityDiagnosticsCallback).onConnectivityReportAvailable(
-                argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
+                .onConnectivityReportAvailable(argThat(report ->
+                        areConnDiagCapsRedacted(report.getNetworkCapabilities())));
     }
 
     @Test
@@ -10444,11 +10440,8 @@
         // cellular network agent
         mCellNetworkAgent.notifyDataStallSuspected();
 
-        // Block until all other events are done processing.
-        HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
         // Verify onDataStallSuspected fired
-        verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS)).onDataStallSuspected(
                 argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
     }
 
@@ -10456,26 +10449,72 @@
     public void testConnectivityDiagnosticsCallbackOnConnectivityReported() throws Exception {
         setUpConnectivityDiagnosticsCallback();
 
+        // reset to ignore callbacks from setup
+        reset(mConnectivityDiagnosticsCallback);
+
         final Network n = mCellNetworkAgent.getNetwork();
         final boolean hasConnectivity = true;
         mService.reportNetworkConnectivity(n, hasConnectivity);
 
-        // Block until all other events are done processing.
-        HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
         // Verify onNetworkConnectivityReported fired
-        verify(mConnectivityDiagnosticsCallback)
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
                 .onNetworkConnectivityReported(eq(n), eq(hasConnectivity));
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
+                .onConnectivityReportAvailable(
+                        argThat(report ->
+                                areConnDiagCapsRedacted(report.getNetworkCapabilities())));
 
         final boolean noConnectivity = false;
         mService.reportNetworkConnectivity(n, noConnectivity);
 
+        // Wait for onNetworkConnectivityReported to fire
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
+                .onNetworkConnectivityReported(eq(n), eq(noConnectivity));
+
+        // Also expect a ConnectivityReport after NetworkMonitor asynchronously re-validates
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS).times(2))
+                .onConnectivityReportAvailable(
+                        argThat(report ->
+                                areConnDiagCapsRedacted(report.getNetworkCapabilities())));
+    }
+
+    @Test
+    public void testConnectivityDiagnosticsCallbackOnConnectivityReportedSeparateUid()
+            throws Exception {
+        setUpConnectivityDiagnosticsCallback();
+
+        // reset to ignore callbacks from setup
+        reset(mConnectivityDiagnosticsCallback);
+
+        // report known Connectivity from a different uid. Verify that network is not re-validated
+        // and this callback is not notified.
+        final Network n = mCellNetworkAgent.getNetwork();
+        final boolean hasConnectivity = true;
+        doAsUid(Process.myUid() + 1, () -> mService.reportNetworkConnectivity(n, hasConnectivity));
+
         // Block until all other events are done processing.
         HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
 
+        // Verify onNetworkConnectivityReported did not fire
+        verify(mConnectivityDiagnosticsCallback, never())
+                .onNetworkConnectivityReported(any(), anyBoolean());
+        verify(mConnectivityDiagnosticsCallback, never())
+                .onConnectivityReportAvailable(any());
+
+        // report different Connectivity from a different uid. Verify that network is re-validated
+        // and that this callback is notified.
+        final boolean noConnectivity = false;
+        doAsUid(Process.myUid() + 1, () -> mService.reportNetworkConnectivity(n, noConnectivity));
+
         // Wait for onNetworkConnectivityReported to fire
-        verify(mConnectivityDiagnosticsCallback)
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
                 .onNetworkConnectivityReported(eq(n), eq(noConnectivity));
+
+        // Also expect a ConnectivityReport after NetworkMonitor asynchronously re-validates
+        verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
+                .onConnectivityReportAvailable(
+                        argThat(report ->
+                                areConnDiagCapsRedacted(report.getNetworkCapabilities())));
     }
 
     @Test
@@ -10597,11 +10636,11 @@
         if (add) {
             inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(
                     new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
-                            toUidRangeStableParcels(vpnRanges), PREFERENCE_PRIORITY_VPN));
+                            toUidRangeStableParcels(vpnRanges), PREFERENCE_ORDER_VPN));
         } else {
             inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(
                     new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
-                            toUidRangeStableParcels(vpnRanges), PREFERENCE_PRIORITY_VPN));
+                            toUidRangeStableParcels(vpnRanges), PREFERENCE_ORDER_VPN));
         }
 
         inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
@@ -10629,7 +10668,7 @@
         verify(mProxyTracker, never()).sendProxyBroadcast();
 
         // Update to new range which is old range minus APP1, i.e. only APP2
-        final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
+        final Set<UidRange> newRanges = new HashSet<>(asList(
                 new UidRange(vpnRange.start, APP1_UID - 1),
                 new UidRange(APP1_UID + 1, vpnRange.stop)));
         mMockVpn.setUids(newRanges);
@@ -11075,7 +11114,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
+        assertEquals(PREFERENCE_ORDER_OEM, nri.mPreferenceOrder);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11105,7 +11144,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
+        assertEquals(PREFERENCE_ORDER_OEM, nri.mPreferenceOrder);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11132,7 +11171,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
+        assertEquals(PREFERENCE_ORDER_OEM, nri.mPreferenceOrder);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11156,7 +11195,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
+        assertEquals(PREFERENCE_ORDER_OEM, nri.mPreferenceOrder);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11230,7 +11269,7 @@
         final int secondUserTestPackageUid = UserHandle.getUid(SECONDARY_USER, TEST_PACKAGE_UID);
         final int thirdUserTestPackageUid = UserHandle.getUid(TERTIARY_USER, TEST_PACKAGE_UID);
         when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
-                Arrays.asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE, TERTIARY_USER_HANDLE));
+                asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE, TERTIARY_USER_HANDLE));
 
         // Arrange PackageManager mocks testing for users who have and don't have a package.
         mockGetApplicationInfoThrowsNameNotFound(TEST_PACKAGE_NAME, PRIMARY_USER_HANDLE);
@@ -11847,11 +11886,11 @@
         verify(mMockNetd, times(addUidRangesTimes)).networkAddUidRangesParcel(argThat(config ->
                 (useAnyIdForAdd ? true : addUidRangesNetId == config.netId)
                         && Arrays.equals(addedUidRanges, config.uidRanges)
-                        && PREFERENCE_PRIORITY_OEM == config.subPriority));
+                        && PREFERENCE_ORDER_OEM == config.subPriority));
         verify(mMockNetd, times(removeUidRangesTimes)).networkRemoveUidRangesParcel(
                 argThat(config -> (useAnyIdForRemove ? true : removeUidRangesNetId == config.netId)
                         && Arrays.equals(removedUidRanges, config.uidRanges)
-                        && PREFERENCE_PRIORITY_OEM == config.subPriority));
+                        && PREFERENCE_ORDER_OEM == config.subPriority));
         if (shouldDestroyNetwork) {
             verify(mMockNetd, times(1))
                     .networkDestroy((useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)));
@@ -12177,7 +12216,7 @@
         final int secondUser = 10;
         final UserHandle secondUserHandle = new UserHandle(secondUser);
         when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
-                Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+                asList(PRIMARY_USER_HANDLE, secondUserHandle));
 
         // Arrange PackageManager mocks
         final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
@@ -12218,7 +12257,7 @@
         final int secondUser = 10;
         final UserHandle secondUserHandle = new UserHandle(secondUser);
         when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
-                Arrays.asList(PRIMARY_USER_HANDLE));
+                asList(PRIMARY_USER_HANDLE));
 
         // Arrange PackageManager mocks
         final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
@@ -12246,7 +12285,7 @@
 
         // Send a broadcast indicating a user was added.
         when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
-                Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+                asList(PRIMARY_USER_HANDLE, secondUserHandle));
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
         addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
         processBroadcast(addedIntent);
@@ -12259,7 +12298,7 @@
 
         // Send a broadcast indicating a user was removed.
         when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
-                Arrays.asList(PRIMARY_USER_HANDLE));
+                asList(PRIMARY_USER_HANDLE));
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
         removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
         processBroadcast(removedIntent);
@@ -13006,7 +13045,7 @@
         // is not handled specially, the rules are always active as long as a preference is set.
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                PREFERENCE_ORDER_PROFILE));
 
         // The enterprise network is not ready yet.
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13021,11 +13060,10 @@
         inOrder.verify(mMockNetd).networkCreate(
                 nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                workAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                workAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE));
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                PREFERENCE_ORDER_PROFILE));
 
         // Make sure changes to the work agent send callbacks to the app in the work profile, but
         // not to the other apps.
@@ -13075,7 +13113,7 @@
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                PREFERENCE_ORDER_PROFILE));
         inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
 
         mCellNetworkAgent.disconnect();
@@ -13099,8 +13137,7 @@
         inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
                 workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                workAgent2.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                workAgent2.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE));
 
         workAgent2.setNetworkValid(true /* isStrictMode */);
         workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
@@ -13146,8 +13183,7 @@
         inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
                 mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                workAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                workAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE));
 
         registerDefaultNetworkCallbacks();
 
@@ -13162,8 +13198,7 @@
         mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
-                workAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                workAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE));
 
         workAgent.disconnect();
         mCellNetworkAgent.disconnect();
@@ -13208,8 +13243,7 @@
                 r -> r.run(), listener);
         listener.expectOnComplete();
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                workAgent.getNetwork().netId, uidRangeFor(testHandle2),
-                PREFERENCE_PRIORITY_PROFILE));
+                workAgent.getNetwork().netId, uidRangeFor(testHandle2), PREFERENCE_ORDER_PROFILE));
 
         mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13219,8 +13253,7 @@
                 r -> r.run(), listener);
         listener.expectOnComplete();
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                workAgent.getNetwork().netId, uidRangeFor(testHandle4),
-                PREFERENCE_PRIORITY_PROFILE));
+                workAgent.getNetwork().netId, uidRangeFor(testHandle4), PREFERENCE_ORDER_PROFILE));
 
         app4Cb.expectAvailableCallbacksValidated(workAgent);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13230,8 +13263,7 @@
                 r -> r.run(), listener);
         listener.expectOnComplete();
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
-                workAgent.getNetwork().netId, uidRangeFor(testHandle2),
-                PREFERENCE_PRIORITY_PROFILE));
+                workAgent.getNetwork().netId, uidRangeFor(testHandle2), PREFERENCE_ORDER_PROFILE));
 
         mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13260,7 +13292,7 @@
                 mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                PREFERENCE_ORDER_PROFILE));
 
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
         removedIntent.putExtra(Intent.EXTRA_USER, testHandle);
@@ -13268,7 +13300,7 @@
 
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                PREFERENCE_PRIORITY_PROFILE));
+                PREFERENCE_ORDER_PROFILE));
     }
 
     /**
@@ -13439,7 +13471,7 @@
         assertEquals(1, nris.size());
         assertTrue(nri.isMultilayerRequest());
         assertEquals(nri.getUids(), uidRangesForUids(uids));
-        assertEquals(PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED, nri.mPreferencePriority);
+        assertEquals(PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED, nri.mPreferenceOrder);
     }
 
     /**
@@ -13491,7 +13523,7 @@
         final Set<Integer> uids1 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
         final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
         final NativeUidRangeConfig config1 = new NativeUidRangeConfig(cellNetId, uidRanges1,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids1);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config1);
         inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
@@ -13503,7 +13535,7 @@
                 SECONDARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
         final UidRangeParcel[] uidRanges2 = toUidRangeStableParcels(uidRangesForUids(uids2));
         final NativeUidRangeConfig config2 = new NativeUidRangeConfig(cellNetId, uidRanges2,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids2);
         inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config1);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config2);
@@ -13551,7 +13583,7 @@
         final Set<Integer> uids = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
         final UidRangeParcel[] uidRanges = toUidRangeStableParcels(uidRangesForUids(uids));
         final NativeUidRangeConfig wifiConfig = new NativeUidRangeConfig(wifiNetId, uidRanges,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(wifiConfig);
         inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
@@ -13567,7 +13599,7 @@
 
         final int cellNetId = mCellNetworkAgent.getNetwork().netId;
         final NativeUidRangeConfig cellConfig = new NativeUidRangeConfig(cellNetId, uidRanges,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
         inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
                 cellNetId, INetd.PERMISSION_NONE));
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(cellConfig);
@@ -13596,7 +13628,7 @@
 
         final int cellNetId2 = mCellNetworkAgent.getNetwork().netId;
         final NativeUidRangeConfig cellConfig2 = new NativeUidRangeConfig(cellNetId2, uidRanges,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
         inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
                 cellNetId2, INetd.PERMISSION_NONE));
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(cellConfig2);
@@ -13695,7 +13727,7 @@
         final int[] uids1 = new int[] { PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID) };
         final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
         final NativeUidRangeConfig config1 = new NativeUidRangeConfig(cellNetId, uidRanges1,
-                PREFERENCE_PRIORITY_OEM);
+                PREFERENCE_ORDER_OEM);
         setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges1, TEST_PACKAGE_NAME);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config1);
         inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
@@ -13709,7 +13741,7 @@
                 r -> r.run(), listener);
         listener.expectOnComplete();
         final NativeUidRangeConfig config2 = new NativeUidRangeConfig(workAgent.getNetwork().netId,
-                uidRangeFor(testHandle), PREFERENCE_PRIORITY_PROFILE);
+                uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE);
         inorder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
                 workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
@@ -13719,7 +13751,7 @@
         final Set<Integer> uids2 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID2));
         final UidRangeParcel[] uidRanges2 = toUidRangeStableParcels(uidRangesForUids(uids2));
         final NativeUidRangeConfig config3 = new NativeUidRangeConfig(cellNetId, uidRanges2,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids2);
         inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config3);
@@ -13728,7 +13760,7 @@
         final Set<Integer> uids3 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID3));
         final UidRangeParcel[] uidRanges3 = toUidRangeStableParcels(uidRangesForUids(uids3));
         final NativeUidRangeConfig config4 = new NativeUidRangeConfig(cellNetId, uidRanges3,
-                PREFERENCE_PRIORITY_OEM);
+                PREFERENCE_ORDER_OEM);
         setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges3, "com.android.test");
         inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config1);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config4);
@@ -13742,7 +13774,7 @@
 
         // Set MOBILE_DATA_PREFERRED_UIDS setting again with same uid as oem network preference.
         final NativeUidRangeConfig config6 = new NativeUidRangeConfig(cellNetId, uidRanges3,
-                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+                PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids3);
         inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config3);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config6);