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

Commit 8e4bde69 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Convert personal app suspension on COMP->COPE migration" into rvc-dev am: b14310b5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11744198

Change-Id: I0be1573786d7c10403be6cd2a9baf7f96c788cb6
parents 2166572e b14310b5
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -988,4 +988,14 @@ public abstract class PackageManagerInternal {
     * Unblocks uninstall for all packages for the user.
     */
    public abstract void clearBlockUninstallForUser(@UserIdInt int userId);

    /**
     * Unsuspends all packages suspended by the given package for the user.
     */
    public abstract void unsuspendForSuspendingPackage(String suspendingPackage, int userId);

    /**
     * Returns {@code true} if the package is suspending any packages for the user.
     */
    public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
}
+21 −1
Original line number Diff line number Diff line
@@ -13518,6 +13518,17 @@ public class PackageManagerService extends IPackageManager.Stub
        removeSuspensionsBySuspendingPackage(allPackages, suspendingPackage::equals, userId);
    }
    boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
        synchronized (mLock) {
            for (final PackageSetting ps : mSettings.mPackages.values()) {
                if (ps.isSuspendedBy(suspendingPackage, userId)) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * Removes any suspensions on given packages that were added by packages that pass the given
     * predicate.
@@ -23913,7 +23924,6 @@ public class PackageManagerService extends IPackageManager.Stub
                    callingUid);
        }
        @Override
        public boolean isPlatformSigned(String packageName) {
            PackageSetting packageSetting = mSettings.mPackages.get(packageName);
@@ -25018,6 +25028,16 @@ public class PackageManagerService extends IPackageManager.Stub
                mSettings.writePackageRestrictionsLPr(userId);
            }
        }
        @Override
        public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
            PackageManagerService.this.unsuspendForSuspendingPackage(packageName, affectedUser);
        }
        @Override
        public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
            return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId);
        }
    }
    @GuardedBy("mLock")
+5 −0
Original line number Diff line number Diff line
@@ -422,6 +422,11 @@ public abstract class PackageSettingBase extends SettingBase {
        return readUserState(userId).suspended;
    }

    boolean isSuspendedBy(String suspendingPackage, int userId) {
        final PackageUserState state = readUserState(userId);
        return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
    }

    void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
            PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
        final PackageUserState existingUserState = modifyUserState(userId);
+43 −12
Original line number Diff line number Diff line
@@ -2755,7 +2755,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Slog.i(LOG_TAG, "Giving the PO additional power...");
        markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
        Slog.i(LOG_TAG, "Migrating DO policies to PO...");
        moveDoPoliciesToProfileParentAdmin(doAdmin, poAdmin.getParentActiveAdmin());
        moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
        migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
        saveSettingsLocked(poUserId);
        Slog.i(LOG_TAG, "Clearing the DO...");
        final ComponentName doAdminReceiver = doAdmin.info.getComponent();
@@ -2775,6 +2776,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                .write();
    }
    @GuardedBy("getLockObject()")
    private void migratePersonalAppSuspensionLocked(
            int doUserId, int poUserId, ActiveAdmin poAdmin) {
        final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
        if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
            Slog.i(LOG_TAG, "DO is not suspending any apps.");
            return;
        }
        if (getTargetSdk(poAdmin.info.getPackageName(), poUserId) >= Build.VERSION_CODES.R) {
            Slog.i(LOG_TAG, "PO is targeting R+, keeping personal apps suspended.");
            getUserData(doUserId).mAppsSuspended = true;
            poAdmin.mSuspendPersonalApps = true;
        } else {
            Slog.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
            pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
        }
    }
    private void uninstallOrDisablePackage(String packageName, int userHandle) {
        final ApplicationInfo appInfo;
        try {
@@ -2816,7 +2836,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        pi.uninstall(packageName, 0 /* flags */, new IntentSender((IIntentSender) mLocalSender));
    }
    private void moveDoPoliciesToProfileParentAdmin(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) {
    @GuardedBy("getLockObject()")
    private void moveDoPoliciesToProfileParentAdminLocked(
            ActiveAdmin doAdmin, ActiveAdmin parentAdmin) {
        // The following policies can be already controlled via parent instance, skip if so.
        if (parentAdmin.mPasswordPolicy.quality == PASSWORD_QUALITY_UNSPECIFIED) {
            parentAdmin.mPasswordPolicy = doAdmin.mPasswordPolicy;
@@ -16147,25 +16169,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
        Slog.i(LOG_TAG, String.format("%s personal apps for user %d",
                suspended ? "Suspending" : "Unsuspending", userId));
        if (suspended) {
            suspendPersonalAppsInPackageManager(userId);
        } else {
            mInjector.getPackageManagerInternal().unsuspendForSuspendingPackage(
                    PLATFORM_PACKAGE_NAME, userId);
        }
        synchronized (getLockObject()) {
            getUserData(userId).mAppsSuspended = suspended;
            saveSettingsLocked(userId);
        }
    }
    private void suspendPersonalAppsInPackageManager(int userId) {
        mInjector.binderWithCleanCallingIdentity(() -> {
            try {
                final String[] appsToSuspend = mInjector.getPersonalAppsForSuspension(userId);
                final String[] failedPackages = mIPackageManager.setPackagesSuspendedAsUser(
                        appsToSuspend, suspended, null, null, null, PLATFORM_PACKAGE_NAME, userId);
                if (!ArrayUtils.isEmpty(failedPackages)) {
                    Slog.wtf(LOG_TAG, String.format("Failed to %s packages: %s",
                            suspended ? "suspend" : "unsuspend", String.join(",", failedPackages)));
                final String[] failedApps = mIPackageManager.setPackagesSuspendedAsUser(
                        appsToSuspend, true, null, null, null, PLATFORM_PACKAGE_NAME, userId);
                if (!ArrayUtils.isEmpty(failedApps)) {
                    Slog.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps));
                }
            } catch (RemoteException re) {
                // Shouldn't happen.
                Slog.e(LOG_TAG, "Failed talking to the package manager", re);
            }
        });
        synchronized (getLockObject()) {
            getUserData(userId).mAppsSuspended = suspended;
            saveSettingsLocked(userId);
        }
    }
    @GuardedBy("getLockObject()")
+77 −11
Original line number Diff line number Diff line
@@ -18,17 +18,24 @@ package com.android.server.devicepolicy;
import static android.os.UserHandle.USER_SYSTEM;

import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;

import static org.junit.Assert.assertArrayEquals;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -354,8 +361,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
        prepareAdmin1AsDo();
        prepareAdminAnotherPackageAsPo(COPE_PROFILE_USER_ID);

        final DevicePolicyManagerServiceTestable dpms;
        dpms = bootDpmsUp();
        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();

        // DO should still be DO since no migration should happen.
        assertTrue(dpms.mOwners.hasDeviceOwner());
@@ -364,13 +370,12 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
    @SmallTest
    public void testCompMigrationAffiliated() throws Exception {
        prepareAdmin1AsDo();
        prepareAdmin1AsPo(COPE_PROFILE_USER_ID);
        prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);

        // Secure lock screen is needed for password policy APIs to work.
        when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);

        final DevicePolicyManagerServiceTestable dpms;
        dpms = bootDpmsUp();
        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();

        // DO should cease to be DO.
        assertFalse(dpms.mOwners.hasDeviceOwner());
@@ -408,6 +413,66 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
                    dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID)
                            .getEffectiveRestrictions()
                            .containsKey(UserManager.DISALLOW_CONFIG_DATE_TIME));
            assertEquals("Personal apps suspension wasn't migrated",
                    DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED,
                    dpm.getPersonalAppsSuspendedReasons(admin1));
        });
    }

    @SmallTest
    public void testCompMigration_keepSuspendedAppsWhenDpcIsRPlus() throws Exception {
        prepareAdmin1AsDo();
        prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);

        // Pretend some packages are suspended.
        when(getServices().packageManagerInternal.isSuspendingAnyPackages(
                PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);

        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();

        verify(getServices().packageManagerInternal, never())
                .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);

        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STARTED, USER_SYSTEM);

        // Verify that actual package suspension state is not modified after user start
        verify(getServices().packageManagerInternal, never())
                .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
        verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
                any(), anyBoolean(), any(), any(), any(), any(), anyInt());

        final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
        poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);

        runAsCaller(poContext, dpms, dpm -> {
            assertEquals("Personal apps suspension wasn't migrated",
                    DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY,
                    dpm.getPersonalAppsSuspendedReasons(admin1));
        });
    }

    @SmallTest
    public void testCompMigration_unsuspendAppsWhenDpcNotRPlus() throws Exception {
        prepareAdmin1AsDo();
        prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q);

        // Pretend some packages are suspended.
        when(getServices().packageManagerInternal.isSuspendingAnyPackages(
                PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);

        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();

        // Verify that apps get unsuspended.
        verify(getServices().packageManagerInternal)
                .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);

        final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
        poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);

        runAsCaller(poContext, dpms, dpm -> {
            assertEquals("Personal apps weren't unsuspended",
                    DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED,
                    dpm.getPersonalAppsSuspendedReasons(admin1));
        });
    }

@@ -439,22 +504,23 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
                        .getAbsoluteFile());
    }

    private void prepareAdmin1AsPo(int profileUserId) throws Exception {
    private void prepareAdmin1AsPo(int profileUserId, int targetSdk) throws Exception {
        preparePo(profileUserId, admin1, R.raw.comp_profile_owner_same_package,
                R.raw.comp_policies_profile_same_package, COPE_ADMIN1_APP_ID);
                R.raw.comp_policies_profile_same_package, COPE_ADMIN1_APP_ID, targetSdk);
    }

    private void prepareAdminAnotherPackageAsPo(int profileUserId) throws Exception {
        preparePo(profileUserId, adminAnotherPackage, R.raw.comp_profile_owner_another_package,
                R.raw.comp_policies_profile_another_package, COPE_ANOTHER_ADMIN_APP_ID);
                R.raw.comp_policies_profile_another_package, COPE_ANOTHER_ADMIN_APP_ID,
                Build.VERSION.SDK_INT);
    }

    private void preparePo(int profileUserId, ComponentName admin, int profileOwnerXmlResId,
            int policyXmlResId, int adminAppId) throws Exception {
            int policyXmlResId, int adminAppId, int targetSdk) throws Exception {
        final File profileDir = getServices().addUser(profileUserId, 0,
                UserManager.USER_TYPE_PROFILE_MANAGED, USER_SYSTEM /* profile group */);
        setUpPackageManagerForFakeAdmin(
                admin, UserHandle.getUid(profileUserId, adminAppId), admin1);
        setUpPackageManagerForFakeAdmin(admin, UserHandle.getUid(profileUserId, adminAppId),
                /* enabledSetting =*/ null, targetSdk, admin1);
        writeInputStreamToFile(getRawStream(policyXmlResId),
                (new File(profileDir, "device_policies.xml")).getAbsoluteFile());
        writeInputStreamToFile(getRawStream(profileOwnerXmlResId),
Loading