diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java index ca5dc34dc1..03cf109256 100644 --- a/framework/src/android/net/NetworkCapabilities.java +++ b/framework/src/android/net/NetworkCapabilities.java @@ -1591,28 +1591,6 @@ public final class NetworkCapabilities implements Parcelable { return false; } - /** - * Compare if the given NetworkCapabilities have the same UIDs. - * - * @hide - */ - public static boolean hasSameUids(@Nullable NetworkCapabilities nc1, - @Nullable NetworkCapabilities nc2) { - final Set uids1 = (nc1 == null) ? null : nc1.mUids; - final Set 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 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. *

@@ -1623,13 +1601,13 @@ public final class NetworkCapabilities implements Parcelable { * Note that this method is not very optimized, which is fine as long as it's not used very * often. *

- * 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 bd332928f4..a1f64f2040 100644 --- a/framework/src/android/net/UidRange.java +++ b/framework/src/android/net/UidRange.java @@ -180,4 +180,24 @@ public final class UidRange implements Parcelable { } return uids; } + + /** + * Compare if the given UID range sets have the same UIDs. + * + * @hide + */ + public static boolean hasSameUids(@Nullable Set uids1, + @Nullable Set 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 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 d507b4b331..6227bb25b9 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -7705,7 +7705,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // 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 prevUids = prevNc == null ? null : prevNc.getUidRanges(); + final Set 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 1b1c95431d..a43511994f 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.USER_SYSTEM; 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.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Set; + @RunWith(AndroidJUnit4.class) @SmallTest public class UidRangeTest { @@ -110,4 +116,61 @@ public class UidRangeTest { assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser()); assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser()); } + + private static void assertSameUids(@NonNull final String msg, @Nullable final Set s1, + @Nullable final Set s2) { + assertTrue(msg + " : " + s1 + " unexpectedly different from " + s2, + UidRange.hasSameUids(s1, s2)); + } + + private static void assertDifferentUids(@NonNull final String msg, + @Nullable final Set s1, @Nullable final Set 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 set1 = new ArraySet<>(); + assertDifferentUids("empty <=> null", set1, null); + final Set 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<>()); + } }