Merge "Replace clearAll with withoutDefaultCapabilities" into sc-dev
diff --git a/framework/Android.bp b/framework/Android.bp
index bb93af9..a75792c 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -102,7 +102,7 @@
         // Tests using hidden APIs
         "//cts/tests/netlegacy22.api",
         "//external/sl4a:__subpackages__",
-        "//frameworks/base/tests/net:__subpackages__",
+        "//frameworks/base/packages/Connectivity/tests:__subpackages__",
         "//frameworks/libs/net/common/testutils",
         "//frameworks/libs/net/common/tests:__subpackages__",
         "//frameworks/opt/telephony/tests/telephonytests",
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 78dff21..b219375 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -57,7 +57,7 @@
     method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
     method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
     method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
-    method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context);
+    method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context);
     method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
     method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
     method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
@@ -65,6 +65,7 @@
     method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
     method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
     method public static int getPrivateDnsMode(@NonNull android.content.Context);
+    method @NonNull public static java.util.Set<java.lang.String> getRestrictedAllowedApps(@NonNull android.content.Context);
     method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
     method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
     method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
@@ -76,7 +77,7 @@
     method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
     method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
     method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
-    method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String);
+    method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
     method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
     method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
     method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
@@ -84,6 +85,7 @@
     method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
     method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
     method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
+    method public static void setRestrictedAllowedApps(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.String>);
     method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
     method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
     field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
diff --git a/framework/jni/android_net_NetworkUtils.cpp b/framework/jni/android_net_NetworkUtils.cpp
index 9bf910b..7478b3e 100644
--- a/framework/jni/android_net_NetworkUtils.cpp
+++ b/framework/jni/android_net_NetworkUtils.cpp
@@ -64,7 +64,7 @@
         filter_code,
     };
 
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(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));
@@ -74,7 +74,7 @@
 static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     int optval_ignored = 0;
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &optval_ignored, sizeof(optval_ignored)) !=
         0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
@@ -107,7 +107,7 @@
 
 static jint android_net_utils_bindSocketToNetworkHandle(JNIEnv *env, jobject thiz, jobject javaFd,
                                                   jlong netHandle) {
-    return android_setsocknetwork(netHandle, AFileDescriptor_getFD(env, javaFd));
+    return android_setsocknetwork(netHandle, AFileDescriptor_getFd(env, javaFd));
 }
 
 static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
@@ -156,7 +156,7 @@
 }
 
 static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     int rcode;
     uint8_t buf[MAXPACKETSIZE] = {0};
 
@@ -182,7 +182,7 @@
 }
 
 static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     android_res_cancel(fd);
     jniSetFileDescriptorOfFD(env, javaFd, -1);
 }
@@ -210,7 +210,7 @@
         return NULL;
     }
 
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     struct tcp_repair_window trw = {};
     socklen_t size = sizeof(trw);
 
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 31e1fb0..07754e4 100644
--- a/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -28,8 +28,11 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.net.ConnectivityManager.MultipathPreference;
+import android.os.Process;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Range;
 
 import com.android.net.module.util.ProxyUtils;
@@ -38,6 +41,9 @@
 import java.lang.annotation.RetentionPolicy;
 import java.time.Duration;
 import java.util.List;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
 
 /**
  * A manager class for connectivity module settings.
@@ -330,12 +336,12 @@
             "network_metered_multipath_preference";
 
     /**
-     * A list of apps that should go on cellular networks in preference even when higher-priority
+     * A list of uids that should go on cellular networks in preference even when higher-priority
      * networks are connected.
      *
      * @hide
      */
-    public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps";
+    public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids";
 
     /**
      * One of the private DNS modes that indicates the private DNS mode is off.
@@ -369,6 +375,13 @@
     private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
 
     /**
+     * A list of apps that should be granted netd system permission for using restricted networks.
+     *
+     * @hide
+     */
+    public static final String RESTRICTED_ALLOWED_APPS = "restricted_allowed_apps";
+
+    /**
      * Get mobile data activity timeout from {@link Settings}.
      *
      * @param context The {@link Context} to query the setting.
@@ -991,27 +1004,88 @@
     }
 
     /**
-     * Get the list of apps(from {@link Settings}) that should go on cellular networks in preference
+     * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference
      * even when higher-priority networks are connected.
      *
      * @param context The {@link Context} to query the setting.
-     * @return A list of apps that should go on cellular networks in preference even when
+     * @return A list of uids that should go on cellular networks in preference even when
      *         higher-priority networks are connected or null if no setting value.
      */
-    @Nullable
-    public static String getMobileDataPreferredApps(@NonNull Context context) {
-        return Settings.Secure.getString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS);
+    @NonNull
+    public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) {
+        final String uidList = Settings.Secure.getString(
+                context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS);
+        final Set<Integer> uids = new ArraySet<>();
+        if (TextUtils.isEmpty(uidList)) {
+            return uids;
+        }
+        for (String uid : uidList.split(";")) {
+            uids.add(Integer.valueOf(uid));
+        }
+        return uids;
     }
 
     /**
-     * Set the list of apps(to {@link Settings}) that should go on cellular networks in preference
+     * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference
      * even when higher-priority networks are connected.
      *
      * @param context The {@link Context} to set the setting.
-     * @param list A list of apps that should go on cellular networks in preference even when
+     * @param uidList A list of uids that should go on cellular networks in preference even when
      *             higher-priority networks are connected.
      */
-    public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) {
-        Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list);
+    public static void setMobileDataPreferredUids(@NonNull Context context,
+            @NonNull Set<Integer> uidList) {
+        final StringJoiner joiner = new StringJoiner(";");
+        for (Integer uid : uidList) {
+            if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
+                throw new IllegalArgumentException("Invalid uid");
+            }
+            joiner.add(uid.toString());
+        }
+        Settings.Secure.putString(
+                context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, joiner.toString());
+    }
+
+    /**
+     * Get the list of apps(from {@link Settings}) that should be granted netd system permission for
+     * using restricted networks.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return A list of apps that should be granted netd system permission for using restricted
+     *         networks or null if no setting value.
+     */
+    @NonNull
+    public static Set<String> getRestrictedAllowedApps(@NonNull Context context) {
+        final String appList = Settings.Secure.getString(
+                context.getContentResolver(), RESTRICTED_ALLOWED_APPS);
+        if (TextUtils.isEmpty(appList)) {
+            return new ArraySet<>();
+        }
+        return new ArraySet<>(appList.split(";"));
+    }
+
+    /**
+     * Set the list of apps(from {@link Settings}) that should be granted netd system permission for
+     * using restricted networks.
+     *
+     * Note: Please refer to android developer guidelines for valid app(package name).
+     * https://developer.android.com/guide/topics/manifest/manifest-element.html#package
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param list A list of apps that should be granted netd system permission for using
+     *             restricted networks.
+     */
+    public static void setRestrictedAllowedApps(@NonNull Context context,
+            @NonNull Set<String> list) {
+        final Pattern appPattern = Pattern.compile("[a-zA-Z_0-9]+([.][a-zA-Z_0-9]+)*");
+        final StringJoiner joiner = new StringJoiner(";");
+        for (String app : list) {
+            if (!appPattern.matcher(app).matches()) {
+                throw new IllegalArgumentException("Invalid app(package name)");
+            }
+            joiner.add(app);
+        }
+        Settings.Secure.putString(
+                context.getContentResolver(), RESTRICTED_ALLOWED_APPS, joiner.toString());
     }
 }
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index b3bb451..4932952 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -139,19 +139,13 @@
      */
     private String mRequestorPackageName;
 
-    /**
-     * Indicates what fields should be redacted from this instance.
-     */
-    private final @RedactionType long mRedactions;
-
     public NetworkCapabilities() {
-        mRedactions = REDACT_ALL;
         clearAll();
         mNetworkCapabilities = DEFAULT_CAPABILITIES;
     }
 
     public NetworkCapabilities(NetworkCapabilities nc) {
-        this(nc, REDACT_ALL);
+        this(nc, REDACT_NONE);
     }
 
     /**
@@ -163,10 +157,12 @@
      * @hide
      */
     public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) {
-        mRedactions = redactions;
         if (nc != null) {
             set(nc);
         }
+        if (mTransportInfo != null) {
+            mTransportInfo = nc.mTransportInfo.makeCopy(redactions);
+        }
     }
 
     /**
@@ -175,14 +171,6 @@
      * @hide
      */
     public void clearAll() {
-        // Ensures that the internal copies maintained by the connectivity stack does not set it to
-        // anything other than |REDACT_ALL|.
-        if (mRedactions != REDACT_ALL) {
-            // This is needed because the current redaction mechanism relies on redaction while
-            // parceling.
-            throw new UnsupportedOperationException(
-                    "Cannot clear NetworkCapabilities when mRedactions is set");
-        }
         mNetworkCapabilities = mTransportTypes = mForbiddenNetworkCapabilities = 0;
         mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
         mNetworkSpecifier = null;
@@ -211,7 +199,7 @@
         mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
         mNetworkSpecifier = nc.mNetworkSpecifier;
         if (nc.getTransportInfo() != null) {
-            setTransportInfo(nc.getTransportInfo().makeCopy(mRedactions));
+            setTransportInfo(nc.getTransportInfo());
         } else {
             setTransportInfo(null);
         }
@@ -839,8 +827,17 @@
         final int[] originalAdministratorUids = getAdministratorUids();
         final TransportInfo originalTransportInfo = getTransportInfo();
         clearAll();
-        mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS)
-                | (1 << TRANSPORT_TEST);
+        if (0 != (originalCapabilities & NET_CAPABILITY_NOT_RESTRICTED)) {
+            // If the test network is not restricted, then it is only allowed to declare some
+            // specific transports. This is to minimize impact on running apps in case an app
+            // run from the shell creates a test a network.
+            mTransportTypes =
+                    (originalTransportTypes & UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS)
+                            | (1 << TRANSPORT_TEST);
+        } else {
+            // If the test transport is restricted, then it may declare any transport.
+            mTransportTypes = (originalTransportTypes | (1 << TRANSPORT_TEST));
+        }
         mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
         mNetworkSpecifier = originalSpecifier;
         mSignalStrength = originalSignalStrength;
@@ -951,9 +948,10 @@
     };
 
     /**
-     * Allowed transports on a test network, in addition to TRANSPORT_TEST.
+     * Allowed transports on an unrestricted test network (in addition to TRANSPORT_TEST).
      */
-    private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST
+    private static final int UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS =
+            1 << TRANSPORT_TEST
             // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
             | 1 << TRANSPORT_ETHERNET
             // Test VPN networks can be created but their UID ranges must be empty.
@@ -2476,7 +2474,8 @@
          * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
          * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
          * to be selected. This is logically different than
-         * {@code NetworkCapabilities.NET_CAPABILITY_*}.
+         * {@code NetworkCapabilities.NET_CAPABILITY_*}. Also note that multiple networks with the
+         * same transport type may be active concurrently.
          *
          * @param transportType the transport type to be added or removed.
          * @return this builder
diff --git a/service/Android.bp b/service/Android.bp
index 20ccf06..813a239 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -54,7 +54,7 @@
     sdk_version: "system_server_current",
     min_sdk_version: "30",
     srcs: [
-        ":connectivity-service-srcs",
+        "src/**/*.java",
         ":framework-connectivity-shared-srcs",
         ":services-connectivity-shared-srcs",
         // TODO: move to net-utils-device-common, enable shrink optimization to avoid extra classes
diff --git a/service/lint-baseline.xml b/service/lint-baseline.xml
index 35ea2d3..95c169c 100644
--- a/service/lint-baseline.xml
+++ b/service/lint-baseline.xml
@@ -7,8 +7,8 @@
         errorLine1="            if (tm.isDataCapable()) {"
         errorLine2="                   ~~~~~~~~~~~~~">
         <location
-            file="frameworks/base/services/core/java/com/android/server/ConnectivityService.java"
-            line="781"
+            file="frameworks/base/packages/Connectivity/service/src/com/android/server/ConnectivityService.java"
+            line="787"
             column="20"/>
     </issue>
 
@@ -18,8 +18,8 @@
         errorLine1="                mUserAllContext.sendStickyBroadcast(intent, options);"
         errorLine2="                                ~~~~~~~~~~~~~~~~~~~">
         <location
-            file="frameworks/base/services/core/java/com/android/server/ConnectivityService.java"
-            line="2633"
+            file="frameworks/base/packages/Connectivity/service/src/com/android/server/ConnectivityService.java"
+            line="2681"
             column="33"/>
     </issue>
 
@@ -29,8 +29,8 @@
         errorLine1="            final int callingVersion = pm.getTargetSdkVersion(callingPackageName);"
         errorLine2="                                          ~~~~~~~~~~~~~~~~~~~">
         <location
-            file="frameworks/base/services/core/java/com/android/server/ConnectivityService.java"
-            line="5784"
+            file="frameworks/base/packages/Connectivity/service/src/com/android/server/ConnectivityService.java"
+            line="5851"
             column="43"/>
     </issue>
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
similarity index 99%
rename from services/core/java/com/android/server/ConnectivityService.java
rename to service/src/com/android/server/ConnectivityService.java
index ae14e37..ed2fe82 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -133,6 +133,8 @@
 import android.net.IpPrefix;
 import android.net.LinkProperties;
 import android.net.MatchAllNetworkSpecifier;
+import android.net.NativeNetworkConfig;
+import android.net.NativeNetworkType;
 import android.net.NattSocketKeepalive;
 import android.net.Network;
 import android.net.NetworkAgent;
@@ -3821,36 +3823,43 @@
         nai.onNetworkDestroyed();
     }
 
-    private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+    private boolean createNativeNetwork(@NonNull NetworkAgentInfo nai) {
         try {
             // This should never fail.  Specifying an already in use NetID will cause failure.
-            if (networkAgent.isVPN()) {
-                mNetd.networkCreateVpn(networkAgent.network.getNetId(),
-                        (networkAgent.networkAgentConfig == null
-                                || !networkAgent.networkAgentConfig.allowBypass));
+            final NativeNetworkConfig config;
+            if (nai.isVPN()) {
+                if (getVpnType(nai) == VpnManager.TYPE_VPN_NONE) {
+                    Log.wtf(TAG, "Unable to get VPN type from network " + nai.toShortString());
+                    return false;
+                }
+                config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.VIRTUAL,
+                        INetd.PERMISSION_NONE,
+                        (nai.networkAgentConfig == null || !nai.networkAgentConfig.allowBypass),
+                        getVpnType(nai));
             } else {
-                mNetd.networkCreatePhysical(networkAgent.network.getNetId(),
-                        getNetworkPermission(networkAgent.networkCapabilities));
+                config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.PHYSICAL,
+                        getNetworkPermission(nai.networkCapabilities), /*secure=*/ false,
+                        VpnManager.TYPE_VPN_NONE);
             }
-            mDnsResolver.createNetworkCache(networkAgent.network.getNetId());
-            mDnsManager.updateTransportsForNetwork(networkAgent.network.getNetId(),
-                    networkAgent.networkCapabilities.getTransportTypes());
+            mNetd.networkCreate(config);
+            mDnsResolver.createNetworkCache(nai.network.getNetId());
+            mDnsManager.updateTransportsForNetwork(nai.network.getNetId(),
+                    nai.networkCapabilities.getTransportTypes());
             return true;
         } catch (RemoteException | ServiceSpecificException e) {
-            loge("Error creating network " + networkAgent.network.getNetId() + ": "
-                    + e.getMessage());
+            loge("Error creating network " + nai.toShortString() + ": " + e.getMessage());
             return false;
         }
     }
 
-    private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+    private void destroyNativeNetwork(@NonNull NetworkAgentInfo nai) {
         try {
-            mNetd.networkDestroy(networkAgent.network.getNetId());
+            mNetd.networkDestroy(nai.network.getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
             loge("Exception destroying network(networkDestroy): " + e);
         }
         try {
-            mDnsResolver.destroyNetworkCache(networkAgent.network.getNetId());
+            mDnsResolver.destroyNetworkCache(nai.network.getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
             loge("Exception destroying network: " + e);
         }
@@ -9134,7 +9143,8 @@
     }
 
     private NetworkCapabilities getNetworkCapabilitiesWithoutUids(@NonNull NetworkCapabilities nc) {
-        final NetworkCapabilities sanitized = new NetworkCapabilities(nc);
+        final NetworkCapabilities sanitized = new NetworkCapabilities(nc,
+                NetworkCapabilities.REDACT_ALL);
         sanitized.setUids(null);
         sanitized.setAdministratorUids(new int[0]);
         sanitized.setOwnerUid(Process.INVALID_UID);
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/service/src/com/android/server/ConnectivityServiceInitializer.java
similarity index 100%
rename from services/core/java/com/android/server/ConnectivityServiceInitializer.java
rename to service/src/com/android/server/ConnectivityServiceInitializer.java
diff --git a/services/core/java/com/android/server/NetIdManager.java b/service/src/com/android/server/NetIdManager.java
similarity index 100%
rename from services/core/java/com/android/server/NetIdManager.java
rename to service/src/com/android/server/NetIdManager.java
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
similarity index 100%
rename from services/core/java/com/android/server/TestNetworkService.java
rename to service/src/com/android/server/TestNetworkService.java
diff --git a/services/core/java/com/android/server/connectivity/AutodestructReference.java b/service/src/com/android/server/connectivity/AutodestructReference.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/AutodestructReference.java
rename to service/src/com/android/server/connectivity/AutodestructReference.java
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/service/src/com/android/server/connectivity/DnsManager.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/DnsManager.java
rename to service/src/com/android/server/connectivity/DnsManager.java
diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/FullScore.java
rename to service/src/com/android/server/connectivity/FullScore.java
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/service/src/com/android/server/connectivity/KeepaliveTracker.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/KeepaliveTracker.java
rename to service/src/com/android/server/connectivity/KeepaliveTracker.java
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/service/src/com/android/server/connectivity/LingerMonitor.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/LingerMonitor.java
rename to service/src/com/android/server/connectivity/LingerMonitor.java
diff --git a/service/src/com/android/server/connectivity/MockableSystemProperties.java b/service/src/com/android/server/connectivity/MockableSystemProperties.java
new file mode 100644
index 0000000..a25b89a
--- /dev/null
+++ b/service/src/com/android/server/connectivity/MockableSystemProperties.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.server.connectivity;
+
+import android.os.SystemProperties;
+
+public class MockableSystemProperties {
+
+    public String get(String key) {
+        return SystemProperties.get(key);
+    }
+
+    public int getInt(String key, int def) {
+        return SystemProperties.getInt(key, def);
+    }
+
+    public boolean getBoolean(String key, boolean def) {
+        return SystemProperties.getBoolean(key, def);
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/service/src/com/android/server/connectivity/Nat464Xlat.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/Nat464Xlat.java
rename to service/src/com/android/server/connectivity/Nat464Xlat.java
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
rename to service/src/com/android/server/connectivity/NetworkAgentInfo.java
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
rename to service/src/com/android/server/connectivity/NetworkDiagnostics.java
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
rename to service/src/com/android/server/connectivity/NetworkNotificationManager.java
diff --git a/services/core/java/com/android/server/connectivity/NetworkOffer.java b/service/src/com/android/server/connectivity/NetworkOffer.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/NetworkOffer.java
rename to service/src/com/android/server/connectivity/NetworkOffer.java
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/service/src/com/android/server/connectivity/NetworkRanker.java
similarity index 77%
rename from services/core/java/com/android/server/connectivity/NetworkRanker.java
rename to service/src/com/android/server/connectivity/NetworkRanker.java
index e839837..a4085cd 100644
--- a/services/core/java/com/android/server/connectivity/NetworkRanker.java
+++ b/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -108,7 +108,58 @@
         }
     }
 
-    @Nullable private <T extends Scoreable> T getBestNetworkByPolicy(
+    private <T extends Scoreable> boolean isBadWiFi(@NonNull final T candidate) {
+        return candidate.getScore().hasPolicy(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD)
+                && candidate.getCapsNoCopy().hasTransport(TRANSPORT_WIFI);
+    }
+
+    /**
+     * Apply the "yield to bad WiFi" policy.
+     *
+     * This function must run immediately after the validation policy.
+     *
+     * If any of the accepted networks has the "yield to bad WiFi" policy AND there are some
+     * bad WiFis in the rejected list, then move the networks with the policy to the rejected
+     * list. If this leaves no accepted network, then move the bad WiFis back to the accepted list.
+     *
+     * This function returns nothing, but will have updated accepted and rejected in-place.
+     *
+     * @param accepted networks accepted by the validation policy
+     * @param rejected networks rejected by the validation policy
+     */
+    private <T extends Scoreable> void applyYieldToBadWifiPolicy(@NonNull ArrayList<T> accepted,
+            @NonNull ArrayList<T> rejected) {
+        if (!CollectionUtils.any(accepted, n -> n.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI))) {
+            // No network with the policy : do nothing.
+            return;
+        }
+        if (!CollectionUtils.any(rejected, n -> isBadWiFi(n))) {
+            // No bad WiFi : do nothing.
+            return;
+        }
+        if (CollectionUtils.all(accepted, n -> n.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI))) {
+            // All validated networks yield to bad WiFis : keep bad WiFis alongside with the
+            // yielders. This is important because the yielders need to be compared to the bad
+            // wifis by the following policies (e.g. exiting).
+            final ArrayList<T> acceptedYielders = new ArrayList<>(accepted);
+            final ArrayList<T> rejectedWithBadWiFis = new ArrayList<>(rejected);
+            partitionInto(rejectedWithBadWiFis, n -> isBadWiFi(n), accepted, rejected);
+            accepted.addAll(acceptedYielders);
+            return;
+        }
+        // Only some of the validated networks yield to bad WiFi : keep only the ones who don't.
+        final ArrayList<T> acceptedWithYielders = new ArrayList<>(accepted);
+        partitionInto(acceptedWithYielders, n -> !n.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI),
+                accepted, rejected);
+    }
+
+    /**
+     * Get the best network among a list of candidates according to policy.
+     * @param candidates the candidates
+     * @param currentSatisfier the current satisfier, or null if none
+     * @return the best network
+     */
+    @Nullable public <T extends Scoreable> T getBestNetworkByPolicy(
             @NonNull List<T> candidates,
             @Nullable final T currentSatisfier) {
         // Used as working areas.
@@ -148,24 +199,15 @@
         if (accepted.size() == 1) return accepted.get(0);
         if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
 
-        // Yield to bad wifi policy : if any wifi has ever been validated (even if it's now
-        // unvalidated), and unless it's been explicitly avoided when bad in UI, then keep only
-        // networks that don't yield to such a wifi network.
-        final boolean anyWiFiEverValidated = CollectionUtils.any(candidates,
-                nai -> nai.getScore().hasPolicy(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD)
-                        && nai.getCapsNoCopy().hasTransport(TRANSPORT_WIFI));
-        if (anyWiFiEverValidated) {
-            partitionInto(candidates, nai -> !nai.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI),
-                    accepted, rejected);
-            if (accepted.size() == 1) return accepted.get(0);
-            if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
-        }
-
         // If any network is validated (or should be accepted even if it's not validated), then
         // don't choose one that isn't.
         partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_IS_VALIDATED)
                         || nai.getScore().hasPolicy(POLICY_ACCEPT_UNVALIDATED),
                 accepted, rejected);
+        // Yield to bad wifi policy : if any network has the "yield to bad WiFi" policy and
+        // there are bad WiFis connected, then accept the bad WiFis and reject the networks with
+        // the policy.
+        applyYieldToBadWifiPolicy(accepted, rejected);
         if (accepted.size() == 1) return accepted.get(0);
         if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
 
@@ -194,16 +236,24 @@
         // subscription with the same transport.
         partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY),
                 accepted, rejected);
-        for (final Scoreable defaultSubNai : accepted) {
-            // Remove all networks without the DEFAULT_SUBSCRIPTION policy and the same transports
-            // as a network that has it.
-            final int[] transports = defaultSubNai.getCapsNoCopy().getTransportTypes();
-            candidates.removeIf(nai -> !nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY)
-                    && Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes()));
+        if (accepted.size() > 0) {
+            // Some networks are primary. For each transport, keep only the primary, but also
+            // keep all networks for which there isn't a primary (which are now in the |rejected|
+            // array).
+            // So for each primary network, remove from |rejected| all networks with the same
+            // transports as one of the primary networks. The remaining networks should be accepted.
+            for (final T defaultSubNai : accepted) {
+                final int[] transports = defaultSubNai.getCapsNoCopy().getTransportTypes();
+                rejected.removeIf(
+                        nai -> Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes()));
+            }
+            accepted.addAll(rejected);
+            candidates = new ArrayList<>(accepted);
         }
         if (1 == candidates.size()) return candidates.get(0);
-        // It's guaranteed candidates.size() > 0 because there is at least one with the
-        // TRANSPORT_PRIMARY policy and only those without it were removed.
+        // If there were no primary network, then candidates.size() > 0 because it didn't
+        // change from the previous result. If there were, it's guaranteed candidates.size() > 0
+        // because accepted.size() > 0 above.
 
         // If some of the networks have a better transport than others, keep only the ones with
         // the best transports.
diff --git a/services/core/java/com/android/server/connectivity/OsCompat.java b/service/src/com/android/server/connectivity/OsCompat.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/OsCompat.java
rename to service/src/com/android/server/connectivity/OsCompat.java
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
similarity index 99%
rename from services/core/java/com/android/server/connectivity/PermissionMonitor.java
rename to service/src/com/android/server/connectivity/PermissionMonitor.java
index 28f208b..5886b1a 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -338,7 +338,8 @@
             return currentPermission;
         }
         try {
-            final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
+            final PackageInfo app = mPackageManager.getPackageInfo(name,
+                    GET_PERMISSIONS | MATCH_ANY_USER);
             final boolean isNetwork = hasNetworkPermission(app);
             final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
             if (isNetwork || hasRestrictedPermission) {
@@ -664,6 +665,7 @@
                     break;
                 case INetd.PERMISSION_UNINSTALLED:
                     uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+                    break;
                 default:
                     Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
                             + netdPermissionsAppIds.keyAt(i));
diff --git a/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java b/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java
rename to service/src/com/android/server/connectivity/ProfileNetworkPreferences.java
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/service/src/com/android/server/connectivity/ProxyTracker.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/ProxyTracker.java
rename to service/src/com/android/server/connectivity/ProxyTracker.java
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
rename to service/src/com/android/server/connectivity/QosCallbackAgentConnection.java
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/service/src/com/android/server/connectivity/QosCallbackTracker.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/QosCallbackTracker.java
rename to service/src/com/android/server/connectivity/QosCallbackTracker.java
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/service/src/com/android/server/connectivity/TcpKeepaliveController.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
rename to service/src/com/android/server/connectivity/TcpKeepaliveController.java
diff --git a/tests/OWNERS b/tests/OWNERS
new file mode 100644
index 0000000..d3836d4
--- /dev/null
+++ b/tests/OWNERS
@@ -0,0 +1,8 @@
+set noparent
+
+codewiz@google.com
+jchalard@google.com
+junyulai@google.com
+lorenzo@google.com
+reminv@google.com
+satk@google.com
diff --git a/tests/net/TEST_MAPPING b/tests/TEST_MAPPING
similarity index 100%
rename from tests/net/TEST_MAPPING
rename to tests/TEST_MAPPING
diff --git a/tests/net/common/Android.bp b/tests/common/Android.bp
similarity index 100%
rename from tests/net/common/Android.bp
rename to tests/common/Android.bp
diff --git a/tests/net/common/java/ParseExceptionTest.kt b/tests/common/java/ParseExceptionTest.kt
similarity index 100%
rename from tests/net/common/java/ParseExceptionTest.kt
rename to tests/common/java/ParseExceptionTest.kt
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/common/java/android/net/CaptivePortalDataTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/CaptivePortalDataTest.kt
rename to tests/common/java/android/net/CaptivePortalDataTest.kt
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/common/java/android/net/CaptivePortalTest.java
similarity index 100%
rename from tests/net/common/java/android/net/CaptivePortalTest.java
rename to tests/common/java/android/net/CaptivePortalTest.java
diff --git a/tests/net/common/java/android/net/DependenciesTest.java b/tests/common/java/android/net/DependenciesTest.java
similarity index 100%
rename from tests/net/common/java/android/net/DependenciesTest.java
rename to tests/common/java/android/net/DependenciesTest.java
diff --git a/tests/net/common/java/android/net/DhcpInfoTest.java b/tests/common/java/android/net/DhcpInfoTest.java
similarity index 100%
rename from tests/net/common/java/android/net/DhcpInfoTest.java
rename to tests/common/java/android/net/DhcpInfoTest.java
diff --git a/tests/net/common/java/android/net/IpPrefixTest.java b/tests/common/java/android/net/IpPrefixTest.java
similarity index 100%
rename from tests/net/common/java/android/net/IpPrefixTest.java
rename to tests/common/java/android/net/IpPrefixTest.java
diff --git a/tests/net/common/java/android/net/KeepalivePacketDataTest.kt b/tests/common/java/android/net/KeepalivePacketDataTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/KeepalivePacketDataTest.kt
rename to tests/common/java/android/net/KeepalivePacketDataTest.kt
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/common/java/android/net/LinkAddressTest.java
similarity index 100%
rename from tests/net/common/java/android/net/LinkAddressTest.java
rename to tests/common/java/android/net/LinkAddressTest.java
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/common/java/android/net/LinkPropertiesTest.java
similarity index 100%
rename from tests/net/common/java/android/net/LinkPropertiesTest.java
rename to tests/common/java/android/net/LinkPropertiesTest.java
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/common/java/android/net/MatchAllNetworkSpecifierTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
rename to tests/common/java/android/net/MatchAllNetworkSpecifierTest.kt
diff --git a/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt b/tests/common/java/android/net/NattKeepalivePacketDataTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt
rename to tests/common/java/android/net/NattKeepalivePacketDataTest.kt
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/common/java/android/net/NetworkAgentConfigTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/NetworkAgentConfigTest.kt
rename to tests/common/java/android/net/NetworkAgentConfigTest.kt
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
similarity index 99%
rename from tests/net/common/java/android/net/NetworkCapabilitiesTest.java
rename to tests/common/java/android/net/NetworkCapabilitiesTest.java
index 1c8a1bf..9efdde4 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -341,7 +341,7 @@
 
     private void testParcelSane(NetworkCapabilities cap) {
         if (isAtLeastS()) {
-            assertParcelSane(cap, 17);
+            assertParcelSane(cap, 16);
         } else if (isAtLeastR()) {
             assertParcelSane(cap, 15);
         } else {
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/common/java/android/net/NetworkProviderTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/NetworkProviderTest.kt
rename to tests/common/java/android/net/NetworkProviderTest.kt
diff --git a/tests/net/common/java/android/net/NetworkSpecifierTest.kt b/tests/common/java/android/net/NetworkSpecifierTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/NetworkSpecifierTest.kt
rename to tests/common/java/android/net/NetworkSpecifierTest.kt
diff --git a/tests/common/java/android/net/NetworkStackTest.java b/tests/common/java/android/net/NetworkStackTest.java
new file mode 100644
index 0000000..f8f9c72
--- /dev/null
+++ b/tests/common/java/android/net/NetworkStackTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Build;
+import android.os.IBinder;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkStackTest {
+    @Rule
+    public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
+
+    @Mock private IBinder mConnectorBinder;
+
+    @Before public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testGetService() {
+        NetworkStack.setServiceForTest(mConnectorBinder);
+        assertEquals(NetworkStack.getService(), mConnectorBinder);
+    }
+}
diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/tests/common/java/android/net/NetworkStateSnapshotTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
rename to tests/common/java/android/net/NetworkStateSnapshotTest.kt
diff --git a/tests/net/common/java/android/net/NetworkTest.java b/tests/common/java/android/net/NetworkTest.java
similarity index 100%
rename from tests/net/common/java/android/net/NetworkTest.java
rename to tests/common/java/android/net/NetworkTest.java
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/common/java/android/net/OemNetworkPreferencesTest.java
similarity index 100%
rename from tests/net/common/java/android/net/OemNetworkPreferencesTest.java
rename to tests/common/java/android/net/OemNetworkPreferencesTest.java
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/common/java/android/net/RouteInfoTest.java
similarity index 100%
rename from tests/net/common/java/android/net/RouteInfoTest.java
rename to tests/common/java/android/net/RouteInfoTest.java
diff --git a/tests/net/common/java/android/net/StaticIpConfigurationTest.java b/tests/common/java/android/net/StaticIpConfigurationTest.java
similarity index 100%
rename from tests/net/common/java/android/net/StaticIpConfigurationTest.java
rename to tests/common/java/android/net/StaticIpConfigurationTest.java
diff --git a/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt b/tests/common/java/android/net/TcpKeepalivePacketDataTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt
rename to tests/common/java/android/net/TcpKeepalivePacketDataTest.kt
diff --git a/tests/net/common/java/android/net/UidRangeTest.java b/tests/common/java/android/net/UidRangeTest.java
similarity index 100%
rename from tests/net/common/java/android/net/UidRangeTest.java
rename to tests/common/java/android/net/UidRangeTest.java
diff --git a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt b/tests/common/java/android/net/UnderlyingNetworkInfoTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
rename to tests/common/java/android/net/UnderlyingNetworkInfoTest.kt
diff --git a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java b/tests/common/java/android/net/apf/ApfCapabilitiesTest.java
similarity index 100%
rename from tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
rename to tests/common/java/android/net/apf/ApfCapabilitiesTest.java
diff --git a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt b/tests/common/java/android/net/metrics/ApfProgramEventTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt
rename to tests/common/java/android/net/metrics/ApfProgramEventTest.kt
diff --git a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt b/tests/common/java/android/net/metrics/ApfStatsTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/metrics/ApfStatsTest.kt
rename to tests/common/java/android/net/metrics/ApfStatsTest.kt
diff --git a/tests/common/java/android/net/metrics/DhcpClientEventTest.kt b/tests/common/java/android/net/metrics/DhcpClientEventTest.kt
new file mode 100644
index 0000000..8d7a9c4
--- /dev/null
+++ b/tests/common/java/android/net/metrics/DhcpClientEventTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val FAKE_MESSAGE = "test"
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DhcpClientEventTest {
+    @Test
+    fun testBuilderAndParcel() {
+        val dhcpClientEvent = DhcpClientEvent.Builder()
+                .setMsg(FAKE_MESSAGE)
+                .setDurationMs(Integer.MAX_VALUE)
+                .build()
+
+        assertEquals(FAKE_MESSAGE, dhcpClientEvent.msg)
+        assertEquals(Integer.MAX_VALUE, dhcpClientEvent.durationMs)
+
+        assertParcelSane(dhcpClientEvent, 2)
+    }
+}
diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/tests/common/java/android/net/metrics/DhcpErrorEventTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
rename to tests/common/java/android/net/metrics/DhcpErrorEventTest.kt
diff --git a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java b/tests/common/java/android/net/metrics/IpConnectivityLogTest.java
similarity index 100%
rename from tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java
rename to tests/common/java/android/net/metrics/IpConnectivityLogTest.java
diff --git a/tests/common/java/android/net/metrics/IpManagerEventTest.kt b/tests/common/java/android/net/metrics/IpManagerEventTest.kt
new file mode 100644
index 0000000..64be508
--- /dev/null
+++ b/tests/common/java/android/net/metrics/IpManagerEventTest.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class IpManagerEventTest {
+    @Test
+    fun testConstructorAndParcel() {
+        (IpManagerEvent.PROVISIONING_OK..IpManagerEvent.ERROR_INTERFACE_NOT_FOUND).forEach {
+            val ipManagerEvent = IpManagerEvent(it, Long.MAX_VALUE)
+            assertEquals(it, ipManagerEvent.eventType)
+            assertEquals(Long.MAX_VALUE, ipManagerEvent.durationMs)
+
+            assertParcelSane(ipManagerEvent, 2)
+        }
+    }
+}
diff --git a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt b/tests/common/java/android/net/metrics/IpReachabilityEventTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt
rename to tests/common/java/android/net/metrics/IpReachabilityEventTest.kt
diff --git a/tests/common/java/android/net/metrics/NetworkEventTest.kt b/tests/common/java/android/net/metrics/NetworkEventTest.kt
new file mode 100644
index 0000000..41430b0
--- /dev/null
+++ b/tests/common/java/android/net/metrics/NetworkEventTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class NetworkEventTest {
+    @Test
+    fun testConstructorAndParcel() {
+        (NetworkEvent.NETWORK_CONNECTED..NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY).forEach {
+            var networkEvent = NetworkEvent(it)
+            assertEquals(it, networkEvent.eventType)
+            assertEquals(0, networkEvent.durationMs)
+
+            networkEvent = NetworkEvent(it, Long.MAX_VALUE)
+            assertEquals(it, networkEvent.eventType)
+            assertEquals(Long.MAX_VALUE, networkEvent.durationMs)
+
+            assertParcelSane(networkEvent, 2)
+        }
+    }
+}
diff --git a/tests/net/common/java/android/net/metrics/RaEventTest.kt b/tests/common/java/android/net/metrics/RaEventTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/metrics/RaEventTest.kt
rename to tests/common/java/android/net/metrics/RaEventTest.kt
diff --git a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt b/tests/common/java/android/net/metrics/ValidationProbeEventTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt
rename to tests/common/java/android/net/metrics/ValidationProbeEventTest.kt
diff --git a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt b/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt
rename to tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
diff --git a/tests/net/common/java/android/net/util/SocketUtilsTest.kt b/tests/common/java/android/net/util/SocketUtilsTest.kt
similarity index 100%
rename from tests/net/common/java/android/net/util/SocketUtilsTest.kt
rename to tests/common/java/android/net/util/SocketUtilsTest.kt
diff --git a/tests/deflake/Android.bp b/tests/deflake/Android.bp
new file mode 100644
index 0000000..58ece37
--- /dev/null
+++ b/tests/deflake/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2019 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_test_host {
+    name: "FrameworksNetDeflakeTest",
+    srcs: ["src/**/*.kt"],
+    libs: [
+        "junit",
+        "tradefed",
+    ],
+    static_libs: [
+        "kotlin-test",
+        "net-host-tests-utils",
+    ],
+    data: [":FrameworksNetTests"],
+    test_suites: ["device-tests"],
+}
diff --git a/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt b/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt
new file mode 100644
index 0000000..6285525
--- /dev/null
+++ b/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 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.server.net
+
+import com.android.testutils.host.DeflakeHostTestBase
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import org.junit.runner.RunWith
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class FrameworksNetDeflakeTest: DeflakeHostTestBase() {
+    override val runCount = 20
+    override val testApkFilename = "FrameworksNetTests.apk"
+    override val testClasses = listOf("com.android.server.ConnectivityServiceTest")
+}
\ No newline at end of file
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp
new file mode 100644
index 0000000..39c424e
--- /dev/null
+++ b/tests/integration/Android.bp
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2019 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "FrameworksNetIntegrationTests",
+    defaults: ["framework-connectivity-test-defaults"],
+    platform_apis: true,
+    certificate: "platform",
+    srcs: [
+        "src/**/*.kt",
+        "src/**/*.aidl",
+    ],
+    libs: [
+        "android.test.mock",
+    ],
+    static_libs: [
+        "NetworkStackApiStableLib",
+        "androidx.test.ext.junit",
+        "frameworks-net-integration-testutils",
+        "kotlin-reflect",
+        "mockito-target-extended-minus-junit4",
+        "net-tests-utils",
+        "service-connectivity",
+        "services.core",
+        "services.net",
+        "testables",
+    ],
+    test_suites: ["device-tests"],
+    use_embedded_native_libs: true,
+    jni_libs: [
+        // For mockito extended
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+        // android_library does not include JNI libs: include NetworkStack dependencies here
+        "libnativehelper_compat_libc++",
+        "libnetworkstackutilsjni",
+    ],
+}
+
+// Utilities for testing framework code both in integration and unit tests.
+java_library {
+    name: "frameworks-net-integration-testutils",
+    defaults: ["framework-connectivity-test-defaults"],
+    srcs: ["util/**/*.java", "util/**/*.kt"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.test.rules",
+        "junit",
+        "net-tests-utils",
+    ],
+    libs: [
+        "service-connectivity",
+        "services.core",
+        "services.net",
+    ],
+}
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/integration/AndroidManifest.xml
similarity index 100%
rename from tests/net/integration/AndroidManifest.xml
rename to tests/integration/AndroidManifest.xml
diff --git a/tests/net/integration/res/values/config.xml b/tests/integration/res/values/config.xml
similarity index 100%
rename from tests/net/integration/res/values/config.xml
rename to tests/integration/res/values/config.xml
diff --git a/tests/net/integration/src/android/net/TestNetworkStackClient.kt b/tests/integration/src/android/net/TestNetworkStackClient.kt
similarity index 100%
rename from tests/net/integration/src/android/net/TestNetworkStackClient.kt
rename to tests/integration/src/android/net/TestNetworkStackClient.kt
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
similarity index 100%
rename from tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
rename to tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
diff --git a/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl b/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl
new file mode 100644
index 0000000..9a2bcfe
--- /dev/null
+++ b/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.server.net.integrationtests;
+
+parcelable HttpResponse;
\ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt b/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
similarity index 100%
rename from tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
rename to tests/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
diff --git a/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl b/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl
new file mode 100644
index 0000000..efc58ad
--- /dev/null
+++ b/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 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.server.net.integrationtests;
+
+import com.android.server.net.integrationtests.HttpResponse;
+
+interface INetworkStackInstrumentation {
+    void clearAllState();
+    void addHttpResponse(in HttpResponse response);
+    List<String> getRequestUrls();
+}
\ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt b/tests/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
similarity index 100%
rename from tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
rename to tests/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
similarity index 100%
rename from tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
rename to tests/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/tests/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
similarity index 100%
rename from tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
rename to tests/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
similarity index 99%
rename from tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
rename to tests/integration/util/com/android/server/NetworkAgentWrapper.java
index 40d068d..17db179 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -381,4 +381,8 @@
             }
         }
     }
+
+    public boolean isBypassableVpn() {
+        return mNetworkAgentConfig.isBypassableVpn();
+    }
 }
diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/tests/integration/util/com/android/server/TestNetIdManager.kt
similarity index 100%
rename from tests/net/integration/util/com/android/server/TestNetIdManager.kt
rename to tests/integration/util/com/android/server/TestNetIdManager.kt
diff --git a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
deleted file mode 100644
index 551b94c..0000000
--- a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2020 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.server.connectivity
-
-import android.net.NetworkCapabilities
-import android.net.NetworkRequest
-import android.net.NetworkScore.KEEP_CONNECTED_NONE
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import kotlin.test.assertEquals
-import kotlin.test.assertNull
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkRankerTest {
-    private val ranker = NetworkRanker()
-
-    private fun makeNai(satisfy: Boolean, legacyScore: Int) =
-            mock(NetworkAgentInfo::class.java).also {
-                doReturn(satisfy).`when`(it).satisfies(any())
-                val fs = FullScore(legacyScore, 0 /* policies */, KEEP_CONNECTED_NONE)
-                doReturn(fs).`when`(it).getScore()
-                val nc = NetworkCapabilities.Builder().build()
-                doReturn(nc).`when`(it).getCapsNoCopy()
-            }
-
-    @Test
-    fun testGetBestNetwork() {
-        val scores = listOf(20, 50, 90, 60, 23, 68)
-        val nais = scores.map { makeNai(true, it) }
-        val bestNetwork = nais[2] // The one with the top score
-        val someRequest = mock(NetworkRequest::class.java)
-        assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais, bestNetwork))
-    }
-
-    @Test
-    fun testIgnoreNonSatisfying() {
-        val nais = listOf(makeNai(true, 20), makeNai(true, 50), makeNai(false, 90),
-                makeNai(false, 60), makeNai(true, 23), makeNai(false, 68))
-        val bestNetwork = nais[1] // Top score that's satisfying
-        val someRequest = mock(NetworkRequest::class.java)
-        assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais, nais[1]))
-    }
-
-    @Test
-    fun testNoMatch() {
-        val nais = listOf(makeNai(false, 20), makeNai(false, 50), makeNai(false, 90))
-        val someRequest = mock(NetworkRequest::class.java)
-        assertNull(ranker.getBestNetwork(someRequest, nais, null))
-    }
-
-    @Test
-    fun testEmpty() {
-        val someRequest = mock(NetworkRequest::class.java)
-        assertNull(ranker.getBestNetwork(someRequest, emptyList(), null))
-    }
-
-    // Make sure the ranker is "stable" (as in stable sort), that is, it always returns the FIRST
-    // network satisfying the request if multiple of them have the same score.
-    @Test
-    fun testStable() {
-        val nais1 = listOf(makeNai(true, 30), makeNai(true, 30), makeNai(true, 30),
-                makeNai(true, 30), makeNai(true, 30), makeNai(true, 30))
-        val someRequest = mock(NetworkRequest::class.java)
-        assertEquals(nais1[0], ranker.getBestNetwork(someRequest, nais1, nais1[0]))
-
-        val nais2 = listOf(makeNai(true, 30), makeNai(true, 50), makeNai(true, 20),
-                makeNai(true, 50), makeNai(true, 50), makeNai(true, 40))
-        assertEquals(nais2[1], ranker.getBestNetwork(someRequest, nais2, nais2[1]))
-    }
-}
diff --git a/tests/net/smoketest/Android.bp b/tests/smoketest/Android.bp
similarity index 100%
rename from tests/net/smoketest/Android.bp
rename to tests/smoketest/Android.bp
diff --git a/tests/smoketest/AndroidManifest.xml b/tests/smoketest/AndroidManifest.xml
new file mode 100644
index 0000000..f1b9feb
--- /dev/null
+++ b/tests/smoketest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.tests.net.smoketest">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.tests.net.smoketest"
+        android:label="Frameworks Networking Smoke Tests" />
+</manifest>
diff --git a/tests/smoketest/AndroidTest.xml b/tests/smoketest/AndroidTest.xml
new file mode 100644
index 0000000..ac366e4
--- /dev/null
+++ b/tests/smoketest/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Runs Frameworks Networking Smoke Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksNetSmokeTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksNetSmokeTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.frameworks.tests.net.smoketest" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/tests/smoketest/java/SmokeTest.java b/tests/smoketest/java/SmokeTest.java
new file mode 100644
index 0000000..7d6655f
--- /dev/null
+++ b/tests/smoketest/java/SmokeTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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.server.net;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class SmokeTest {
+
+    @Test
+    public void testLoadJni() {
+        System.loadLibrary("networkstatsfactorytestjni");
+        assertEquals(0, 0x00);
+    }
+}
diff --git a/tests/net/Android.bp b/tests/unit/Android.bp
similarity index 100%
rename from tests/net/Android.bp
rename to tests/unit/Android.bp
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
new file mode 100644
index 0000000..4c60ccf
--- /dev/null
+++ b/tests/unit/AndroidManifest.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.tests.net">
+
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.NETWORK_STACK" />
+    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.NETWORK_FACTORY" />
+    <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
+    <uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.net.ipsec.ike" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.tests.net"
+        android:label="Frameworks Networking Tests" />
+</manifest>
diff --git a/tests/unit/AndroidTest.xml b/tests/unit/AndroidTest.xml
new file mode 100644
index 0000000..939ae49
--- /dev/null
+++ b/tests/unit/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Frameworks Networking Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksNetTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksNetTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.frameworks.tests.net" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/tests/net/jarjar-rules.txt b/tests/unit/jarjar-rules.txt
similarity index 100%
rename from tests/net/jarjar-rules.txt
rename to tests/unit/jarjar-rules.txt
diff --git a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
similarity index 100%
rename from tests/net/java/android/app/usage/NetworkStatsManagerTest.java
rename to tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java
similarity index 100%
rename from tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
rename to tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/unit/java/android/net/ConnectivityManagerTest.java
similarity index 100%
rename from tests/net/java/android/net/ConnectivityManagerTest.java
rename to tests/unit/java/android/net/ConnectivityManagerTest.java
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
similarity index 100%
rename from tests/net/java/android/net/Ikev2VpnProfileTest.java
rename to tests/unit/java/android/net/Ikev2VpnProfileTest.java
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/unit/java/android/net/IpMemoryStoreTest.java
similarity index 100%
rename from tests/net/java/android/net/IpMemoryStoreTest.java
rename to tests/unit/java/android/net/IpMemoryStoreTest.java
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/unit/java/android/net/IpSecAlgorithmTest.java
similarity index 100%
rename from tests/net/java/android/net/IpSecAlgorithmTest.java
rename to tests/unit/java/android/net/IpSecAlgorithmTest.java
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/unit/java/android/net/IpSecConfigTest.java
similarity index 100%
rename from tests/net/java/android/net/IpSecConfigTest.java
rename to tests/unit/java/android/net/IpSecConfigTest.java
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/unit/java/android/net/IpSecManagerTest.java
similarity index 100%
rename from tests/net/java/android/net/IpSecManagerTest.java
rename to tests/unit/java/android/net/IpSecManagerTest.java
diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/unit/java/android/net/IpSecTransformTest.java
similarity index 100%
rename from tests/net/java/android/net/IpSecTransformTest.java
rename to tests/unit/java/android/net/IpSecTransformTest.java
diff --git a/tests/net/java/android/net/KeepalivePacketDataUtilTest.java b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
similarity index 100%
rename from tests/net/java/android/net/KeepalivePacketDataUtilTest.java
rename to tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/unit/java/android/net/MacAddressTest.java
similarity index 100%
rename from tests/net/java/android/net/MacAddressTest.java
rename to tests/unit/java/android/net/MacAddressTest.java
diff --git a/tests/net/java/android/net/NetworkIdentityTest.kt b/tests/unit/java/android/net/NetworkIdentityTest.kt
similarity index 100%
rename from tests/net/java/android/net/NetworkIdentityTest.kt
rename to tests/unit/java/android/net/NetworkIdentityTest.kt
diff --git a/tests/net/java/android/net/NetworkStatsHistoryTest.java b/tests/unit/java/android/net/NetworkStatsHistoryTest.java
similarity index 100%
rename from tests/net/java/android/net/NetworkStatsHistoryTest.java
rename to tests/unit/java/android/net/NetworkStatsHistoryTest.java
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/unit/java/android/net/NetworkStatsTest.java
similarity index 100%
rename from tests/net/java/android/net/NetworkStatsTest.java
rename to tests/unit/java/android/net/NetworkStatsTest.java
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt
similarity index 100%
rename from tests/net/java/android/net/NetworkTemplateTest.kt
rename to tests/unit/java/android/net/NetworkTemplateTest.kt
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/unit/java/android/net/NetworkUtilsTest.java
similarity index 100%
rename from tests/net/java/android/net/NetworkUtilsTest.java
rename to tests/unit/java/android/net/NetworkUtilsTest.java
diff --git a/tests/net/java/android/net/QosSocketFilterTest.java b/tests/unit/java/android/net/QosSocketFilterTest.java
similarity index 100%
rename from tests/net/java/android/net/QosSocketFilterTest.java
rename to tests/unit/java/android/net/QosSocketFilterTest.java
diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java
similarity index 100%
rename from tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
rename to tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/unit/java/android/net/VpnManagerTest.java
similarity index 85%
rename from tests/net/java/android/net/VpnManagerTest.java
rename to tests/unit/java/android/net/VpnManagerTest.java
index c548e30..3135062 100644
--- a/tests/net/java/android/net/VpnManagerTest.java
+++ b/tests/unit/java/android/net/VpnManagerTest.java
@@ -28,11 +28,13 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.test.mock.MockContext;
+import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.net.VpnProfile;
+import com.android.internal.util.MessageUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -119,4 +121,18 @@
                 .setAuthPsk(PSK_BYTES)
                 .build();
     }
+
+    @Test
+    public void testVpnTypesEqual() throws Exception {
+        SparseArray<String> vmVpnTypes = MessageUtils.findMessageNames(
+                new Class[] { VpnManager.class }, new String[]{ "TYPE_VPN_" });
+        SparseArray<String> nativeVpnType = MessageUtils.findMessageNames(
+                new Class[] { NativeVpnType.class }, new String[]{ "" });
+
+        // TYPE_VPN_NONE = -1 is only defined in VpnManager.
+        assertEquals(vmVpnTypes.size() - 1, nativeVpnType.size());
+        for (int i = VpnManager.TYPE_VPN_SERVICE; i < vmVpnTypes.size(); i++) {
+            assertEquals(vmVpnTypes.get(i), "TYPE_VPN_" + nativeVpnType.get(i));
+        }
+    }
 }
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/unit/java/android/net/VpnTransportInfoTest.java
similarity index 100%
rename from tests/net/java/android/net/VpnTransportInfoTest.java
rename to tests/unit/java/android/net/VpnTransportInfoTest.java
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/unit/java/android/net/ipmemorystore/ParcelableTests.java
similarity index 100%
rename from tests/net/java/android/net/ipmemorystore/ParcelableTests.java
rename to tests/unit/java/android/net/ipmemorystore/ParcelableTests.java
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/unit/java/android/net/nsd/NsdManagerTest.java
similarity index 100%
rename from tests/net/java/android/net/nsd/NsdManagerTest.java
rename to tests/unit/java/android/net/nsd/NsdManagerTest.java
diff --git a/tests/net/java/android/net/nsd/NsdServiceInfoTest.java b/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
similarity index 100%
rename from tests/net/java/android/net/nsd/NsdServiceInfoTest.java
rename to tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
diff --git a/tests/net/java/android/net/util/DnsUtilsTest.java b/tests/unit/java/android/net/util/DnsUtilsTest.java
similarity index 100%
rename from tests/net/java/android/net/util/DnsUtilsTest.java
rename to tests/unit/java/android/net/util/DnsUtilsTest.java
diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt
similarity index 100%
rename from tests/net/java/android/net/util/KeepaliveUtilsTest.kt
rename to tests/unit/java/android/net/util/KeepaliveUtilsTest.kt
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
similarity index 100%
rename from tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
rename to tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
diff --git a/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java b/tests/unit/java/com/android/internal/net/NetworkUtilsInternalTest.java
similarity index 100%
rename from tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java
rename to tests/unit/java/com/android/internal/net/NetworkUtilsInternalTest.java
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
similarity index 100%
rename from tests/net/java/com/android/internal/net/VpnProfileTest.java
rename to tests/unit/java/com/android/internal/net/VpnProfileTest.java
diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/tests/unit/java/com/android/internal/util/BitUtilsTest.java
similarity index 100%
rename from tests/net/java/com/android/internal/util/BitUtilsTest.java
rename to tests/unit/java/com/android/internal/util/BitUtilsTest.java
diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/tests/unit/java/com/android/internal/util/RingBufferTest.java
similarity index 100%
rename from tests/net/java/com/android/internal/util/RingBufferTest.java
rename to tests/unit/java/com/android/internal/util/RingBufferTest.java
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
similarity index 98%
rename from tests/net/java/com/android/server/ConnectivityServiceTest.java
rename to tests/unit/java/com/android/server/ConnectivityServiceTest.java
index f277e94..63501d7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.CHANGE_NETWORK_STATE;
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
 import static android.Manifest.permission.NETWORK_FACTORY;
 import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
@@ -212,6 +213,8 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.MatchAllNetworkSpecifier;
+import android.net.NativeNetworkConfig;
+import android.net.NativeNetworkType;
 import android.net.Network;
 import android.net.NetworkAgent;
 import android.net.NetworkAgentConfig;
@@ -1240,6 +1243,8 @@
             verify(mMockNetd, never())
                     .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any());
             mAgentRegistered = true;
+            verify(mMockNetd).networkCreate(nativeNetworkConfigVpn(getNetwork().netId,
+                    !mMockNetworkAgent.isBypassableVpn(), mVpnType));
             updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
             mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
             mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -2777,8 +2782,9 @@
 
     private void grantUsingBackgroundNetworksPermissionForUid(
             final int uid, final String packageName) throws Exception {
-        when(mPackageManager.getPackageInfo(eq(packageName), eq(GET_PERMISSIONS)))
-                .thenReturn(buildPackageInfo(true, uid));
+        when(mPackageManager.getPackageInfo(
+                eq(packageName), eq(GET_PERMISSIONS | MATCH_ANY_USER)))
+                .thenReturn(buildPackageInfo(true /* hasSystemPermission */, uid));
         mService.mPermissionMonitor.onPackageAdded(packageName, uid);
     }
 
@@ -2828,6 +2834,16 @@
         mCm.unregisterNetworkCallback(callback);
     }
 
+    private NativeNetworkConfig nativeNetworkConfigPhysical(int netId, int permission) {
+        return new NativeNetworkConfig(netId, NativeNetworkType.PHYSICAL, permission,
+                /*secure=*/ false, VpnManager.TYPE_VPN_NONE);
+    }
+
+    private NativeNetworkConfig nativeNetworkConfigVpn(int netId, boolean secure, int vpnType) {
+        return new NativeNetworkConfig(netId, NativeNetworkType.VIRTUAL, INetd.PERMISSION_NONE,
+                secure, vpnType);
+    }
+
     @Test
     public void testNetworkAgentCallbacks() throws Exception {
         // Keeps track of the order of events that happen in this test.
@@ -2849,8 +2865,8 @@
             wifiNetwork.set(mWiFiNetworkAgent.getNetwork());
             assertNotNull(wifiNetwork.get());
             try {
-                verify(mMockNetd).networkCreatePhysical(wifiNetwork.get().getNetId(),
-                        INetd.PERMISSION_NONE);
+                verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                        wifiNetwork.get().getNetId(), INetd.PERMISSION_NONE));
             } catch (RemoteException impossible) {
                 fail();
             }
@@ -8404,7 +8420,8 @@
         final int cellNetId = mCellNetworkAgent.getNetwork().netId;
         waitForIdle();
 
-        verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
+        verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId,
+                INetd.PERMISSION_NONE));
         assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
         verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
@@ -9469,9 +9486,9 @@
         @Override
         public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
             return new TestTransportInfo(
-                    (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
-                    (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
-                    (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
+                    locationRedacted | (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
+                    localMacAddressRedacted | (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
+                    settingsRedacted | (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
             );
         }
 
@@ -9494,8 +9511,26 @@
         public int hashCode() {
             return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted);
         }
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "TestTransportInfo{locationRedacted=%s macRedacted=%s settingsRedacted=%s}",
+                    locationRedacted, localMacAddressRedacted, settingsRedacted);
+        }
     }
 
+    private TestTransportInfo getTestTransportInfo(NetworkCapabilities nc) {
+        return (TestTransportInfo) nc.getTransportInfo();
+    }
+
+    private TestTransportInfo getTestTransportInfo(TestNetworkAgentWrapper n) {
+        final NetworkCapabilities nc = mCm.getNetworkCapabilities(n.getNetwork());
+        assertNotNull(nc);
+        return getTestTransportInfo(nc);
+    }
+
+
     private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
             @NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid,
             @NonNull TransportInfo actualTransportInfo, int expectedOwnerUid,
@@ -9524,7 +9559,6 @@
         wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent,
                 nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid())
                         && Objects.equals(expectedTransportInfo, nc.getTransportInfo()));
-
     }
 
     @Test
@@ -9545,6 +9579,40 @@
                 wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo);
     }
 
+    @Test
+    public void testTransportInfoRedactionInSynchronousCalls() throws Exception {
+        final NetworkCapabilities ncTemplate = new NetworkCapabilities()
+                .addTransportType(TRANSPORT_WIFI)
+                .setTransportInfo(new TestTransportInfo());
+
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
+                ncTemplate);
+        mWiFiNetworkAgent.connect(true /* validated; waits for callback */);
+
+        // NETWORK_SETTINGS redaction is controlled by the NETWORK_SETTINGS permission
+        assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
+        withPermission(NETWORK_SETTINGS, () -> {
+            assertFalse(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
+        });
+        assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
+
+        // LOCAL_MAC_ADDRESS redaction is controlled by the LOCAL_MAC_ADDRESS permission
+        assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
+        withPermission(LOCAL_MAC_ADDRESS, () -> {
+            assertFalse(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
+        });
+        assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
+
+        // Synchronous getNetworkCapabilities calls never return unredacted location-sensitive
+        // information.
+        assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
+        setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+        assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
+        denyAllLocationPrivilegedPermissions();
+        assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
+    }
+
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
             throws Exception {
         final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
@@ -9903,12 +9971,27 @@
         // Connect the cell agent verify that it notifies TestNetworkCallback that it is available
         final TestNetworkCallback callback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(callback);
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+
+        final NetworkCapabilities ncTemplate = new NetworkCapabilities()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .setTransportInfo(new TestTransportInfo());
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(),
+                ncTemplate);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         callback.assertNoCallback();
     }
 
+    private boolean areConnDiagCapsRedacted(NetworkCapabilities nc) {
+        TestTransportInfo ti = (TestTransportInfo) nc.getTransportInfo();
+        return nc.getUids() == null
+                && nc.getAdministratorUids().length == 0
+                && nc.getOwnerUid() == Process.INVALID_UID
+                && getTestTransportInfo(nc).locationRedacted
+                && getTestTransportInfo(nc).localMacAddressRedacted
+                && getTestTransportInfo(nc).settingsRedacted;
+    }
+
     @Test
     public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable()
             throws Exception {
@@ -9919,12 +10002,7 @@
 
         // Verify onConnectivityReport fired
         verify(mConnectivityDiagnosticsCallback).onConnectivityReportAvailable(
-                argThat(report -> {
-                    final NetworkCapabilities nc = report.getNetworkCapabilities();
-                    return nc.getUids() == null
-                            && nc.getAdministratorUids().length == 0
-                            && nc.getOwnerUid() == Process.INVALID_UID;
-                }));
+                argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
     }
 
     @Test
@@ -9940,12 +10018,7 @@
 
         // Verify onDataStallSuspected fired
         verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(
-                argThat(report -> {
-                    final NetworkCapabilities nc = report.getNetworkCapabilities();
-                    return nc.getUids() == null
-                            && nc.getAdministratorUids().length == 0
-                            && nc.getOwnerUid() == Process.INVALID_UID;
-                }));
+                argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
     }
 
     @Test
@@ -12255,8 +12328,9 @@
         mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
-                INetd.PERMISSION_NONE);
+        inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
+
 
         final TestOnCompleteListener listener = new TestOnCompleteListener();
         mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
@@ -12283,8 +12357,8 @@
         mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
         mSystemDefaultNetworkCallback.assertNoCallback();
         mDefaultNetworkCallback.assertNoCallback();
-        inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId,
-                INetd.PERMISSION_SYSTEM);
+        inOrder.verify(mMockNetd).networkCreate(
+                nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
                 uidRangeFor(testHandle));
         inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
@@ -12327,8 +12401,8 @@
         mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mProfileDefaultNetworkCallback.assertNoCallback();
-        inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
-                INetd.PERMISSION_NONE);
+        inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
 
         // When the agent disconnects, test that the app on the work profile falls back to the
         // default network.
@@ -12358,8 +12432,8 @@
 
         mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
-        inOrder.verify(mMockNetd).networkCreatePhysical(workAgent2.getNetwork().netId,
-                INetd.PERMISSION_SYSTEM);
+        inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRanges(workAgent2.getNetwork().netId,
                 uidRangeFor(testHandle));
 
@@ -12404,8 +12478,8 @@
         mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
                 r -> r.run(), listener);
         listener.expectOnComplete();
-        inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
-                INetd.PERMISSION_NONE);
+        inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
         inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
                 uidRangeFor(testHandle));
 
@@ -12457,10 +12531,10 @@
         mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         app4Cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
-                INetd.PERMISSION_NONE);
-        inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId,
-                INetd.PERMISSION_SYSTEM);
+        inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
+        inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
 
         final TestOnCompleteListener listener = new TestOnCompleteListener();
         mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
@@ -12512,8 +12586,8 @@
         mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
                 r -> r.run(), listener);
         listener.expectOnComplete();
-        inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
-                INetd.PERMISSION_NONE);
+        inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
         inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
                 uidRangeFor(testHandle));
 
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
similarity index 100%
rename from tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
rename to tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java
similarity index 100%
rename from tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
rename to tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/unit/java/com/android/server/IpSecServiceTest.java
similarity index 100%
rename from tests/net/java/com/android/server/IpSecServiceTest.java
rename to tests/unit/java/com/android/server/IpSecServiceTest.java
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
similarity index 100%
rename from tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
rename to tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
diff --git a/tests/net/java/com/android/server/NetIdManagerTest.kt b/tests/unit/java/com/android/server/NetIdManagerTest.kt
similarity index 100%
rename from tests/net/java/com/android/server/NetIdManagerTest.kt
rename to tests/unit/java/com/android/server/NetIdManagerTest.kt
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/unit/java/com/android/server/NetworkManagementServiceTest.java
similarity index 100%
rename from tests/net/java/com/android/server/NetworkManagementServiceTest.java
rename to tests/unit/java/com/android/server/NetworkManagementServiceTest.java
diff --git a/tests/net/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
similarity index 100%
rename from tests/net/java/com/android/server/NsdServiceTest.java
rename to tests/unit/java/com/android/server/NsdServiceTest.java
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/DnsManagerTest.java
rename to tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/FullScoreTest.kt
rename to tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/unit/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
rename to tests/unit/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
rename to tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
rename to tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
diff --git a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java b/tests/unit/java/com/android/server/connectivity/MetricsTestUtil.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
rename to tests/unit/java/com/android/server/connectivity/MetricsTestUtil.java
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
rename to tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
rename to tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
rename to tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
rename to tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
diff --git a/tests/net/java/com/android/server/connectivity/NetworkOfferTest.kt b/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/NetworkOfferTest.kt
rename to tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
new file mode 100644
index 0000000..4408958
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 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.server.connectivity
+
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.NetworkScore.KEEP_CONNECTED_NONE
+import android.net.NetworkScore.POLICY_EXITING
+import android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY
+import android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD
+import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+private fun score(vararg policies: Int) = FullScore(0,
+        policies.fold(0L) { acc, e -> acc or (1L shl e) }, KEEP_CONNECTED_NONE)
+private fun caps(transport: Int) = NetworkCapabilities.Builder().addTransportType(transport).build()
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+class NetworkRankerTest {
+    private val mRanker = NetworkRanker()
+
+    private class TestScore(private val sc: FullScore, private val nc: NetworkCapabilities)
+            : NetworkRanker.Scoreable {
+        override fun getScore() = sc
+        override fun getCapsNoCopy(): NetworkCapabilities = nc
+    }
+
+    @Test
+    fun testYieldToBadWiFiOneCell() {
+        // Only cell, it wins
+        val winner = TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                caps(TRANSPORT_CELLULAR))
+        val scores = listOf(winner)
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiOneCellOneBadWiFi() {
+        // Bad wifi wins against yielding validated cell
+        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
+                caps(TRANSPORT_WIFI))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                        caps(TRANSPORT_CELLULAR))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiOneCellTwoBadWiFi() {
+        // Bad wifi wins against yielding validated cell. Prefer the one that's primary.
+        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
+                POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
+                        caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                        caps(TRANSPORT_CELLULAR))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiOneCellTwoBadWiFiOneNotAvoided() {
+        // Bad wifi ever validated wins against bad wifi that never was validated (or was
+        // avoided when bad).
+        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
+                caps(TRANSPORT_WIFI))
+        val scores = listOf(
+                winner,
+                TestScore(score(), caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                        caps(TRANSPORT_CELLULAR))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiOneCellOneBadWiFiOneGoodWiFi() {
+        // Good wifi wins
+        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
+                POLICY_IS_VALIDATED), caps(TRANSPORT_WIFI))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
+                        POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                        caps(TRANSPORT_CELLULAR))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiTwoCellsOneBadWiFi() {
+        // Cell that doesn't yield wins over cell that yields and bad wifi
+        val winner = TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_CELLULAR))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
+                        POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                        caps(TRANSPORT_CELLULAR))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiTwoCellsOneBadWiFiOneGoodWiFi() {
+        // Good wifi wins over cell that doesn't yield and cell that yields
+        val winner = TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_WIFI))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
+                        POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_CELLULAR)),
+                TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                        caps(TRANSPORT_CELLULAR))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiOneExitingGoodWiFi() {
+        // Yielding cell wins over good exiting wifi
+        val winner = TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                caps(TRANSPORT_CELLULAR))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_IS_VALIDATED, POLICY_EXITING), caps(TRANSPORT_WIFI))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
+    fun testYieldToBadWiFiOneExitingBadWiFi() {
+        // Yielding cell wins over bad exiting wifi
+        val winner = TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                caps(TRANSPORT_CELLULAR))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
+                        POLICY_EXITING), caps(TRANSPORT_WIFI))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
similarity index 97%
rename from tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
rename to tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index d7535a9..02a5808 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -479,13 +479,14 @@
     public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
                 Arrays.asList(new PackageInfo[] {
-                        buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
-                        buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
-                        buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
-                        buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
+                        buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
                 }));
-        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
-                buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
+                eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+                buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
         mPermissionMonitor.startMonitoring();
         // Every app on user 0 except MOCK_UID2 are under VPN.
         final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
@@ -530,11 +531,12 @@
     public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
                 Arrays.asList(new PackageInfo[] {
-                        buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
-                        buildPackageInfo(false, VPN_UID, MOCK_USER1)
+                        buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
                 }));
-        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
-                        buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
+                eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+                buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
 
         mPermissionMonitor.startMonitoring();
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/VpnTest.java
rename to tests/unit/java/com/android/server/connectivity/VpnTest.java
diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/unit/java/com/android/server/net/NetworkStatsAccessTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
rename to tests/unit/java/com/android/server/net/NetworkStatsAccessTest.java
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/unit/java/com/android/server/net/NetworkStatsBaseTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
rename to tests/unit/java/com/android/server/net/NetworkStatsBaseTest.java
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/unit/java/com/android/server/net/NetworkStatsCollectionTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
rename to tests/unit/java/com/android/server/net/NetworkStatsCollectionTest.java
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
rename to tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
rename to tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
rename to tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/unit/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
rename to tests/unit/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/unit/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
similarity index 100%
rename from tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
rename to tests/unit/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
diff --git a/tests/unit/jni/Android.bp b/tests/unit/jni/Android.bp
new file mode 100644
index 0000000..22a04f5
--- /dev/null
+++ b/tests/unit/jni/Android.bp
@@ -0,0 +1,32 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_library_shared {
+    name: "libnetworkstatsfactorytestjni",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+
+    srcs: [
+        ":lib_networkStatsFactory_native",
+        "test_onload.cpp",
+    ],
+
+    shared_libs: [
+        "libbpf_android",
+        "liblog",
+        "libnativehelper",
+        "libnetdbpf",
+        "libnetdutils",
+    ],
+}
diff --git a/tests/unit/jni/test_onload.cpp b/tests/unit/jni/test_onload.cpp
new file mode 100644
index 0000000..5194ddb
--- /dev/null
+++ b/tests/unit/jni/test_onload.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/*
+ * this is a mini native libaray for NetworkStatsFactoryTest to run properly. It
+ * load all the native method related to NetworkStatsFactory when test run
+ */
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+namespace android {
+int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
+};
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
+{
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        ALOGE("GetEnv failed!");
+        return result;
+    }
+    ALOG_ASSERT(env, "Could not retrieve the env!");
+    register_android_server_net_NetworkStatsFactory(env);
+    return JNI_VERSION_1_4;
+}
diff --git a/tests/net/res/raw/history_v1 b/tests/unit/res/raw/history_v1
similarity index 100%
rename from tests/net/res/raw/history_v1
rename to tests/unit/res/raw/history_v1
Binary files differ
diff --git a/tests/net/res/raw/net_dev_typical b/tests/unit/res/raw/net_dev_typical
similarity index 100%
rename from tests/net/res/raw/net_dev_typical
rename to tests/unit/res/raw/net_dev_typical
diff --git a/tests/net/res/raw/netstats_uid_v4 b/tests/unit/res/raw/netstats_uid_v4
similarity index 100%
rename from tests/net/res/raw/netstats_uid_v4
rename to tests/unit/res/raw/netstats_uid_v4
Binary files differ
diff --git a/tests/net/res/raw/netstats_v1 b/tests/unit/res/raw/netstats_v1
similarity index 100%
rename from tests/net/res/raw/netstats_v1
rename to tests/unit/res/raw/netstats_v1
Binary files differ
diff --git a/tests/net/res/raw/xt_qtaguid_iface_fmt_typical b/tests/unit/res/raw/xt_qtaguid_iface_fmt_typical
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_iface_fmt_typical
rename to tests/unit/res/raw/xt_qtaguid_iface_fmt_typical
diff --git a/tests/net/res/raw/xt_qtaguid_iface_typical b/tests/unit/res/raw/xt_qtaguid_iface_typical
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_iface_typical
rename to tests/unit/res/raw/xt_qtaguid_iface_typical
diff --git a/tests/net/res/raw/xt_qtaguid_typical b/tests/unit/res/raw/xt_qtaguid_typical
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_typical
rename to tests/unit/res/raw/xt_qtaguid_typical
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface b/tests/unit/res/raw/xt_qtaguid_vpn_incorrect_iface
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface
rename to tests/unit/res/raw/xt_qtaguid_vpn_incorrect_iface
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying b/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_one_underlying
rename to tests/unit/res/raw/xt_qtaguid_vpn_one_underlying
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression b/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_compression
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression
rename to tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_compression
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic b/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
rename to tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn b/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
rename to tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self b/tests/unit/res/raw/xt_qtaguid_vpn_rewrite_through_self
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self
rename to tests/unit/res/raw/xt_qtaguid_vpn_rewrite_through_self
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication b/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_duplication
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication
rename to tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_duplication
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split b/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split
rename to tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression b/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
rename to tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_with_clat b/tests/unit/res/raw/xt_qtaguid_vpn_with_clat
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_vpn_with_clat
rename to tests/unit/res/raw/xt_qtaguid_vpn_with_clat
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat b/tests/unit/res/raw/xt_qtaguid_with_clat
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_with_clat
rename to tests/unit/res/raw/xt_qtaguid_with_clat
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after b/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_after
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
rename to tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_after
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before b/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_before
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
rename to tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_before
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/tests/unit/res/raw/xt_qtaguid_with_clat_simple
similarity index 100%
rename from tests/net/res/raw/xt_qtaguid_with_clat_simple
rename to tests/unit/res/raw/xt_qtaguid_with_clat_simple