Genericize NC#hasSameUids

This will be used by another set of UIDs in a future patch

Test: FrameworksNetTests
Change-Id: I2c5d18ef93e73b702723814592ef3f3baf5dfbc4
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index ca5dc34..03cf109 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -1592,28 +1592,6 @@
     }
 
     /**
-     * Compare if the given NetworkCapabilities have the same UIDs.
-     *
-     * @hide
-     */
-    public static boolean hasSameUids(@Nullable NetworkCapabilities nc1,
-            @Nullable NetworkCapabilities nc2) {
-        final Set<UidRange> uids1 = (nc1 == null) ? null : nc1.mUids;
-        final Set<UidRange> uids2 = (nc2 == null) ? null : nc2.mUids;
-        if (null == uids1) return null == uids2;
-        if (null == uids2) return false;
-        // Make a copy so it can be mutated to check that all ranges in uids2 also are in uids.
-        final Set<UidRange> uids = new ArraySet<>(uids2);
-        for (UidRange range : uids1) {
-            if (!uids.contains(range)) {
-                return false;
-            }
-            uids.remove(range);
-        }
-        return uids.isEmpty();
-    }
-
-    /**
      * Tests if the set of UIDs that this network applies to is the same as the passed network.
      * <p>
      * This test only checks whether equal range objects are in both sets. It will
@@ -1623,13 +1601,13 @@
      * Note that this method is not very optimized, which is fine as long as it's not used very
      * often.
      * <p>
-     * nc is assumed nonnull.
+     * nc is assumed nonnull, else NPE.
      *
      * @hide
      */
     @VisibleForTesting
     public boolean equalsUids(@NonNull NetworkCapabilities nc) {
-        return hasSameUids(nc, this);
+        return UidRange.hasSameUids(nc.mUids, mUids);
     }
 
     /**
diff --git a/framework/src/android/net/UidRange.java b/framework/src/android/net/UidRange.java
index bd33292..a1f64f2 100644
--- a/framework/src/android/net/UidRange.java
+++ b/framework/src/android/net/UidRange.java
@@ -180,4 +180,24 @@
         }
         return uids;
     }
+
+    /**
+     * Compare if the given UID range sets have the same UIDs.
+     *
+     * @hide
+     */
+    public static boolean hasSameUids(@Nullable Set<UidRange> uids1,
+            @Nullable Set<UidRange> uids2) {
+        if (null == uids1) return null == uids2;
+        if (null == uids2) return false;
+        // Make a copy so it can be mutated to check that all ranges in uids2 also are in uids.
+        final Set<UidRange> remainingUids = new ArraySet<>(uids2);
+        for (UidRange range : uids1) {
+            if (!remainingUids.contains(range)) {
+                return false;
+            }
+            remainingUids.remove(range);
+        }
+        return remainingUids.isEmpty();
+    }
 }
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index d507b4b..6227bb2 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -7705,7 +7705,9 @@
         // changed.
         // TODO: Try to track the default network that apps use and only send a proxy broadcast when
         //  that happens to prevent false alarms.
-        if (nai.isVPN() && nai.everConnected && !NetworkCapabilities.hasSameUids(prevNc, newNc)
+        final Set<UidRange> prevUids = prevNc == null ? null : prevNc.getUidRanges();
+        final Set<UidRange> newUids = newNc == null ? null : newNc.getUidRanges();
+        if (nai.isVPN() && nai.everConnected && !UidRange.hasSameUids(prevUids, newUids)
                 && (nai.linkProperties.getHttpProxy() != null || isProxySetOnAnyDefaultNetwork())) {
             mProxyTracker.sendProxyBroadcast();
         }
diff --git a/tests/common/java/android/net/UidRangeTest.java b/tests/common/java/android/net/UidRangeTest.java
index 1b1c954..a435119 100644
--- a/tests/common/java/android/net/UidRangeTest.java
+++ b/tests/common/java/android/net/UidRangeTest.java
@@ -22,11 +22,15 @@
 import static android.os.UserHandle.getUid;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Build;
 import android.os.UserHandle;
+import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +42,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Set;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class UidRangeTest {
@@ -110,4 +116,61 @@
         assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
         assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
     }
+
+    private static void assertSameUids(@NonNull final String msg, @Nullable final Set<UidRange> s1,
+            @Nullable final Set<UidRange> s2) {
+        assertTrue(msg + " : " + s1 + " unexpectedly different from " + s2,
+                UidRange.hasSameUids(s1, s2));
+    }
+
+    private static void assertDifferentUids(@NonNull final String msg,
+            @Nullable final Set<UidRange> s1, @Nullable final Set<UidRange> s2) {
+        assertFalse(msg + " : " + s1 + " unexpectedly equal to " + s2,
+                UidRange.hasSameUids(s1, s2));
+    }
+
+    // R doesn't have UidRange.hasSameUids, but since S has the module, it does have hasSameUids.
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testHasSameUids() {
+        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(800, 1000);
+
+        assertSameUids("null <=> null", null, null);
+        final Set<UidRange> set1 = new ArraySet<>();
+        assertDifferentUids("empty <=> null", set1, null);
+        final Set<UidRange> set2 = new ArraySet<>();
+        set1.add(uids1);
+        assertDifferentUids("uids1 <=> null", set1, null);
+        assertDifferentUids("null <=> uids1", null, set1);
+        assertDifferentUids("uids1 <=> empty", set1, set2);
+        set2.add(uids1);
+        assertSameUids("uids1 <=> uids1", set1, set2);
+        set1.add(uids2);
+        assertDifferentUids("uids1,2 <=> uids1", set1, set2);
+        set1.add(uids3);
+        assertDifferentUids("uids1,2,3 <=> uids1", set1, set2);
+        set2.add(uids3);
+        assertDifferentUids("uids1,2,3 <=> uids1,3", set1, set2);
+        set2.add(uids2);
+        assertSameUids("uids1,2,3 <=> uids1,2,3", set1, set2);
+        set1.remove(uids2);
+        assertDifferentUids("uids1,3 <=> uids1,2,3", set1, set2);
+        set1.add(uids4);
+        assertDifferentUids("uids1,3,4 <=> uids1,2,3", set1, set2);
+        set2.add(uids4);
+        assertDifferentUids("uids1,3,4 <=> uids1,2,3,4", set1, set2);
+        assertDifferentUids("uids1,3,4 <=> null", set1, null);
+        set2.remove(uids2);
+        assertSameUids("uids1,3,4 <=> uids1,3,4", set1, set2);
+        set2.remove(uids1);
+        assertDifferentUids("uids1,3,4 <=> uids3,4", set1, set2);
+        set2.remove(uids3);
+        assertDifferentUids("uids1,3,4 <=> uids4", set1, set2);
+        set2.remove(uids4);
+        assertDifferentUids("uids1,3,4 <=> empty", set1, set2);
+        assertDifferentUids("null <=> empty", null, set2);
+        assertSameUids("empty <=> empty", set2, new ArraySet<>());
+    }
 }