diff options
| author | 2018-05-24 03:01:38 +0000 | |
|---|---|---|
| committer | 2018-05-24 03:01:38 +0000 | |
| commit | 24e913e5a84507f0c683ed492d87744c4b5e05af (patch) | |
| tree | 0691baf8d024f3d36c194961287980b51503e8c2 | |
| parent | 062c050d01972035b1d758a9649714ac879dea8d (diff) | |
| parent | 77e2245e713a30c81c1ac44a7635c7ffef193461 (diff) | |
Merge "Unsuspending packages when a PO or DO is set" into pi-dev
4 files changed, 133 insertions, 19 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9886a07c0a49..d5f936b28b8c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -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,28 +14259,50 @@ 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<>(); - synchronized (mPackages) { - for (PackageSetting ps : mSettings.mPackages.values()) { - final PackageUserState pus = ps.readUserState(userId); - if (pus.suspended && packageName.equals(pus.suspendingPackage)) { - ps.setSuspended(false, null, null, null, null, userId); - affectedPackages.add(ps.name); - } + 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 && packagePredicate.test(pus.suspendingPackage)) { + ps.setSuspended(false, null, null, null, null, userId); + affectedPackages.add(ps.name); } } - if (!affectedPackages.isEmpty()) { - final String[] packageArray = affectedPackages.toArray( - new String[affectedPackages.size()]); - sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId); - sendPackagesSuspendedForUser(packageArray, userId, false, null); - // Write package restrictions immediately to avoid an inconsistent state. - mSettings.writePackageRestrictionsLPr(userId); - } + } + if (!affectedPackages.isEmpty()) { + final String[] packageArray = affectedPackages.toArray( + new String[affectedPackages.size()]); + sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId); + sendPackagesSuspendedForUser(packageArray, userId, false, null); + // Write package restrictions immediately to avoid an inconsistent state. + mSettings.writePackageRestrictionsLPr(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 diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 2ac9df9c975c..a8efe819e518 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -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" diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml index 8f989df23b1b..5ac68d4b69d4 100644 --- a/services/tests/servicestests/AndroidTest.xml +++ b/services/tests/servicestests/AndroidTest.xml @@ -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" /> diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java index b8922eb4cc94..c186e48e8794 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java @@ -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)); } |