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

Commit 2ba61c57 authored by Suprabh Shukla's avatar Suprabh Shukla Committed by android-build-merger
Browse files

Merge "Unsuspending packages when a PO or DO is set" into pi-dev

am: 24e913e5

Change-Id: Ibc0d2d064fa642f668cf084022f0f7d10e82bc88
parents 60ba3af0 24e913e5
Loading
Loading
Loading
Loading
+52 −17
Original line number Diff line number Diff line
@@ -367,6 +367,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
/**
 * Keep track of all those APKs everywhere.
@@ -14258,15 +14259,38 @@ public class PackageManagerService extends IPackageManager.Stub
     * @param packageName The package holding {@link Manifest.permission#SUSPEND_APPS} permission
     * @param affectedUser The user for which the changes are taking place.
     */
    void unsuspendForSuspendingPackage(String packageName, int affectedUser) {
    void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds()
                : new int[] {affectedUser};
        for (int userId : userIds) {
            List<String> affectedPackages = new ArrayList<>();
            unsuspendForSuspendingPackages(packageName::equals, userId);
        }
    }
    /**
     * Immediately unsuspends any packages in the given users not suspended by the platform or root.
     * To be called when a profile owner or a device owner is added.
     *
     * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
     * synchronously
     *
     * @param userIds The users for which to unsuspend packages
     */
    void unsuspendForNonSystemSuspendingPackages(ArraySet<Integer> userIds) {
        final int sz = userIds.size();
        for (int i = 0; i < sz; i++) {
            unsuspendForSuspendingPackages(
                    (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
                    userIds.valueAt(i));
        }
    }
    private void unsuspendForSuspendingPackages(Predicate<String> packagePredicate, int userId) {
        final List<String> affectedPackages = new ArrayList<>();
        synchronized (mPackages) {
            for (PackageSetting ps : mSettings.mPackages.values()) {
                final PackageUserState pus = ps.readUserState(userId);
                    if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
                if (pus.suspended && packagePredicate.test(pus.suspendingPackage)) {
                    ps.setSuspended(false, null, null, null, null, userId);
                    affectedPackages.add(ps.name);
                }
@@ -14281,7 +14305,6 @@ public class PackageManagerService extends IPackageManager.Stub
            mSettings.writePackageRestrictionsLPr(userId);
        }
    }
    }
    @GuardedBy("mPackages")
    private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
@@ -23977,6 +24000,18 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
                SparseArray<String> profileOwnerPackages) {
            mProtectedPackages.setDeviceAndProfileOwnerPackages(
                    deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
            final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>();
            if (deviceOwnerPackage != null) {
                usersWithPoOrDo.add(deviceOwnerUserId);
            }
            final int sz = profileOwnerPackages.size();
            for (int i = 0; i < sz; i++) {
                if (profileOwnerPackages.valueAt(i) != null) {
                    usersWithPoOrDo.add(profileOwnerPackages.keyAt(i));
                }
            }
            unsuspendForNonSystemSuspendingPackages(usersWithPoOrDo);
        }
        @Override
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@
    <uses-sdk android:minSdkVersion="1"
          android:targetSdkVersion="26"/>

    <application>
    <application android:testOnly="true">
        <uses-library android:name="android.test.runner" />

        <service android:name="com.android.server.accounts.TestAccountType1AuthenticatorService"
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
    <option name="test-suite-tag" value="apct-instrumentation" />
    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
        <option name="cleanup-apks" value="true" />
        <option name="install-arg" value="-t" />
        <option name="test-file-name" value="FrameworksServicesTests.apk" />
        <option name="test-file-name" value="JobTestApp.apk" />
        <option name="test-file-name" value="ConnTestApp.apk" />
+79 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;

import android.app.AppGlobals;
import android.content.BroadcastReceiver;
@@ -59,6 +60,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
@@ -97,6 +99,9 @@ public class SuspendPackagesTest {
    private AppCommunicationReceiver mAppCommsReceiver;
    private StubbedCallback mTestCallback;
    private UiDevice mUiDevice;
    private ComponentName mDeviceAdminComponent;
    private boolean mPoSet;
    private boolean mDoSet;

    private static final class AppCommunicationReceiver extends BroadcastReceiver {
        private Context context;
@@ -163,6 +168,8 @@ public class SuspendPackagesTest {
        mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
        mReceiverHandler = new Handler(Looper.getMainLooper());
        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        mDeviceAdminComponent = new ComponentName(mContext,
                "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
        IPackageManager ipm = AppGlobals.getPackageManager();
        try {
            // Otherwise implicit broadcasts will not be delivered.
@@ -469,12 +476,83 @@ public class SuspendPackagesTest {
                TEST_APP_PACKAGE_NAME, receivedPackageName);
    }

    private boolean setProfileOwner() throws IOException {
        final String result = mUiDevice.executeShellCommand("dpm set-profile-owner --user cur "
                + mDeviceAdminComponent.flattenToString());
        return mPoSet = result.trim().startsWith("Success");
    }

    private boolean setDeviceOwner() throws IOException {
        final String result = mUiDevice.executeShellCommand("dpm set-device-owner --user cur "
                + mDeviceAdminComponent.flattenToString());
        return mDoSet = result.trim().startsWith("Success");
    }

    private void removeProfileOrDeviceOwner() throws IOException {
        if (mPoSet || mDoSet) {
            mUiDevice.executeShellCommand("dpm remove-active-admin --user cur "
                    + mDeviceAdminComponent.flattenToString());
            mPoSet = mDoSet = false;
        }
    }

    @Test
    public void testCannotSuspendWhenProfileOwner() throws IOException {
        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
        assertTrue("Profile-owner could not be set", setProfileOwner());
        try {
            suspendTestPackage(null, null, null);
            fail("Suspend succeeded. Expected UnsupportedOperationException");
        } catch (UnsupportedOperationException uex) {
        }
    }

    @Test
    public void testCannotSuspendWhenDeviceOwner() throws IOException {
        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
        assertTrue("Device-owner could not be set", setDeviceOwner());
        try {
            suspendTestPackage(null, null, null);
            fail("Suspend succeeded. Expected UnsupportedOperationException");
        } catch (UnsupportedOperationException uex) {
        }
    }

    @Test
    public void testPackageUnsuspendedOnAddingDeviceOwner() throws IOException {
        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
        mAppCommsReceiver.drainPendingBroadcasts();
        suspendTestPackage(null, null, null);
        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
        assertTrue("Device-owner could not be set", setDeviceOwner());
        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
    }

    @Test
    public void testPackageUnsuspendedOnAddingProfileOwner() throws IOException {
        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
        mAppCommsReceiver.drainPendingBroadcasts();
        suspendTestPackage(null, null, null);
        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
        assertTrue("Profile-owner could not be set", setProfileOwner());
        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
    }

    @After
    public void tearDown() {
    public void tearDown() throws IOException {
        mAppCommsReceiver.unregister();
        if (mTestCallback != null) {
            mLauncherApps.unregisterCallback(mTestCallback);
        }
        removeProfileOrDeviceOwner();
        mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
                .setPackage(TEST_APP_PACKAGE_NAME));
    }