Correctly get uids for per-app network preferences

Per-app network functionality assumed all apps were installed for user 0
which is not always the case. This fix will address that by checking for
the existance of an app for all users and adding it to the per-app
network preference as was originally intended. Prior, no apps were
included if they were not installed for user 0 even if they were
available for another user such as user 10 in automotive.

Bug: 189838408
Test: atest FrameworksNetTests
atest FrameworksNetIntegrationTests
atest CtsNetTestCases

Change-Id: I7d75cdb02041e7a202254be2eaeca6c2b02d7c29
This commit is contained in:
James Mattis
2021-06-01 22:30:36 -07:00
parent 0a0d7c99c9
commit b6b6a4335a
2 changed files with 47 additions and 41 deletions

View File

@@ -10077,7 +10077,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences( private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences(
@NonNull final OemNetworkPreferences preference) { @NonNull final OemNetworkPreferences preference) {
final SparseArray<Set<Integer>> uids = new SparseArray<>(); final SparseArray<Set<Integer>> prefToUids = new SparseArray<>();
final PackageManager pm = mContext.getPackageManager(); final PackageManager pm = mContext.getPackageManager();
final List<UserHandle> users = final List<UserHandle> users =
mContext.getSystemService(UserManager.class).getUserHandles(true); mContext.getSystemService(UserManager.class).getUserHandles(true);
@@ -10085,29 +10085,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG || DDBG) { if (VDBG || DDBG) {
log("No users currently available for setting the OEM network preference."); log("No users currently available for setting the OEM network preference.");
} }
return uids; return prefToUids;
} }
for (final Map.Entry<String, Integer> entry : for (final Map.Entry<String, Integer> entry :
preference.getNetworkPreferences().entrySet()) { preference.getNetworkPreferences().entrySet()) {
@OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue(); @OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
try {
final int uid = pm.getApplicationInfo(entry.getKey(), 0).uid;
if (!uids.contains(pref)) {
uids.put(pref, new ArraySet<>());
}
for (final UserHandle ui : users) {
// Add the rules for all users as this policy is device wide. // Add the rules for all users as this policy is device wide.
uids.get(pref).add(ui.getUid(uid)); for (final UserHandle user : users) {
try {
final int uid = pm.getApplicationInfoAsUser(entry.getKey(), 0, user).uid;
if (!prefToUids.contains(pref)) {
prefToUids.put(pref, new ArraySet<>());
} }
prefToUids.get(pref).add(uid);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
// Although this may seem like an error scenario, it is ok that uninstalled // Although this may seem like an error scenario, it is ok that uninstalled
// packages are sent on a network preference as the system will watch for // packages are sent on a network preference as the system will watch for
// package installations associated with this network preference and update // package installations associated with this network preference and update
// accordingly. This is done so as to minimize race conditions on app install. // accordingly. This is done to minimize race conditions on app install.
continue; continue;
} }
} }
return uids; }
return prefToUids;
} }
private NetworkRequestInfo createNriFromOemNetworkPreferences( private NetworkRequestInfo createNriFromOemNetworkPreferences(

View File

@@ -1535,6 +1535,8 @@ public class ConnectivityServiceTest {
} }
private static final int PRIMARY_USER = 0; private static final int PRIMARY_USER = 0;
private static final int SECONDARY_USER = 10;
private static final int TERTIARY_USER = 11;
private static final UidRange PRIMARY_UIDRANGE = private static final UidRange PRIMARY_UIDRANGE =
UidRange.createForUser(UserHandle.of(PRIMARY_USER)); UidRange.createForUser(UserHandle.of(PRIMARY_USER));
private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100); private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
@@ -1543,8 +1545,8 @@ public class ConnectivityServiceTest {
private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "", private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
UserInfo.FLAG_PRIMARY); UserInfo.FLAG_PRIMARY);
private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER); private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER);
private static final int SECONDARY_USER = 10;
private static final UserHandle SECONDARY_USER_HANDLE = new UserHandle(SECONDARY_USER); private static final UserHandle SECONDARY_USER_HANDLE = new UserHandle(SECONDARY_USER);
private static final UserHandle TERTIARY_USER_HANDLE = new UserHandle(TERTIARY_USER);
private static final int RESTRICTED_USER = 1; private static final int RESTRICTED_USER = 1;
private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "", private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
@@ -10315,29 +10317,30 @@ public class ConnectivityServiceTest {
fail("TOO_MANY_REQUESTS never thrown"); fail("TOO_MANY_REQUESTS never thrown");
} }
private UidRange createUidRange(int userId) { private void mockGetApplicationInfo(@NonNull final String packageName, final int uid) {
return UidRange.createForUser(UserHandle.of(userId)); mockGetApplicationInfo(packageName, uid, PRIMARY_USER_HANDLE);
} }
private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid) { private void mockGetApplicationInfo(@NonNull final String packageName, final int uid,
@NonNull final UserHandle user) {
final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = uid; applicationInfo.uid = uid;
try { try {
when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())) when(mPackageManager.getApplicationInfoAsUser(eq(packageName), anyInt(), eq(user)))
.thenReturn(applicationInfo); .thenReturn(applicationInfo);
} catch (Exception e) { } catch (Exception e) {
fail(e.getMessage()); fail(e.getMessage());
} }
} }
private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName) private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName,
@NonNull final UserHandle user)
throws Exception { throws Exception {
when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())) when(mPackageManager.getApplicationInfoAsUser(eq(packageName), anyInt(), eq(user)))
.thenThrow(new PackageManager.NameNotFoundException(packageName)); .thenThrow(new PackageManager.NameNotFoundException(packageName));
} }
private void mockHasSystemFeature(@NonNull final String featureName, private void mockHasSystemFeature(@NonNull final String featureName, final boolean hasFeature) {
@NonNull final boolean hasFeature) {
when(mPackageManager.hasSystemFeature(eq(featureName))) when(mPackageManager.hasSystemFeature(eq(featureName)))
.thenReturn(hasFeature); .thenReturn(hasFeature);
} }
@@ -10531,16 +10534,18 @@ public class ConnectivityServiceTest {
} }
@Test @Test
public void testOemNetworkRequestFactoryMultipleUsersCorrectlySetsUids() public void testOemNetworkRequestFactoryMultipleUsersSetsUids()
throws Exception { throws Exception {
// Arrange users // Arrange users
final int secondUser = 10; final int secondUserTestPackageUid = UserHandle.getUid(SECONDARY_USER, TEST_PACKAGE_UID);
final UserHandle secondUserHandle = new UserHandle(secondUser); final int thirdUserTestPackageUid = UserHandle.getUid(TERTIARY_USER, TEST_PACKAGE_UID);
when(mUserManager.getUserHandles(anyBoolean())).thenReturn( when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle)); Arrays.asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE, TERTIARY_USER_HANDLE));
// Arrange PackageManager mocks // Arrange PackageManager mocks testing for users who have and don't have a package.
mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID); mockGetApplicationInfoThrowsNameNotFound(TEST_PACKAGE_NAME, PRIMARY_USER_HANDLE);
mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, SECONDARY_USER_HANDLE);
mockGetApplicationInfo(TEST_PACKAGE_NAME, thirdUserTestPackageUid, TERTIARY_USER_HANDLE);
// Build OemNetworkPreferences object // Build OemNetworkPreferences object
final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID; final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
@@ -10554,8 +10559,8 @@ public class ConnectivityServiceTest {
mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences( mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
pref)); pref));
// UIDs for all users and all managed packages should be present. // UIDs for users with installed packages should be present.
// Two users each with two packages. // Three users exist, but only two have the test package installed.
final int expectedUidSize = 2; final int expectedUidSize = 2;
final List<Range<Integer>> uids = final List<Range<Integer>> uids =
new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids()); new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
@@ -10563,11 +10568,10 @@ public class ConnectivityServiceTest {
// Sort by uid to access nris by index // Sort by uid to access nris by index
uids.sort(Comparator.comparingInt(uid -> uid.getLower())); uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID); assertEquals(secondUserTestPackageUid, (int) uids.get(0).getLower());
assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower()); assertEquals(secondUserTestPackageUid, (int) uids.get(0).getUpper());
assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper()); assertEquals(thirdUserTestPackageUid, (int) uids.get(1).getLower());
assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower()); assertEquals(thirdUserTestPackageUid, (int) uids.get(1).getUpper());
assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
} }
@Test @Test
@@ -11368,6 +11372,7 @@ public class ConnectivityServiceTest {
final UidRangeParcel[] uidRanges = final UidRangeParcel[] uidRanges =
toUidRangeStableParcels( toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid)); uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, secondUserHandle);
setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME); setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
// Verify the starting state. No networks should be connected. // Verify the starting state. No networks should be connected.
@@ -11410,6 +11415,7 @@ public class ConnectivityServiceTest {
final UidRangeParcel[] uidRangesBothUsers = final UidRangeParcel[] uidRangesBothUsers =
toUidRangeStableParcels( toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid)); uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, secondUserHandle);
setupSetOemNetworkPreferenceForPreferenceTest( setupSetOemNetworkPreferenceForPreferenceTest(
networkPref, uidRangesSingleUser, TEST_PACKAGE_NAME); networkPref, uidRangesSingleUser, TEST_PACKAGE_NAME);
@@ -11466,7 +11472,7 @@ public class ConnectivityServiceTest {
final UidRangeParcel[] uidRangesSinglePackage = final UidRangeParcel[] uidRangesSinglePackage =
toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID)); toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID); mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
mockGetApplicationInfoThrowsNameNotFound(packageToInstall); mockGetApplicationInfoThrowsNameNotFound(packageToInstall, PRIMARY_USER_HANDLE);
setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall); setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall); grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
@@ -11500,7 +11506,7 @@ public class ConnectivityServiceTest {
false /* shouldDestroyNetwork */); false /* shouldDestroyNetwork */);
// Set the system to no longer recognize the package to be installed // Set the system to no longer recognize the package to be installed
mockGetApplicationInfoThrowsNameNotFound(packageToInstall); mockGetApplicationInfoThrowsNameNotFound(packageToInstall, PRIMARY_USER_HANDLE);
// Send a broadcast indicating a package was removed. // Send a broadcast indicating a package was removed.
final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED); final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);