Merge changes from topic "clean_move_and_delete"

* changes:
  Delete dead codes within TrafficController in mainline module
  Move TrafficController relevant files from netd to mainline module
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 415b3e5..ec169b6 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -163,6 +163,8 @@
 
   public final class ProfileNetworkPreference implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public java.util.List<java.lang.Integer> getExcludedUids();
+    method @NonNull public java.util.List<java.lang.Integer> getIncludedUids();
     method public int getPreference();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.ProfileNetworkPreference> CREATOR;
@@ -171,6 +173,8 @@
   public static final class ProfileNetworkPreference.Builder {
     ctor public ProfileNetworkPreference.Builder();
     method @NonNull public android.net.ProfileNetworkPreference build();
+    method @NonNull public android.net.ProfileNetworkPreference.Builder setExcludedUids(@Nullable java.util.List<java.lang.Integer>);
+    method @NonNull public android.net.ProfileNetworkPreference.Builder setIncludedUids(@Nullable java.util.List<java.lang.Integer>);
     method @NonNull public android.net.ProfileNetworkPreference.Builder setPreference(int);
   }
 
diff --git a/framework/src/android/net/ProfileNetworkPreference.java b/framework/src/android/net/ProfileNetworkPreference.java
index 2ce1698..0571b36 100644
--- a/framework/src/android/net/ProfileNetworkPreference.java
+++ b/framework/src/android/net/ProfileNetworkPreference.java
@@ -20,11 +20,16 @@
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.ConnectivityManager.ProfileNetworkPreferencePolicy;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
 /**
  * Network preferences to be set for the user profile
  * {@link ProfileNetworkPreferencePolicy}.
@@ -33,23 +38,69 @@
 @SystemApi(client = MODULE_LIBRARIES)
 public final class ProfileNetworkPreference implements Parcelable {
     private final @ProfileNetworkPreferencePolicy int mPreference;
+    private final List<Integer> mIncludedUids;
+    private final List<Integer> mExcludedUids;
 
-    private ProfileNetworkPreference(int preference) {
+    private ProfileNetworkPreference(int preference, List<Integer> includedUids,
+            List<Integer> excludedUids) {
         mPreference = preference;
+        if (includedUids != null) {
+            mIncludedUids = new ArrayList<>(includedUids);
+        } else {
+            mIncludedUids = new ArrayList<>();
+        }
+
+        if (excludedUids != null) {
+            mExcludedUids = new ArrayList<>(excludedUids);
+        } else {
+            mExcludedUids = new ArrayList<>();
+        }
     }
 
     private ProfileNetworkPreference(Parcel in) {
         mPreference = in.readInt();
+        mIncludedUids = in.readArrayList(Integer.class.getClassLoader());
+        mExcludedUids = in.readArrayList(Integer.class.getClassLoader());
     }
 
     public int getPreference() {
         return mPreference;
     }
 
+    /**
+     * Get the list of UIDs subject to this preference.
+     *
+     * Included UIDs and Excluded UIDs can't both be non-empty.
+     * if both are empty, it means this request applies to all uids in the user profile.
+     * if included is not empty, then only included UIDs are applied.
+     * if excluded is not empty, then it is all uids in the user profile except these UIDs.
+     * @return List of uids included for the profile preference.
+     * {@see #getExcludedUids()}
+     */
+    public @NonNull List<Integer> getIncludedUids() {
+        return new ArrayList<>(mIncludedUids);
+    }
+
+    /**
+     * Get the list of UIDS excluded from this preference.
+     *
+     * <ul>Included UIDs and Excluded UIDs can't both be non-empty.</ul>
+     * <ul>If both are empty, it means this request applies to all uids in the user profile.</ul>
+     * <ul>If included is not empty, then only included UIDs are applied.</ul>
+     * <ul>If excluded is not empty, then it is all uids in the user profile except these UIDs.</ul>
+     * @return List of uids not included for the profile preference.
+     * {@see #getIncludedUids()}
+     */
+    public @NonNull List<Integer> getExcludedUids() {
+        return new ArrayList<>(mExcludedUids);
+    }
+
     @Override
     public String toString() {
         return "ProfileNetworkPreference{"
                 + "mPreference=" + getPreference()
+                + "mIncludedUids=" + mIncludedUids.toString()
+                + "mExcludedUids=" + mExcludedUids.toString()
                 + '}';
     }
 
@@ -58,12 +109,16 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         final ProfileNetworkPreference that = (ProfileNetworkPreference) o;
-        return mPreference == that.mPreference;
+        return mPreference == that.mPreference
+                && (Objects.equals(mIncludedUids, that.mIncludedUids))
+                && (Objects.equals(mExcludedUids, that.mExcludedUids));
     }
 
     @Override
     public int hashCode() {
-        return mPreference;
+        return mPreference
+                + (Objects.hashCode(mIncludedUids) * 11)
+                + (Objects.hashCode(mExcludedUids) * 13);
     }
 
     /**
@@ -73,6 +128,8 @@
     public static final class Builder {
         private @ProfileNetworkPreferencePolicy int mPreference =
                 PROFILE_NETWORK_PREFERENCE_DEFAULT;
+        private @NonNull List<Integer> mIncludedUids = new ArrayList<>();
+        private @NonNull List<Integer> mExcludedUids = new ArrayList<>();
 
         /**
          * Constructs an empty Builder with PROFILE_NETWORK_PREFERENCE_DEFAULT profile preference
@@ -93,18 +150,66 @@
         }
 
         /**
+         * This is a list of uids for which profile perefence is set.
+         * Null would mean that this preference applies to all uids in the profile.
+         * {@see #setExcludedUids(List<Integer>)}
+         * Included UIDs and Excluded UIDs can't both be non-empty.
+         * if both are empty, it means this request applies to all uids in the user profile.
+         * if included is not empty, then only included UIDs are applied.
+         * if excluded is not empty, then it is all uids in the user profile except these UIDs.
+         * @param uids  list of uids that are included
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        public Builder setIncludedUids(@Nullable List<Integer> uids) {
+            if (uids != null) {
+                mIncludedUids = new ArrayList<Integer>(uids);
+            } else {
+                mIncludedUids = new ArrayList<Integer>();
+            }
+            return this;
+        }
+
+
+        /**
+         * This is a list of uids that are excluded for the profile perefence.
+         * {@see #setIncludedUids(List<Integer>)}
+         * Included UIDs and Excluded UIDs can't both be non-empty.
+         * if both are empty, it means this request applies to all uids in the user profile.
+         * if included is not empty, then only included UIDs are applied.
+         * if excluded is not empty, then it is all uids in the user profile except these UIDs.
+         * @param uids  list of uids that are not included
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        public Builder setExcludedUids(@Nullable List<Integer> uids) {
+            if (uids != null) {
+                mExcludedUids = new ArrayList<Integer>(uids);
+            } else {
+                mExcludedUids = new ArrayList<Integer>();
+            }
+            return this;
+        }
+
+         /**
          * Returns an instance of {@link ProfileNetworkPreference} created from the
          * fields set on this builder.
          */
         @NonNull
         public ProfileNetworkPreference  build() {
-            return new ProfileNetworkPreference(mPreference);
+            if (mIncludedUids.size() > 0 && mExcludedUids.size() > 0) {
+                throw new IllegalArgumentException("Both includedUids and excludedUids "
+                        + "cannot be nonempty");
+            }
+            return new ProfileNetworkPreference(mPreference, mIncludedUids, mExcludedUids);
         }
     }
 
     @Override
     public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
         dest.writeInt(mPreference);
+        dest.writeList(mIncludedUids);
+        dest.writeList(mExcludedUids);
     }
 
     @Override
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index d625d1b..6c27c4a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -262,6 +262,7 @@
 import com.android.server.connectivity.ProfileNetworkPreferenceList;
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.QosCallbackTracker;
+import com.android.server.connectivity.UidRangeUtils;
 
 import libcore.io.IoUtils;
 
@@ -1489,16 +1490,17 @@
     }
 
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
-        return createDefaultNetworkCapabilitiesForUidRange(new UidRange(uid, uid));
+        return createDefaultNetworkCapabilitiesForUidRangeSet(Collections.singleton(
+                new UidRange(uid, uid)));
     }
 
-    private static NetworkCapabilities createDefaultNetworkCapabilitiesForUidRange(
-            @NonNull final UidRange uids) {
+    private static NetworkCapabilities createDefaultNetworkCapabilitiesForUidRangeSet(
+            @NonNull final Set<UidRange> uidRangeSet) {
         final NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
         netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
-        netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids)));
+        netCap.setUids(UidRange.toIntRanges(uidRangeSet));
         return netCap;
     }
 
@@ -10150,8 +10152,14 @@
                     allowFallback = false;
                     // continue to process the enterprise preference.
                 case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE:
-                    final UidRange uids = UidRange.createForUser(profile);
-                    nc = createDefaultNetworkCapabilitiesForUidRange(uids);
+                    final Set<UidRange> uidRangeSet =
+                            getUidListToBeAppliedForNetworkPreference(profile, preference);
+                    if (!isRangeAlreadyInPreferenceList(preferenceList, uidRangeSet)) {
+                        nc = createDefaultNetworkCapabilitiesForUidRangeSet(uidRangeSet);
+                    } else {
+                        throw new IllegalArgumentException(
+                                "Overlapping uid range in setProfileNetworkPreferences");
+                    }
                     nc.addCapability(NET_CAPABILITY_ENTERPRISE);
                     nc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
                     break;
@@ -10166,6 +10174,35 @@
                 new Pair<>(preferenceList, listener)));
     }
 
+    private Set<UidRange> getUidListToBeAppliedForNetworkPreference(
+            @NonNull final UserHandle profile,
+            @NonNull final ProfileNetworkPreference profileNetworkPreference) {
+        final UidRange profileUids = UidRange.createForUser(profile);
+        Set<UidRange> uidRangeSet = UidRangeUtils.convertListToUidRange(
+                profileNetworkPreference.getIncludedUids());
+        if (uidRangeSet.size() > 0) {
+            if (!UidRangeUtils.isRangeSetInUidRange(profileUids, uidRangeSet)) {
+                throw new IllegalArgumentException(
+                        "Allow uid range is outside the uid range of profile.");
+            }
+        } else {
+            ArraySet<UidRange> disallowUidRangeSet = UidRangeUtils.convertListToUidRange(
+                    profileNetworkPreference.getExcludedUids());
+            if (disallowUidRangeSet.size() > 0) {
+                if (!UidRangeUtils.isRangeSetInUidRange(profileUids, disallowUidRangeSet)) {
+                    throw new IllegalArgumentException(
+                            "disallow uid range is outside the uid range of profile.");
+                }
+                uidRangeSet = UidRangeUtils.removeRangeSetFromUidRange(profileUids,
+                        disallowUidRangeSet);
+            } else {
+                uidRangeSet = new ArraySet<UidRange>();
+                uidRangeSet.add(profileUids);
+            }
+        }
+        return uidRangeSet;
+    }
+
     private void validateNetworkCapabilitiesOfProfileNetworkPreference(
             @Nullable final NetworkCapabilities nc) {
         if (null == nc) return; // Null caps are always allowed. It means to remove the setting.
@@ -10187,6 +10224,11 @@
                 nrs.add(createDefaultInternetRequestForTransport(
                         TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
             }
+            if (VDBG) {
+                loge("pref.capabilities.getUids():" + UidRange.fromIntRanges(
+                        pref.capabilities.getUids()));
+            }
+
             setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
             final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs,
                     PREFERENCE_ORDER_PROFILE);
@@ -10195,6 +10237,25 @@
         return result;
     }
 
+    /**
+     * Compare if the given UID range sets have the same UIDs.
+     *
+     */
+    private boolean isRangeAlreadyInPreferenceList(
+            @NonNull List<ProfileNetworkPreferenceList.Preference> preferenceList,
+            @NonNull Set<UidRange> uidRangeSet) {
+        if (uidRangeSet.size() == 0 || preferenceList.size() == 0) {
+            return false;
+        }
+        for (ProfileNetworkPreferenceList.Preference pref : preferenceList) {
+            if (UidRangeUtils.doesRangeSetOverlap(
+                    UidRange.fromIntRanges(pref.capabilities.getUids()), uidRangeSet)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void handleSetProfileNetworkPreference(
             @NonNull final List<ProfileNetworkPreferenceList.Preference> preferenceList,
             @Nullable final IOnCompleteListener listener) {
diff --git a/service/src/com/android/server/connectivity/UidRangeUtils.java b/service/src/com/android/server/connectivity/UidRangeUtils.java
new file mode 100644
index 0000000..7318296
--- /dev/null
+++ b/service/src/com/android/server/connectivity/UidRangeUtils.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+import android.net.UidRange;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Utility class for UidRange
+ *
+ * @hide
+ */
+public final class UidRangeUtils {
+    /**
+     * Check if given uid range set is within the uid range
+     * @param uids uid range in which uidRangeSet is checked to be in range.
+     * @param uidRangeSet uid range set to be be checked if it is in range of uids
+     * @return true uidRangeSet is in the range of uids
+     * @hide
+     */
+    public static boolean isRangeSetInUidRange(@NonNull UidRange uids,
+            @NonNull Set<UidRange> uidRangeSet) {
+        Objects.requireNonNull(uids);
+        Objects.requireNonNull(uidRangeSet);
+        if (uidRangeSet.size() == 0) {
+            return true;
+        }
+        for (UidRange range : uidRangeSet) {
+            if (!uids.contains(range.start) || !uids.contains(range.stop)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Remove given uid ranges set from a uid range
+     * @param uids uid range from which uidRangeSet will be removed
+     * @param uidRangeSet uid range set to be removed from uids.
+     * WARNING : This function requires the UidRanges in uidRangeSet to be disjoint
+     * WARNING : This function requires the arrayset to be iterated in increasing order of the
+     *                    ranges. Today this is provided by the iteration order stability of
+     *                    ArraySet, and the fact that the code creating this ArraySet always
+     *                    creates it in increasing order.
+     * Note : if any of the above is not satisfied this function throws IllegalArgumentException
+     * TODO : remove these limitations
+     * @hide
+     */
+    public static ArraySet<UidRange> removeRangeSetFromUidRange(@NonNull UidRange uids,
+            @NonNull ArraySet<UidRange> uidRangeSet) {
+        Objects.requireNonNull(uids);
+        Objects.requireNonNull(uidRangeSet);
+        final ArraySet<UidRange> filteredRangeSet = new ArraySet<UidRange>();
+        if (uidRangeSet.size() == 0) {
+            filteredRangeSet.add(uids);
+            return filteredRangeSet;
+        }
+
+        int start = uids.start;
+        UidRange previousRange = null;
+        for (UidRange uidRange : uidRangeSet) {
+            if (previousRange != null) {
+                if (previousRange.stop > uidRange.start) {
+                    throw new IllegalArgumentException("UID ranges are not increasing order");
+                }
+            }
+            if (uidRange.start > start) {
+                filteredRangeSet.add(new UidRange(start, uidRange.start - 1));
+                start = uidRange.stop + 1;
+            } else if (uidRange.start == start) {
+                start = uidRange.stop + 1;
+            }
+            previousRange = uidRange;
+        }
+        if (start < uids.stop) {
+            filteredRangeSet.add(new UidRange(start, uids.stop));
+        }
+        return filteredRangeSet;
+    }
+
+    /**
+     * Compare if the given UID range sets have overlapping uids
+     * @param uidRangeSet1 first uid range set to check for overlap
+     * @param uidRangeSet2 second uid range set to check for overlap
+     * @hide
+     */
+    public static boolean doesRangeSetOverlap(@NonNull Set<UidRange> uidRangeSet1,
+            @NonNull Set<UidRange> uidRangeSet2) {
+        Objects.requireNonNull(uidRangeSet1);
+        Objects.requireNonNull(uidRangeSet2);
+
+        if (uidRangeSet1.size() == 0 || uidRangeSet2.size() == 0) {
+            return false;
+        }
+        for (UidRange range1 : uidRangeSet1) {
+            for (UidRange range2 : uidRangeSet2) {
+                if (range1.contains(range2.start) || range1.contains(range2.stop)
+                        || range2.contains(range1.start) || range2.contains(range1.stop)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Convert a list of uid to set of UidRanges.
+     * @param uids list of uids
+     * @return set of UidRanges
+     * @hide
+     */
+    public static ArraySet<UidRange> convertListToUidRange(@NonNull List<Integer> uids) {
+        Objects.requireNonNull(uids);
+        final ArraySet<UidRange> uidRangeSet = new ArraySet<UidRange>();
+        if (uids.size() == 0) {
+            return uidRangeSet;
+        }
+        List<Integer> uidsNew = new ArrayList<>(uids);
+        Collections.sort(uidsNew);
+        int start = uidsNew.get(0);
+        int stop = start;
+
+        for (Integer i : uidsNew) {
+            if (i <= stop + 1) {
+                stop = i;
+            } else {
+                uidRangeSet.add(new UidRange(start, stop));
+                start = i;
+                stop = i;
+            }
+        }
+        uidRangeSet.add(new UidRange(start, stop));
+        return uidRangeSet;
+    }
+}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index abb34dc..14ff981 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -338,6 +338,7 @@
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.QosCallbackTracker;
+import com.android.server.connectivity.UidRangeUtils;
 import com.android.server.connectivity.Vpn;
 import com.android.server.connectivity.VpnProfileStore;
 import com.android.server.net.NetworkPinner;
@@ -350,6 +351,7 @@
 import com.android.testutils.TestableNetworkOfferCallback;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -443,6 +445,10 @@
     private static final int TEST_WORK_PROFILE_USER_ID = 2;
     private static final int TEST_WORK_PROFILE_APP_UID =
             UserHandle.getUid(TEST_WORK_PROFILE_USER_ID, TEST_APP_ID);
+    private static final int TEST_APP_ID_2 = 104;
+    private static final int TEST_WORK_PROFILE_APP_UID_2 =
+            UserHandle.getUid(TEST_WORK_PROFILE_USER_ID, TEST_APP_ID_2);
+
     private static final String CLAT_PREFIX = "v4-";
     private static final String MOBILE_IFNAME = "test_rmnet_data0";
     private static final String CLAT_MOBILE_IFNAME = CLAT_PREFIX + MOBILE_IFNAME;
@@ -492,6 +498,8 @@
     private TestNetworkCallback mSystemDefaultNetworkCallback;
     private TestNetworkCallback mProfileDefaultNetworkCallback;
     private TestNetworkCallback mTestPackageDefaultNetworkCallback;
+    private TestNetworkCallback mProfileDefaultNetworkCallbackAsAppUid2;
+    private TestNetworkCallback mTestPackageDefaultNetworkCallback2;
 
     // State variables required to emulate NetworkPolicyManagerService behaviour.
     private int mBlockedReasons = BLOCKED_REASON_NONE;
@@ -12247,6 +12255,8 @@
     private void registerDefaultNetworkCallbacks() {
         if (mSystemDefaultNetworkCallback != null || mDefaultNetworkCallback != null
                 || mProfileDefaultNetworkCallback != null
+                || mProfileDefaultNetworkCallbackAsAppUid2 != null
+                || mTestPackageDefaultNetworkCallback2 != null
                 || mTestPackageDefaultNetworkCallback != null) {
             throw new IllegalStateException("Default network callbacks already registered");
         }
@@ -12257,12 +12267,18 @@
         mDefaultNetworkCallback = new TestNetworkCallback();
         mProfileDefaultNetworkCallback = new TestNetworkCallback();
         mTestPackageDefaultNetworkCallback = new TestNetworkCallback();
+        mProfileDefaultNetworkCallbackAsAppUid2 = new TestNetworkCallback();
+        mTestPackageDefaultNetworkCallback2 = new TestNetworkCallback();
         mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
                 new Handler(ConnectivityThread.getInstanceLooper()));
         mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
         registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
                 TEST_WORK_PROFILE_APP_UID);
         registerDefaultNetworkCallbackAsUid(mTestPackageDefaultNetworkCallback, TEST_PACKAGE_UID);
+        registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallbackAsAppUid2,
+                TEST_WORK_PROFILE_APP_UID_2);
+        registerDefaultNetworkCallbackAsUid(mTestPackageDefaultNetworkCallback2,
+                TEST_PACKAGE_UID2);
         // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
         mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
     }
@@ -12280,6 +12296,12 @@
         if (null != mTestPackageDefaultNetworkCallback) {
             mCm.unregisterNetworkCallback(mTestPackageDefaultNetworkCallback);
         }
+        if (null != mProfileDefaultNetworkCallbackAsAppUid2) {
+            mCm.unregisterNetworkCallback(mProfileDefaultNetworkCallbackAsAppUid2);
+        }
+        if (null != mTestPackageDefaultNetworkCallback2) {
+            mCm.unregisterNetworkCallback(mTestPackageDefaultNetworkCallback2);
+        }
     }
 
     private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@@ -13708,10 +13730,34 @@
     }
 
     private UidRangeParcel[] uidRangeFor(final UserHandle handle) {
-        UidRange range = UidRange.createForUser(handle);
+        final UidRange range = UidRange.createForUser(handle);
         return new UidRangeParcel[] { new UidRangeParcel(range.start, range.stop) };
     }
 
+    private UidRangeParcel[] uidRangeFor(final UserHandle handle,
+            ProfileNetworkPreference profileNetworkPreference) {
+        final Set<UidRange> uidRangeSet;
+        UidRange range = UidRange.createForUser(handle);
+        if (profileNetworkPreference.getIncludedUids().size() != 0) {
+            uidRangeSet = UidRangeUtils.convertListToUidRange(
+                    profileNetworkPreference.getIncludedUids());
+        } else if (profileNetworkPreference.getExcludedUids().size() != 0)  {
+            uidRangeSet = UidRangeUtils.removeRangeSetFromUidRange(
+                    range, UidRangeUtils.convertListToUidRange(
+                            profileNetworkPreference.getExcludedUids()));
+        } else {
+            uidRangeSet = new ArraySet<>();
+            uidRangeSet.add(range);
+        }
+        UidRangeParcel[] uidRangeParcels = new UidRangeParcel[uidRangeSet.size()];
+        int i = 0;
+        for (UidRange range1 : uidRangeSet) {
+            uidRangeParcels[i] = new UidRangeParcel(range1.start, range1.stop);
+            i++;
+        }
+        return uidRangeParcels;
+    }
+
     private static class TestOnCompleteListener implements Runnable {
         final class OnComplete {}
         final ArrayTrackRecord<OnComplete>.ReadHead mHistory =
@@ -13762,17 +13808,22 @@
      */
     public void testPreferenceForUserNetworkUpDownForGivenPreference(
             ProfileNetworkPreference profileNetworkPreference,
-            boolean connectWorkProfileAgentAhead) throws Exception {
+            boolean connectWorkProfileAgentAhead,
+            UserHandle testHandle,
+            TestNetworkCallback profileDefaultNetworkCallback,
+            TestNetworkCallback disAllowProfileDefaultNetworkCallback) throws Exception {
         final InOrder inOrder = inOrder(mMockNetd);
-        final UserHandle testHandle = setupEnterpriseNetwork();
-        registerDefaultNetworkCallbacks();
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
         mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        profileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            disAllowProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(
+                    mCellNetworkAgent);
+        }
         inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
                 mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
 
@@ -13800,33 +13851,43 @@
             // system default is not handled specially, the rules are always active as long as
             // a preference is set.
             inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                    mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+                    mCellNetworkAgent.getNetwork().netId,
+                    uidRangeFor(testHandle, profileNetworkPreference),
                     PREFERENCE_ORDER_PROFILE));
         }
 
         // The enterprise network is not ready yet.
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         if (allowFallback) {
-            assertNoCallbacks(mProfileDefaultNetworkCallback);
+            assertNoCallbacks(profileDefaultNetworkCallback);
         } else if (!connectWorkProfileAgentAhead) {
-            mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            profileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            if (disAllowProfileDefaultNetworkCallback != null) {
+                assertNoCallbacks(disAllowProfileDefaultNetworkCallback);
+            }
         }
 
         if (!connectWorkProfileAgentAhead) {
             workAgent.connect(false);
         }
 
-        mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
+        profileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            disAllowProfileDefaultNetworkCallback.assertNoCallback();
+        }
         mSystemDefaultNetworkCallback.assertNoCallback();
         mDefaultNetworkCallback.assertNoCallback();
         inOrder.verify(mMockNetd).networkCreate(
                 nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                workAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE));
+                workAgent.getNetwork().netId,
+                uidRangeFor(testHandle, profileNetworkPreference),
+                PREFERENCE_ORDER_PROFILE));
 
         if (allowFallback) {
             inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
-                    mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+                    mCellNetworkAgent.getNetwork().netId,
+                    uidRangeFor(testHandle, profileNetworkPreference),
                     PREFERENCE_ORDER_PROFILE));
         }
 
@@ -13834,14 +13895,20 @@
         // not to the other apps.
         workAgent.setNetworkValid(true /* isStrictMode */);
         workAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
-        mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent,
+        profileDefaultNetworkCallback.expectCapabilitiesThat(workAgent,
                 nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED)
                         && nc.hasCapability(NET_CAPABILITY_ENTERPRISE));
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            assertNoCallbacks(disAllowProfileDefaultNetworkCallback);
+        }
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
 
         workAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
-        mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, nc ->
+        profileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, nc ->
                 nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            assertNoCallbacks(disAllowProfileDefaultNetworkCallback);
+        }
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
 
         // Conversely, change a capability on the system-wide default network and make sure
@@ -13851,7 +13918,11 @@
                 nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
         mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
                 nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
-        mProfileDefaultNetworkCallback.assertNoCallback();
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            disAllowProfileDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
+                    nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+        }
+        profileDefaultNetworkCallback.assertNoCallback();
 
         // Disconnect and reconnect the system-wide default network and make sure that the
         // apps on this network see the appropriate callbacks, and the app on the work profile
@@ -13859,28 +13930,41 @@
         mCellNetworkAgent.disconnect();
         mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-        mProfileDefaultNetworkCallback.assertNoCallback();
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            disAllowProfileDefaultNetworkCallback.expectCallback(
+                    CallbackEntry.LOST, mCellNetworkAgent);
+        }
+        profileDefaultNetworkCallback.assertNoCallback();
         inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        mProfileDefaultNetworkCallback.assertNoCallback();
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            disAllowProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(
+                    mCellNetworkAgent);
+
+        }
+        profileDefaultNetworkCallback.assertNoCallback();
         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.
         workAgent.disconnect();
-        mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
+        profileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
         if (allowFallback) {
-            mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+            profileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+            if (disAllowProfileDefaultNetworkCallback != null) {
+                assertNoCallbacks(disAllowProfileDefaultNetworkCallback);
+            }
         }
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         if (allowFallback) {
             inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                    mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+                    mCellNetworkAgent.getNetwork().netId,
+                    uidRangeFor(testHandle, profileNetworkPreference),
                     PREFERENCE_ORDER_PROFILE));
         }
         inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
@@ -13888,8 +13972,12 @@
         mCellNetworkAgent.disconnect();
         mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            disAllowProfileDefaultNetworkCallback.expectCallback(
+                    CallbackEntry.LOST, mCellNetworkAgent);
+        }
         if (allowFallback) {
-            mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            profileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         }
 
         // Waiting for the handler to be idle before checking for networkDestroy is necessary
@@ -13903,30 +13991,40 @@
         final TestNetworkAgentWrapper workAgent2 = makeEnterpriseNetworkAgent();
         workAgent2.connect(false);
 
-        mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2);
+        profileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2);
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            assertNoCallbacks(disAllowProfileDefaultNetworkCallback);
+        }
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
                 workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
-                workAgent2.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE));
+                workAgent2.getNetwork().netId,
+                uidRangeFor(testHandle, profileNetworkPreference), PREFERENCE_ORDER_PROFILE));
 
         workAgent2.setNetworkValid(true /* isStrictMode */);
         workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
-        mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent2,
+        profileDefaultNetworkCallback.expectCapabilitiesThat(workAgent2,
                 nc -> nc.hasCapability(NET_CAPABILITY_ENTERPRISE)
                         && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            assertNoCallbacks(disAllowProfileDefaultNetworkCallback);
+        }
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd, never()).networkAddUidRangesParcel(any());
 
         // When the agent disconnects, test that the app on the work profile fall back to the
         // default network.
         workAgent2.disconnect();
-        mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
+        profileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
+        if (disAllowProfileDefaultNetworkCallback != null) {
+            assertNoCallbacks(disAllowProfileDefaultNetworkCallback);
+        }
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd).networkDestroy(workAgent2.getNetwork().netId);
 
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
-                mProfileDefaultNetworkCallback);
+                profileDefaultNetworkCallback);
 
         // Callbacks will be unregistered by tearDown()
     }
@@ -13938,11 +14036,14 @@
      */
     @Test
     public void testPreferenceForUserNetworkUpDown() throws Exception {
+        final UserHandle testHandle = setupEnterpriseNetwork();
         ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
                 new ProfileNetworkPreference.Builder();
         profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        registerDefaultNetworkCallbacks();
         testPreferenceForUserNetworkUpDownForGivenPreference(
-                profileNetworkPreferenceBuilder.build(), false);
+                profileNetworkPreferenceBuilder.build(), false,
+                testHandle, mProfileDefaultNetworkCallback, null);
     }
 
     /**
@@ -13952,12 +14053,15 @@
      */
     @Test
     public void testPreferenceForUserNetworkUpDownWithNoFallback() throws Exception {
+        final UserHandle testHandle = setupEnterpriseNetwork();
         ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
                 new ProfileNetworkPreference.Builder();
         profileNetworkPreferenceBuilder.setPreference(
                 PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+        registerDefaultNetworkCallbacks();
         testPreferenceForUserNetworkUpDownForGivenPreference(
-                profileNetworkPreferenceBuilder.build(), false);
+                profileNetworkPreferenceBuilder.build(), false,
+                testHandle, mProfileDefaultNetworkCallback, null);
     }
 
     /**
@@ -13969,12 +14073,143 @@
     @Test
     public void testPreferenceForUserNetworkUpDownWithNoFallbackWithAlreadyConnectedWorkAgent()
             throws Exception {
+        final UserHandle testHandle = setupEnterpriseNetwork();
         ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
                 new ProfileNetworkPreference.Builder();
         profileNetworkPreferenceBuilder.setPreference(
                 PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+        registerDefaultNetworkCallbacks();
         testPreferenceForUserNetworkUpDownForGivenPreference(
-                profileNetworkPreferenceBuilder.build(), true);
+                profileNetworkPreferenceBuilder.build(), true, testHandle,
+                mProfileDefaultNetworkCallback, null);
+    }
+
+    /**
+     * Make sure per-profile networking preference for specific uid of test handle
+     * behaves as expected
+     */
+    @Test
+    public void testPreferenceForDefaultUidOfTestHandle() throws Exception {
+        final UserHandle testHandle = setupEnterpriseNetwork();
+        ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+                new ProfileNetworkPreference.Builder();
+        profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder.setIncludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID)));
+        registerDefaultNetworkCallbacks();
+        testPreferenceForUserNetworkUpDownForGivenPreference(
+                profileNetworkPreferenceBuilder.build(), false, testHandle,
+                mProfileDefaultNetworkCallback, null);
+    }
+
+    /**
+     * Make sure per-profile networking preference for specific uid of test handle
+     * behaves as expected
+     */
+    @Test
+    public void testPreferenceForSpecificUidOfOnlyOneApp() throws Exception {
+        final UserHandle testHandle = setupEnterpriseNetwork();
+        ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+                new ProfileNetworkPreference.Builder();
+        profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder.setIncludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        registerDefaultNetworkCallbacks();
+        testPreferenceForUserNetworkUpDownForGivenPreference(
+                profileNetworkPreferenceBuilder.build(), false,
+                testHandle, mProfileDefaultNetworkCallbackAsAppUid2, null);
+    }
+
+    /**
+     * Make sure per-profile networking preference for specific uid of test handle
+     * behaves as expected
+     */
+    @Test
+    public void testPreferenceForDisallowSpecificUidOfApp() throws Exception {
+        final UserHandle testHandle = setupEnterpriseNetwork();
+        ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+                new ProfileNetworkPreference.Builder();
+        profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder.setExcludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        registerDefaultNetworkCallbacks();
+        testPreferenceForUserNetworkUpDownForGivenPreference(
+                profileNetworkPreferenceBuilder.build(), false,
+                testHandle, mProfileDefaultNetworkCallback,
+                mProfileDefaultNetworkCallbackAsAppUid2);
+    }
+
+    /**
+     * Make sure per-profile networking preference for specific uid of test handle
+     * invalid uid inputs
+     */
+    @Test
+    public void testPreferenceForInvalidUids() throws Exception {
+        final UserHandle testHandle = setupEnterpriseNetwork();
+        ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+                new ProfileNetworkPreference.Builder();
+        profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder.setExcludedUids(
+                List.of(testHandle.getUid(0) - 1));
+        final TestOnCompleteListener listener = new TestOnCompleteListener();
+        Assert.assertThrows(IllegalArgumentException.class, () -> mCm.setProfileNetworkPreferences(
+                testHandle, List.of(profileNetworkPreferenceBuilder.build()),
+                r -> r.run(), listener));
+
+        profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder.setIncludedUids(
+                List.of(testHandle.getUid(0) - 1));
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> mCm.setProfileNetworkPreferences(
+                        testHandle, List.of(profileNetworkPreferenceBuilder.build()),
+                        r -> r.run(), listener));
+
+
+        profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder.setIncludedUids(
+                List.of(testHandle.getUid(0) - 1));
+        profileNetworkPreferenceBuilder.setExcludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> mCm.setProfileNetworkPreferences(
+                        testHandle, List.of(profileNetworkPreferenceBuilder.build()),
+                        r -> r.run(), listener));
+
+        ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder2 =
+                new ProfileNetworkPreference.Builder();
+        profileNetworkPreferenceBuilder2.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder2.setIncludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        profileNetworkPreferenceBuilder.setIncludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> mCm.setProfileNetworkPreferences(
+                        testHandle, List.of(profileNetworkPreferenceBuilder.build(),
+                                profileNetworkPreferenceBuilder2.build()),
+                        r -> r.run(), listener));
+
+        profileNetworkPreferenceBuilder2.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+        profileNetworkPreferenceBuilder2.setExcludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        profileNetworkPreferenceBuilder.setExcludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> mCm.setProfileNetworkPreferences(
+                        testHandle, List.of(profileNetworkPreferenceBuilder.build(),
+                                profileNetworkPreferenceBuilder2.build()),
+                        r -> r.run(), listener));
+
+        profileNetworkPreferenceBuilder2.setPreference(
+                PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+        profileNetworkPreferenceBuilder2.setExcludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        profileNetworkPreferenceBuilder.setExcludedUids(
+                List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> mCm.setProfileNetworkPreferences(
+                        testHandle, List.of(profileNetworkPreferenceBuilder.build(),
+                                profileNetworkPreferenceBuilder2.build()),
+                        r -> r.run(), listener));
     }
 
     /**
diff --git a/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java b/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java
new file mode 100644
index 0000000..b8c2673
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.UidRange;
+import android.os.Build;
+import android.util.ArraySet;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for UidRangeUtils.
+ *
+ * Build, install and run with:
+ *  runtest frameworks-net -c com.android.server.connectivity.UidRangeUtilsTest
+ */
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+public class UidRangeUtilsTest {
+    private static void assertInSameRange(@NonNull final String msg,
+            @Nullable final UidRange r1,
+            @Nullable final Set<UidRange> s2) {
+        assertTrue(msg + " : " + s2 + " unexpectedly is not in range of " + r1,
+                UidRangeUtils.isRangeSetInUidRange(r1, s2));
+    }
+
+    private static void assertNotInSameRange(@NonNull final String msg,
+            @Nullable final UidRange r1, @Nullable final Set<UidRange> s2) {
+        assertFalse(msg + " : " + s2 + " unexpectedly is in range of " + r1,
+                UidRangeUtils.isRangeSetInUidRange(r1, s2));
+    }
+
+    @Test @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testRangeSetInUidRange() {
+        final UidRange uids1 = new UidRange(1, 100);
+        final UidRange uids2 = new UidRange(3, 300);
+        final UidRange uids3 = new UidRange(1, 1000);
+        final UidRange uids4 = new UidRange(1, 100);
+        final UidRange uids5 = new UidRange(2, 20);
+        final UidRange uids6 = new UidRange(3, 30);
+
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.isRangeSetInUidRange(null, null));
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.isRangeSetInUidRange(uids1, null));
+
+        final ArraySet<UidRange> set1 = new ArraySet<>();
+        final ArraySet<UidRange> set2 = new ArraySet<>();
+
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.isRangeSetInUidRange(null, set1));
+        assertInSameRange("uids1 <=> empty", uids1, set2);
+
+        set2.add(uids1);
+        assertInSameRange("uids1 <=> uids1", uids1, set2);
+
+        set2.clear();
+        set2.add(uids2);
+        assertNotInSameRange("uids1 <=> uids2", uids1, set2);
+        set2.clear();
+        set2.add(uids3);
+        assertNotInSameRange("uids1 <=> uids3", uids1, set2);
+        set2.clear();
+        set2.add(uids4);
+        assertInSameRange("uids1 <=> uids4", uids1, set2);
+
+        set2.clear();
+        set2.add(uids5);
+        set2.add(uids6);
+        assertInSameRange("uids1 <=> uids5, 6", uids1, set2);
+
+        set2.clear();
+        set2.add(uids2);
+        set2.add(uids6);
+        assertNotInSameRange("uids1 <=> uids2, 6", uids1, set2);
+    }
+
+    @Test @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testRemoveRangeSetFromUidRange() {
+        final UidRange uids1 = new UidRange(1, 100);
+        final UidRange uids2 = new UidRange(3, 300);
+        final UidRange uids3 = new UidRange(1, 1000);
+        final UidRange uids4 = new UidRange(1, 100);
+        final UidRange uids5 = new UidRange(2, 20);
+        final UidRange uids6 = new UidRange(3, 30);
+        final UidRange uids7 = new UidRange(30, 39);
+
+        final UidRange uids8 = new UidRange(1, 1);
+        final UidRange uids9 = new UidRange(21, 100);
+        final UidRange uids10 = new UidRange(1, 2);
+        final UidRange uids11 = new UidRange(31, 100);
+
+        final UidRange uids12 = new UidRange(1, 1);
+        final UidRange uids13 = new UidRange(21, 29);
+        final UidRange uids14 = new UidRange(40, 100);
+
+        final UidRange uids15 = new UidRange(3, 30);
+        final UidRange uids16 = new UidRange(31, 39);
+
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.removeRangeSetFromUidRange(null, null));
+        Set<UidRange> expected = new ArraySet<>();
+        expected.add(uids1);
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.removeRangeSetFromUidRange(uids1, null));
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, new ArraySet<>()));
+
+        expected.clear();
+        final ArraySet<UidRange> set2 = new ArraySet<>();
+        set2.add(uids1);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+        set2.clear();
+        set2.add(uids4);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+
+        expected.add(uids10);
+        set2.clear();
+        set2.add(uids2);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+
+        expected.clear();
+        set2.clear();
+        set2.add(uids3);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+
+        set2.clear();
+        set2.add(uids3);
+        set2.add(uids6);
+        assertThrows(IllegalArgumentException.class,
+                () -> UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+
+        expected.clear();
+        expected.add(uids8);
+        expected.add(uids9);
+        set2.clear();
+        set2.add(uids5);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+
+        expected.clear();
+        expected.add(uids10);
+        expected.add(uids11);
+        set2.clear();
+        set2.add(uids6);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+
+        expected.clear();
+        expected.add(uids12);
+        expected.add(uids13);
+        expected.add(uids14);
+        set2.clear();
+        set2.add(uids5);
+        set2.add(uids7);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+
+        expected.clear();
+        expected.add(uids10);
+        expected.add(uids14);
+        set2.clear();
+        set2.add(uids15);
+        set2.add(uids16);
+        assertEquals(expected, UidRangeUtils.removeRangeSetFromUidRange(uids1, set2));
+    }
+
+    private static void assertRangeOverlaps(@NonNull final String msg,
+            @Nullable final Set<UidRange> s1,
+            @Nullable final Set<UidRange> s2) {
+        assertTrue(msg + " : " + s2 + " unexpectedly does not overlap with " + s1,
+                UidRangeUtils.doesRangeSetOverlap(s1, s2));
+    }
+
+    private static void assertRangeDoesNotOverlap(@NonNull final String msg,
+            @Nullable final Set<UidRange> s1, @Nullable final Set<UidRange> s2) {
+        assertFalse(msg + " : " + s2 + " unexpectedly ovelaps with " + s1,
+                UidRangeUtils.doesRangeSetOverlap(s1, s2));
+    }
+
+    @Test @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testRangeSetOverlap() {
+        final UidRange uids1 = new UidRange(1, 100);
+        final UidRange uids2 = new UidRange(3, 300);
+        final UidRange uids3 = new UidRange(1, 1000);
+        final UidRange uids4 = new UidRange(1, 100);
+        final UidRange uids5 = new UidRange(2, 20);
+        final UidRange uids6 = new UidRange(3, 30);
+        final UidRange uids7 = new UidRange(0, 0);
+        final UidRange uids8 = new UidRange(1, 500);
+        final UidRange uids9 = new UidRange(101, 200);
+
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.doesRangeSetOverlap(null, null));
+
+        final ArraySet<UidRange> set1 = new ArraySet<>();
+        final ArraySet<UidRange> set2 = new ArraySet<>();
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.doesRangeSetOverlap(set1, null));
+        assertThrows(NullPointerException.class,
+                () -> UidRangeUtils.doesRangeSetOverlap(null, set2));
+        assertRangeDoesNotOverlap("empty <=> null", set1, set2);
+
+        set2.add(uids1);
+        set1.add(uids1);
+        assertRangeOverlaps("uids1 <=> uids1", set1, set2);
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids2);
+        assertRangeOverlaps("uids1 <=> uids2", set1, set2);
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids3);
+        assertRangeOverlaps("uids1 <=> uids3", set1, set2);
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids4);
+        assertRangeOverlaps("uids1 <=> uids4", set1, set2);
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids5);
+        set2.add(uids6);
+        assertRangeOverlaps("uids1 <=> uids5,6", set1, set2);
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids7);
+        assertRangeDoesNotOverlap("uids1 <=> uids7", set1, set2);
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids9);
+        assertRangeDoesNotOverlap("uids1 <=> uids9", set1, set2);
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids8);
+        assertRangeOverlaps("uids1 <=> uids8", set1, set2);
+
+
+        set1.clear();
+        set1.add(uids1);
+        set2.clear();
+        set2.add(uids8);
+        set2.add(uids7);
+        assertRangeOverlaps("uids1 <=> uids7, 8", set1, set2);
+    }
+
+    @Test @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testConvertListToUidRange() {
+        final UidRange uids1 = new UidRange(1, 1);
+        final UidRange uids2 = new UidRange(1, 2);
+        final UidRange uids3 = new UidRange(100, 100);
+        final UidRange uids4 = new UidRange(10, 10);
+
+        final UidRange uids5 = new UidRange(10, 14);
+        final UidRange uids6 = new UidRange(20, 24);
+
+        final Set<UidRange> expected = new ArraySet<>();
+        final List<Integer> input = new ArrayList<Integer>();
+
+        assertThrows(NullPointerException.class, () -> UidRangeUtils.convertListToUidRange(null));
+        assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
+
+        input.add(1);
+        expected.add(uids1);
+        assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
+
+        input.add(2);
+        expected.clear();
+        expected.add(uids2);
+        assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
+
+        input.clear();
+        input.add(1);
+        input.add(100);
+        expected.clear();
+        expected.add(uids1);
+        expected.add(uids3);
+        assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
+
+        input.clear();
+        input.add(100);
+        input.add(1);
+        expected.clear();
+        expected.add(uids1);
+        expected.add(uids3);
+        assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
+
+        input.clear();
+        input.add(100);
+        input.add(1);
+        input.add(2);
+        input.add(1);
+        input.add(10);
+        expected.clear();
+        expected.add(uids2);
+        expected.add(uids4);
+        expected.add(uids3);
+        assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
+
+        input.clear();
+        input.add(10);
+        input.add(11);
+        input.add(12);
+        input.add(13);
+        input.add(14);
+        input.add(20);
+        input.add(21);
+        input.add(22);
+        input.add(23);
+        input.add(24);
+        expected.clear();
+        expected.add(uids5);
+        expected.add(uids6);
+        assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
+    }
+}