Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a552dd65 authored by Alex Johnston's avatar Alex Johnston
Browse files

Modify setApplicationHidden and isApplicationHidden APIs

* Introduced new logic that allows the profile owner of an
  organization-owned device (COPE PO) to hide/unhide system
  apps in the personal profile.
* Modified both APIs to be callable on the parent profile
  instance if called by the COPE PO.
* When called by the COPE PO, the package provided
  must be a system package, otherwise an IllegalArgument
  Exception is thrown.

Bug: 147413198
Test: manual testing
      atest com.android.server.devicepolicy.DevicePolicyManagerTest
      atest com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testApplicationHidden
      atest com.android.cts.devicepolicy.ManagedProfileTest#testParentProfileApiDisabled

Change-Id: I4fae8acee9f00e3b9c805f29cf826f917cda6abd
parent 871fe0a9
Loading
Loading
Loading
Loading
+24 −6
Original line number Diff line number Diff line
@@ -8199,6 +8199,11 @@ public class DevicePolicyManager {
     * actual package file remain. This function can be called by a device owner, profile owner, or
     * by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
     * {@link #setDelegatedScopes}.
     * <p>
     * This method can be called on the {@link DevicePolicyManager} instance, returned by
     * {@link #getParentProfileInstance(ComponentName)}, where the caller must be the profile owner
     * of an organization-owned managed profile and the package must be a system package. If called
     * on the parent instance, then the package is hidden or unhidden in the personal profile.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
     *            {@code null} if the caller is a package access delegate.
@@ -8206,17 +8211,20 @@ public class DevicePolicyManager {
     * @param hidden {@code true} if the package should be hidden, {@code false} if it should be
     *            unhidden.
     * @return boolean Whether the hidden setting of the package was successfully updated.
     * @throws SecurityException if {@code admin} is not a device or profile owner.
     * @throws SecurityException if {@code admin} is not a device or profile owner or if called on
     *            the parent profile and the {@code admin} is not a profile owner of an
     *            organization-owned managed profile.
     * @throws IllegalArgumentException if called on the parent profile and the package provided
     *            is not a system package.
     * @see #setDelegatedScopes
     * @see #DELEGATION_PACKAGE_ACCESS
     */
    public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName,
            boolean hidden) {
        throwIfParentInstance("setApplicationHidden");
        if (mService != null) {
            try {
                return mService.setApplicationHidden(admin, mContext.getPackageName(), packageName,
                        hidden);
                        hidden, mParentInstance);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
@@ -8228,20 +8236,30 @@ public class DevicePolicyManager {
     * Determine if a package is hidden. This function can be called by a device owner, profile
     * owner, or by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
     * {@link #setDelegatedScopes}.
     * <p>
     * This method can be called on the {@link DevicePolicyManager} instance, returned by
     * {@link #getParentProfileInstance(ComponentName)}, where the caller must be the profile owner
     * of an organization-owned managed profile and the package must be a system package. If called
     * on the parent instance, this will determine whether the package is hidden or unhidden in the
     * personal profile.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
     *            {@code null} if the caller is a package access delegate.
     * @param packageName The name of the package to retrieve the hidden status of.
     * @return boolean {@code true} if the package is hidden, {@code false} otherwise.
     * @throws SecurityException if {@code admin} is not a device or profile owner.
     * @throws SecurityException if {@code admin} is not a device or profile owner or if called on
     *            the parent profile and the {@code admin} is not a profile owner of an
     *            organization-owned managed profile.
     * @throws IllegalArgumentException if called on the parent profile and the package provided
     *            is not a system package.
     * @see #setDelegatedScopes
     * @see #DELEGATION_PACKAGE_ACCESS
     */
    public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) {
        throwIfParentInstance("isApplicationHidden");
        if (mService != null) {
            try {
                return mService.isApplicationHidden(admin, mContext.getPackageName(), packageName);
                return mService.isApplicationHidden(admin, mContext.getPackageName(), packageName,
                        mParentInstance);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
+2 −2
Original line number Diff line number Diff line
@@ -233,8 +233,8 @@ interface IDevicePolicyManager {
    boolean isNotificationListenerServicePermitted(in String packageName, int userId);

    Intent createAdminSupportIntent(in String restriction);
    boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden);
    boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName);
    boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden, boolean parent);
    boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent);

    UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
    boolean removeUser(in ComponentName who, in UserHandle userHandle);
+45 −24
Original line number Diff line number Diff line
@@ -10649,30 +10649,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @Override
    public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
            boolean hidden) {
        int callingUserId = UserHandle.getCallingUserId();
        boolean result = false;
            boolean hidden, boolean parent) {
        final int userId = parent ? getProfileParentId(UserHandle.getCallingUserId())
                : UserHandle.getCallingUserId();
        boolean result;
        synchronized (getLockObject()) {
            // Ensure the caller is a DO/PO or a package access delegate.
            enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
                    DELEGATION_PACKAGE_ACCESS);
            long id = mInjector.binderClearCallingIdentity();
            try {
                result = mIPackageManager
                        .setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId);
            } catch (RemoteException re) {
                // shouldn't happen
                Slog.e(LOG_TAG, "Failed to setApplicationHiddenSetting", re);
            } finally {
                mInjector.binderRestoreCallingIdentity(id);
            if (parent) {
                getActiveAdminForCallerLocked(who,
                        DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
                // Ensure the package provided is a system package, this is to ensure that this
                // API cannot be used to leak if certain non-system package exists in the person
                // profile.
                mInjector.binderWithCleanCallingIdentity(() ->
                        enforcePackageIsSystemPackage(packageName, hidden, userId));
            }
            result = mInjector.binderWithCleanCallingIdentity(() -> mIPackageManager
                    .setApplicationHiddenSettingAsUser(packageName, hidden, userId));
        }
        final boolean isDelegate = (who == null);
        DevicePolicyEventLogger
                .createEvent(DevicePolicyEnums.SET_APPLICATION_HIDDEN)
                .setAdmin(callerPackage)
                .setBoolean(isDelegate)
                .setBoolean(parent)
                .setStrings(packageName, hidden ? "hidden" : "not_hidden")
                .write();
        return result;
@@ -10680,24 +10685,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @Override
    public boolean isApplicationHidden(ComponentName who, String callerPackage,
            String packageName) {
        int callingUserId = UserHandle.getCallingUserId();
            String packageName, boolean parent) {
        final int userId = parent ? getProfileParentId(UserHandle.getCallingUserId())
                : UserHandle.getCallingUserId();
        synchronized (getLockObject()) {
            // Ensure the caller is a DO/PO or a package access delegate.
            enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
                    DELEGATION_PACKAGE_ACCESS);
            long id = mInjector.binderClearCallingIdentity();
            try {
                return mIPackageManager.getApplicationHiddenSettingAsUser(
                        packageName, callingUserId);
            } catch (RemoteException re) {
                // shouldn't happen
                Slog.e(LOG_TAG, "Failed to getApplicationHiddenSettingAsUser", re);
            } finally {
                mInjector.binderRestoreCallingIdentity(id);
            if (parent) {
                getActiveAdminForCallerLocked(who,
                        DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
                // Ensure the package provided is a system package.
                mInjector.binderWithCleanCallingIdentity(() ->
                        enforcePackageIsSystemPackage(packageName, false, userId));
            }
            return false;
            return mInjector.binderWithCleanCallingIdentity(
                    () -> mIPackageManager.getApplicationHiddenSettingAsUser(packageName, userId));
        }
    }
    private void enforcePackageIsSystemPackage(String packageName, boolean hidden, int userId)
            throws RemoteException {
        int flags = PackageManager.MATCH_SYSTEM_ONLY;
        // If the package is currently hidden then it is considered uninstalled and
        // the MATCH_UNINSTALLED_PACKAGES flag has to be added.
        if (!hidden) {
            flags |= PackageManager.MATCH_UNINSTALLED_PACKAGES;
        }
        PackageInfo packageInfo = mIPackageManager.getPackageInfo(packageName, flags, userId);
        if (packageInfo == null || !packageInfo.applicationInfo.isSystemApp()) {
            throw new IllegalArgumentException(
                    "The provided package is not a system package");
        }
    }
+57 −0
Original line number Diff line number Diff line
@@ -2183,6 +2183,63 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
    }

    public void testSetApplicationHiddenWithDO() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);

        String packageName = "com.google.android.test";

        dpm.setApplicationHidden(admin1, packageName, true);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                true, UserHandle.USER_SYSTEM);

        dpm.setApplicationHidden(admin1, packageName, false);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                false, UserHandle.USER_SYSTEM);

        verify(getServices().ipackageManager, never()).getPackageInfo(packageName,
                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
        verify(getServices().ipackageManager, never()).getPackageInfo(packageName,
                PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_SYSTEM_ONLY,
                UserHandle.USER_SYSTEM);
    }

    public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception {
        final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;

        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);

        String packageName = "com.google.android.test";

        PackageInfo packageInfo = new PackageInfo();
        packageInfo.applicationInfo = new ApplicationInfo();
        packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
        when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID))
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        when(getServices().ipackageManager.getPackageInfo(packageName,
                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM)).thenReturn(
                packageInfo);
        when(getServices().ipackageManager.getPackageInfo(packageName,
                PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_SYSTEM_ONLY,
                UserHandle.USER_SYSTEM)).thenReturn(packageInfo);

        parentDpm.setApplicationHidden(admin1, packageName, true);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                true, UserHandle.USER_SYSTEM);

        parentDpm.setApplicationHidden(admin1, packageName, false);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                false, UserHandle.USER_SYSTEM);
    }

    public void testGetMacAddress() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);