Loading services/core/java/com/android/server/pm/PackageManagerService.java +52 −17 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); } Loading @@ -14281,7 +14305,6 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writePackageRestrictionsLPr(userId); } } } @GuardedBy("mPackages") private boolean canSuspendPackageForUserLocked(String packageName, int userId) { Loading Loading @@ -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 services/tests/servicestests/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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" Loading services/tests/servicestests/AndroidTest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java +79 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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)); } Loading Loading
services/core/java/com/android/server/pm/PackageManagerService.java +52 −17 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); } Loading @@ -14281,7 +14305,6 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writePackageRestrictionsLPr(userId); } } } @GuardedBy("mPackages") private boolean canSuspendPackageForUserLocked(String packageName, int userId) { Loading Loading @@ -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
services/tests/servicestests/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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" Loading
services/tests/servicestests/AndroidTest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading
services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java +79 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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)); } Loading