diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 269c4abf537e6..2479646e4561f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -475,6 +475,7 @@ import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.net.module.util.ProxyUtils; import com.android.server.AlarmManagerInternal; +import com.android.server.LocalManagerRegistry; import com.android.server.LocalServices; import com.android.server.LockGuard; import com.android.server.PersistentDataBlockManagerInternal; @@ -485,6 +486,7 @@ import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.DefaultCrossProfileIntentFilter; import com.android.server.pm.DefaultCrossProfileIntentFiltersUtils; +import com.android.server.pm.PackageManagerLocal; import com.android.server.pm.RestrictionsSet; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.UserManagerInternal.UserRestrictionsListener; @@ -1618,6 +1620,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return LocalServices.getService(PackageManagerInternal.class); } + PackageManagerLocal getPackageManagerLocal() { + return LocalManagerRegistry.getManager(PackageManagerLocal.class); + } + ActivityTaskManagerInternal getActivityTaskManagerInternal() { return LocalServices.getService(ActivityTaskManagerInternal.class); } @@ -16354,19 +16360,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // The per-Q behavior was to not check the app-ops state. granted = mIPackageManager.checkPermission(permission, packageName, userId); } else { - try { - int uid = mInjector.getPackageManager().getPackageUidAsUser( - packageName, userId); - if (PermissionChecker.checkPermissionForPreflight(mContext, permission, - PermissionChecker.PID_UNKNOWN, uid, packageName) - != PermissionChecker.PERMISSION_GRANTED) { - granted = PackageManager.PERMISSION_DENIED; + try (var snapshot = mInjector.getPackageManagerLocal().withUnfilteredSnapshot()) { + var packageState = snapshot.getPackageStates().get(packageName); + if (packageState == null) { + Slog.w(LOG_TAG, "Can't get permission state for missing package " + + packageName); + return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; + } else if (!packageState.getUserStateOrDefault(userId).isInstalled()) { + Slog.w(LOG_TAG, "Can't get permission state for uninstalled package " + + packageName); + return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; } else { - granted = PackageManager.PERMISSION_GRANTED; + if (PermissionChecker.checkPermissionForPreflight(mContext, permission, + PermissionChecker.PID_UNKNOWN, + UserHandle.getUid(userId, packageState.getAppId()), packageName) + != PermissionChecker.PERMISSION_GRANTED) { + granted = PackageManager.PERMISSION_DENIED; + } else { + granted = PackageManager.PERMISSION_GRANTED; + } } - } catch (NameNotFoundException e) { - // Package does not exit - return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; } } int permFlags = mInjector.getPackageManager().getPermissionFlags( @@ -19344,23 +19357,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isPackageAllowedToAccessCalendarForUser(String packageName, - int userHandle) { + @UserIdInt int userId) { if (!mHasFeature) { return false; } Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty"); - Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId"); + Preconditions.checkArgumentNonnegative(userId, "Invalid userId"); - final CallerIdentity caller = getCallerIdentity(); - final int packageUid = mInjector.binderWithCleanCallingIdentity(() -> { - try { - return mInjector.getPackageManager().getPackageUidAsUser(packageName, userHandle); - } catch (NameNotFoundException e) { - Slogf.w(LOG_TAG, e, - "Couldn't find package %s in user %d", packageName, userHandle); - return -1; + final int packageUid; + try (var snapshot = mInjector.getPackageManagerLocal().withUnfilteredSnapshot()) { + var packageState = snapshot.getPackageStates().get(packageName); + if (packageState == null) { + Slogf.w(LOG_TAG, "Couldn't find package %s in user %d", packageName, + userId); + return false; + } else if (!packageState.getUserStateOrDefault(userId).isInstalled()) { + Slogf.w(LOG_TAG, "Couldn't find installed package %s in user %d", packageName, + userId); + return false; + } else { + packageUid = UserHandle.getUid(userId, packageState.getAppId()); } - }); + } + final CallerIdentity caller = getCallerIdentity(); if (caller.getUid() != packageUid) { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS) @@ -19369,10 +19388,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (getLockObject()) { if (mInjector.settingsSecureGetIntForUser( - Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, userHandle) == 0) { + Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, userId) == 0) { return false; } - final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle); + final ActiveAdmin admin = getProfileOwnerAdminLocked(userId); if (admin != null) { if (admin.mCrossProfileCalendarPackages == null) { return true; @@ -19726,16 +19745,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isCallingFromPackage(String packageName, int callingUid) { - return mInjector.binderWithCleanCallingIdentity(() -> { - try { - final int packageUid = mInjector.getPackageManager().getPackageUidAsUser( - packageName, UserHandle.getUserId(callingUid)); - return packageUid == callingUid; - } catch (NameNotFoundException e) { - Slogf.d(LOG_TAG, "Calling package not found", e); + try (var snapshot = mInjector.getPackageManagerLocal().withUnfilteredSnapshot()) { + var packageState = snapshot.getPackageStates().get(packageName); + var userId = UserHandle.getUserId(callingUid); + if (packageState == null) { + Slogf.d(LOG_TAG, "Calling UID " + callingUid + " not found"); return false; + } else if (!packageState.getUserStateOrDefault(userId).isInstalled()) { + Slogf.d(LOG_TAG, "Calling UID " + callingUid + " not installed"); + return false; + } else { + return callingUid == UserHandle.getUid(userId, packageState.getAppId()); } - }); + } } private DevicePolicyConstants loadConstants() { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index f0013a6f98b98..9b32a809d2b50 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -56,6 +56,7 @@ import com.android.server.AlarmManagerInternal; import com.android.server.LocalServices; import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; +import com.android.server.pm.PackageManagerLocal; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -149,6 +150,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi return services.packageManagerInternal; } + @Override + PackageManagerLocal getPackageManagerLocal() { + return services.packageManagerLocal; + } + @Override PowerManagerInternal getPowerManagerInternal() { return services.powerManagerInternal; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 4f74ef8b5f705..dd81abeec5d3f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1398,8 +1398,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().userManager.getUserRestrictions()).thenReturn(new Bundle()); // Now call clear. - doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(getServices().packageManager). - getPackageUidAsUser(eq(admin1.getPackageName()), anyInt()); + getServices().addTestPackageUid(admin1.getPackageName(), + DpmMockContext.CALLER_SYSTEM_USER_UID); // But first pretend the user is locked. Then it should fail. when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(false); @@ -1495,9 +1495,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Now call clear. - doReturn(DpmMockContext.CALLER_UID).when(getServices().packageManager).getPackageUidAsUser( - eq(admin1.getPackageName()), - anyInt()); + getServices().addTestPackageUid(admin1.getPackageName(), DpmMockContext.CALLER_UID); assertExpectException(SecurityException.class, /* messageRegex =*/ "clearDeviceOwner can only be called by the device owner", () -> dpm.clearDeviceOwnerApp(admin1.getPackageName())); @@ -1734,9 +1732,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(userId)); doReturn(true).when(getServices().ipackageManager).isPackageAvailable(packageName, userId); // Setup application UID with the PackageManager - doReturn(uid).when(getServices().packageManager).getPackageUidAsUser( - eq(packageName), - eq(userId)); + getServices().addTestPackageUid(packageName, uid); // Associate packageName to uid doReturn(packageName).when(getServices().ipackageManager).getNameForUid(eq(uid)); doReturn(new String[]{packageName}) @@ -3955,9 +3951,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(dpms.hasUserSetupCompleted()).isFalse(); } - private void clearDeviceOwner() throws Exception { - doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(getServices().packageManager) - .getPackageUidAsUser(eq(admin1.getPackageName()), anyInt()); + private void clearDeviceOwner() { + getServices().addTestPackageUid(admin1.getPackageName(), + DpmMockContext.CALLER_SYSTEM_USER_UID); mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; runAsCaller(mAdmin1Context, dpms, dpm -> { @@ -6321,7 +6317,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID; setAsProfileOwner(admin1); - final DpmMockContext caller = new DpmMockContext(getServices(), mRealTestContext); + var caller = new DpmMockContext(getServices(), mRealTestContext); caller.packageName = "com.example.delegate"; caller.binder.callingUid = setupPackageInPackageManager(caller.packageName, CALLER_USER_HANDLE, 20988, ApplicationInfo.FLAG_HAS_CODE); @@ -6965,6 +6961,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { @Test public void testIsPackageAllowedToAccessCalendar_adminNotAllowed() { + final String testPackage = "TEST_PACKAGE"; setAsProfileOwner(admin1); dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet()); when(getServices().settings.settingsSecureGetIntForUser( @@ -6972,7 +6969,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { 0, CALLER_USER_HANDLE)).thenReturn(1); mContext.permissions.add(permission.INTERACT_ACROSS_USERS); - assertThat(dpm.isPackageAllowedToAccessCalendar("TEST_PACKAGE")).isFalse(); + assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isFalse(); } @Test @@ -6991,6 +6988,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { @Test public void testIsPackageAllowedToAccessCalendar_bothAllowed() { final String testPackage = "TEST_PACKAGE"; + getServices().addTestPackageUid(testPackage, DpmMockContext.ANOTHER_UID); setAsProfileOwner(admin1); dpm.setCrossProfileCalendarPackages(admin1, null); when(getServices().settings.settingsSecureGetIntForUser( @@ -7004,24 +7002,22 @@ public class DevicePolicyManagerTest extends DpmTestBase { @Test public void testIsPackageAllowedToAccessCalendar_requiresPermission() { final String testPackage = "TEST_PACKAGE"; + getServices().addTestPackageUid(testPackage, DpmMockContext.ANOTHER_UID); assertExpectException(SecurityException.class, /* messageRegex= */ null, () -> dpm.isPackageAllowedToAccessCalendar(testPackage)); } @Test - public void testIsPackageAllowedToAccessCalendar_samePackageAndSameUser_noPermissionRequired() - throws Exception { + public void testIsPackageAllowedToAccessCalendar_samePackageAndSameUser_noPermissionRequired() { final String testPackage = "TEST_PACKAGE"; setAsProfileOwner(admin1); dpm.setCrossProfileCalendarPackages(admin1, null); when(getServices().settings.settingsSecureGetIntForUser( Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, CALLER_USER_HANDLE)).thenReturn(1); - doReturn(mContext.binder.callingUid) - .when(getServices().packageManager).getPackageUidAsUser( - eq(testPackage), - anyInt()); + + getServices().addTestPackageUid(testPackage, mContext.binder.callingUid); assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isTrue(); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index ded8ad5956456..9ff600a6d0f86 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -171,10 +171,15 @@ public class DpmMockContext extends MockContext { public ApplicationInfo applicationInfo = null; public DpmMockContext(MockSystemServices mockSystemServices, Context context) { + this(mockSystemServices, context, new MockBinder()); + } + + public DpmMockContext(MockSystemServices mockSystemServices, Context context, + @NonNull MockBinder mockBinder) { mMockSystemServices = mockSystemServices; realTestContext = context; + binder = mockBinder; - binder = new MockBinder(); resources = mock(Resources.class); spiedContext = mock(Context.class); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index b8824c3d8268a..03aaeb7e0db8f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -67,8 +67,9 @@ public abstract class DpmTestBase { @Before public void setFixtures() throws Exception { - mServices = new MockSystemServices(mRealTestContext, "test-data"); - mMockContext = new DpmMockContext(mServices, mRealTestContext); + var mockBinder = new DpmMockContext.MockBinder(); + mServices = new MockSystemServices(mRealTestContext, "test-data", mockBinder); + mMockContext = new DpmMockContext(mServices, mRealTestContext, mockBinder); admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); @@ -150,7 +151,7 @@ public abstract class DpmTestBase { doReturn(pi).when(mServices.ipackageManager).getPackageInfo(packageName, 0, userId); - doReturn(ai.uid).when(mServices.packageManager).getPackageUidAsUser(packageName, userId); + mServices.addTestPackageUid(packageName, ai.uid); } protected void markDelegatedCertInstallerAsInstalled() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 4163f33e94e9f..16fdfb16444a0 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.when; import android.accounts.Account; import android.accounts.AccountManager; +import android.annotation.NonNull; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.AppOpsManager; @@ -55,6 +56,7 @@ import android.net.IIpConnectivityMetrics; import android.net.Uri; import android.net.VpnManager; import android.net.wifi.WifiManager; +import android.os.Binder; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManagerInternal; @@ -77,7 +79,10 @@ import com.android.internal.widget.LockSettingsInternal; import com.android.server.AlarmManagerInternal; import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; +import com.android.server.pm.PackageManagerLocal; import com.android.server.pm.UserManagerInternal; +import com.android.server.pm.pkg.PackageState; +import com.android.server.pm.pkg.PackageUserState; import com.android.server.wm.ActivityTaskManagerInternal; import java.io.File; @@ -101,6 +106,7 @@ public class MockSystemServices { public final UsageStatsManagerInternal usageStatsManagerInternal; public final NetworkPolicyManagerInternal networkPolicyManagerInternal; public final PackageManagerInternal packageManagerInternal; + public final PackageManagerLocal packageManagerLocal; public final UserManagerForMock userManagerForMock; public final PowerManagerForMock powerManager; public final PowerManagerInternal powerManagerInternal; @@ -143,7 +149,10 @@ public class MockSystemServices { public final File dataDir; public final PolicyPathProvider pathProvider; - public MockSystemServices(Context realContext, String name) { + private final Map mTestPackageStates = new ArrayMap<>(); + + public MockSystemServices(Context realContext, String name, + @NonNull DpmMockContext.MockBinder mockBinder) { dataDir = new File(realContext.getCacheDir(), name); DpmTestUtils.clearDir(dataDir); @@ -157,6 +166,7 @@ public class MockSystemServices { userManagerForMock = mock(UserManagerForMock.class); packageManagerInternal = mock(PackageManagerInternal.class); + packageManagerLocal = mock(PackageManagerLocal.class); powerManager = mock(PowerManagerForMock.class); powerManagerInternal = mock(PowerManagerInternal.class); recoverySystem = mock(RecoverySystemForMock.class); @@ -197,6 +207,14 @@ public class MockSystemServices { when(packageManagerInternal.getSystemUiServiceComponent()).thenReturn( new ComponentName("com.android.systemui", ".Service")); + addTestPackageUid("android", DpmMockContext.SYSTEM_UID); + addTestPackageUid(realContext.getPackageName(), Binder.getCallingUid()); + when(packageManagerLocal.withUnfilteredSnapshot()).thenAnswer(unused -> { + var snapshot = mock(PackageManagerLocal.UnfilteredSnapshot.class); + when(snapshot.getPackageStates()).thenAnswer(unused1 -> mTestPackageStates); + return snapshot; + }); + contentResolver = new MockContentResolver(); contentResolver.addProvider("telephony", new MockContentProvider(realContext) { @Override @@ -409,6 +427,16 @@ public class MockSystemServices { throw new UnsupportedOperationException("No package " + packageName + " for user " + user); } + public void addTestPackageUid(@NonNull String packageName, int uid) { + var packageState = mock(PackageState.class); + when(packageState.getAppId()).thenReturn(UserHandle.getAppId(uid)); + when(packageState.getUserStateOrDefault(anyInt())).thenAnswer(invocation -> { + var userState = mock(PackageUserState.class); + when(userState.isInstalled()).thenReturn(true); + return userState; + }); + mTestPackageStates.put(packageName, packageState); + } public static class EnvironmentForMock { public File getUserSystemDirectory(int userId) {