Merge "Sending MY_PACKAGE_SUSPENDED to suspended apps" into pi-dev

This commit is contained in:
TreeHugger Robot
2018-03-28 00:45:23 +00:00
committed by Android (Google) Code Review
11 changed files with 328 additions and 48 deletions

View File

@@ -9905,6 +9905,8 @@ package android.content {
field public static final java.lang.String ACTION_MEDIA_UNMOUNTABLE = "android.intent.action.MEDIA_UNMOUNTABLE";
field public static final java.lang.String ACTION_MEDIA_UNMOUNTED = "android.intent.action.MEDIA_UNMOUNTED";
field public static final java.lang.String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
field public static final java.lang.String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
field public static final java.lang.String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
@@ -10065,6 +10067,7 @@ package android.content {
field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
field public static final java.lang.String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE";
@@ -11178,7 +11181,7 @@ package android.content.pm {
method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
method public android.os.PersistableBundle getSuspendedPackageAppExtras();
method public android.os.Bundle getSuspendedPackageAppExtras();
method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
method public abstract java.lang.String[] getSystemSharedLibraryNames();
method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);

View File

@@ -2167,15 +2167,16 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
try {
return mPM.getPackageSuspendedAppExtras(packageName, mContext.getUserId());
return mPM.getSuspendedPackageAppExtras(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
public PersistableBundle getSuspendedPackageAppExtras() {
return getSuspendedPackageAppExtras(mContext.getOpPackageName());
public Bundle getSuspendedPackageAppExtras() {
final PersistableBundle extras = getSuspendedPackageAppExtras(mContext.getOpPackageName());
return extras != null ? new Bundle(extras.deepCopy()) : null;
}
@Override

View File

@@ -1813,6 +1813,17 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
/**
* Intent extra: A {@link Bundle} of extras for a package being suspended. Will be sent with
* {@link #ACTION_MY_PACKAGE_SUSPENDED}.
*
* @see #ACTION_MY_PACKAGE_SUSPENDED
* @see #ACTION_MY_PACKAGE_UNSUSPENDED
* @see PackageManager#isPackageSuspended()
* @see PackageManager#getSuspendedPackageAppExtras()
*/
public static final String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
/**
* Intent extra: An app split name.
* <p>
@@ -2237,6 +2248,43 @@ public class Intent implements Parcelable, Cloneable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
/**
* Broadcast Action: Sent to a package that has been suspended by the system. This is sent
* whenever a package is put into a suspended state or any of it's app extras change while
* in the suspended state.
* <p> Optionally includes the following extras:
* <ul>
* <li> {@link #EXTRA_SUSPENDED_PACKAGE_EXTRAS} which is a {@link Bundle} which will contain
* useful information for the app being suspended.
* </ul>
* <p class="note">This is a protected intent that can only be sent
* by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in
* the manifest.</em>
*
* @see #ACTION_MY_PACKAGE_UNSUSPENDED
* @see #EXTRA_SUSPENDED_PACKAGE_EXTRAS
* @see PackageManager#isPackageSuspended()
* @see PackageManager#getSuspendedPackageAppExtras()
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
/**
* Broadcast Action: Sent to a package that has been unsuspended.
*
* <p class="note">This is a protected intent that can only be sent
* by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in
* the manifest.</em>
*
* @see #ACTION_MY_PACKAGE_SUSPENDED
* @see #EXTRA_SUSPENDED_PACKAGE_EXTRAS
* @see PackageManager#isPackageSuspended()
* @see PackageManager#getSuspendedPackageAppExtras()
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
/**
* Broadcast Action: A user ID has been removed from the system. The user
* ID number is stored in the extra data under {@link #EXTRA_UID}.

View File

@@ -278,7 +278,7 @@ interface IPackageManager {
boolean isPackageSuspendedForUser(String packageName, int userId);
PersistableBundle getPackageSuspendedAppExtras(String pacakgeName, int userId);
PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId);
void setSuspendedPackageAppExtras(String packageName, in PersistableBundle appExtras,
int userId);

View File

@@ -5513,7 +5513,7 @@ public abstract class PackageManager {
* Puts the package in a suspended state, where attempts at starting activities are denied.
*
* <p>It doesn't remove the data or the actual package file. The application's notifications
* will be hidden, any of the it's started activities will be stopped and it will not be able to
* will be hidden, any of its started activities will be stopped and it will not be able to
* show toasts or dialogs or ring the device. When the user tries to launch a suspended app, a
* system dialog with the given {@code dialogMessage} will be shown instead.</p>
*
@@ -5577,11 +5577,26 @@ public abstract class PackageManager {
}
/**
* Apps can query this to know if they have been suspended.
* Apps can query this to know if they have been suspended. A system app with the permission
* {@code android.permission.SUSPEND_APPS} can put any app on the device into a suspended state.
*
* <p>While in this state, the application's notifications will be hidden, any of its started
* activities will be stopped and it will not be able to show toasts or dialogs or ring the
* device. When the user tries to launch a suspended app, the system will, instead, show a
* dialog to the user informing them that they cannot use this app while it is suspended.
*
* <p>When an app is put into this state, the broadcast action
* {@link Intent#ACTION_MY_PACKAGE_SUSPENDED} will be delivered to any of its broadcast
* receivers that included this action in their intent-filters, <em>including manifest
* receivers.</em> Similarly, a broadcast action {@link Intent#ACTION_MY_PACKAGE_UNSUSPENDED}
* is delivered when a previously suspended app is taken out of this state.
* </p>
*
* @return {@code true} if the calling package has been suspended, {@code false} otherwise.
*
* @see #getSuspendedPackageAppExtras()
* @see Intent#ACTION_MY_PACKAGE_SUSPENDED
* @see Intent#ACTION_MY_PACKAGE_UNSUSPENDED
*/
public boolean isPackageSuspended() {
throw new UnsupportedOperationException("isPackageSuspended not implemented");
@@ -5602,7 +5617,7 @@ public abstract class PackageManager {
*/
@SystemApi
@RequiresPermission(Manifest.permission.SUSPEND_APPS)
public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
public @Nullable PersistableBundle getSuspendedPackageAppExtras(String packageName) {
throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
}
@@ -5631,15 +5646,17 @@ public abstract class PackageManager {
* Returns any extra information supplied as {@code appExtras} to the system when the calling
* app was suspended.
*
* <p> Note: This just returns whatever {@link PersistableBundle} was passed to the system via
* {@code setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
* String)} when suspending the package, <em> which might be {@code null}. </em></p>
* <p>Note: If no extras were supplied to the system, this method will return {@code null}, even
* when the calling app has been suspended.</p>
*
* @return A {@link PersistableBundle} containing the extras for the app, or {@code null} if the
* @return A {@link Bundle} containing the extras for the app, or {@code null} if the
* package is not currently suspended.
*
* @see #isPackageSuspended()
* @see Intent#ACTION_MY_PACKAGE_UNSUSPENDED
* @see Intent#ACTION_MY_PACKAGE_SUSPENDED
*/
public @Nullable PersistableBundle getSuspendedPackageAppExtras() {
public @Nullable Bundle getSuspendedPackageAppExtras() {
throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
}

View File

@@ -89,6 +89,8 @@
<protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
<protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
<protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
<protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
<protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />

View File

@@ -92,6 +92,7 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.ArrayUtils.appendElement;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -13987,18 +13988,15 @@ public class PackageManagerService extends IPackageManager.Stub
return packageNames;
}
// List of package names for whom the suspended state has changed.
final List<String> changedPackages = new ArrayList<>(packageNames.length);
// List of package names for whom the suspended state is not set as requested in this
// method.
final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mPackages) {
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
if (packageName == callingPackage) {
Slog.w(TAG, "Calling package: " + callingPackage + "trying to "
if (callingPackage.equals(packageName)) {
Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ (suspended ? "" : "un") + "suspend itself. Ignoring");
unactionedPackages.add(packageName);
continue;
@@ -14018,17 +14016,18 @@ public class PackageManagerService extends IPackageManager.Stub
}
pkgSetting.setSuspended(suspended, callingPackage, appExtras,
launcherExtras, userId);
changedPackages.add(packageName);
changedPackagesList.add(packageName);
}
}
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
// TODO (b/75036698): Also send each package a broadcast when suspended state changed
if (!changedPackages.isEmpty()) {
sendPackagesSuspendedForUser(changedPackages.toArray(
new String[changedPackages.size()]), userId, suspended);
if (!changedPackagesList.isEmpty()) {
final String[] changedPackages = changedPackagesList.toArray(
new String[changedPackagesList.size()]);
sendPackagesSuspendedForUser(changedPackages, userId, suspended);
sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, appExtras, userId);
synchronized (mPackages) {
scheduleWritePackageRestrictionsLocked(userId);
}
@@ -14038,7 +14037,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
public PersistableBundle getPackageSuspendedAppExtras(String packageName, int userId) {
public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
if (getPackageUid(packageName, 0, userId) != callingUid) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
@@ -14049,7 +14048,10 @@ public class PackageManagerService extends IPackageManager.Stub
throw new IllegalArgumentException("Unknown target package: " + packageName);
}
final PackageUserState packageUserState = ps.readUserState(userId);
return packageUserState.suspended ? packageUserState.suspendedAppExtras : null;
if (packageUserState.suspended) {
return packageUserState.suspendedAppExtras;
}
return null;
}
}
@@ -14065,12 +14067,49 @@ public class PackageManagerService extends IPackageManager.Stub
}
final PackageUserState packageUserState = ps.readUserState(userId);
if (packageUserState.suspended) {
// TODO (b/75036698): Also send this package a broadcast with the new app extras
packageUserState.suspendedAppExtras = appExtras;
sendMyPackageSuspendedOrUnsuspended(new String[] {packageName}, true, appExtras,
userId);
}
}
}
private void sendMyPackageSuspendedOrUnsuspended(String[] affectedPackages, boolean suspended,
PersistableBundle appExtras, int userId) {
final String action;
final Bundle intentExtras = new Bundle();
if (suspended) {
action = Intent.ACTION_MY_PACKAGE_SUSPENDED;
if (appExtras != null) {
final Bundle bundledAppExtras = new Bundle(appExtras.deepCopy());
intentExtras.putBundle(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS, bundledAppExtras);
}
} else {
action = Intent.ACTION_MY_PACKAGE_UNSUSPENDED;
}
mHandler.post(new Runnable() {
@Override
public void run() {
try {
final IActivityManager am = ActivityManager.getService();
if (am == null) {
Slog.wtf(TAG, "IActivityManager null. Cannot send MY_PACKAGE_ "
+ (suspended ? "" : "UN") + "SUSPENDED broadcasts");
return;
}
final int[] targetUserIds = new int[] {userId};
for (String packageName : affectedPackages) {
doSendBroadcast(am, action, null, intentExtras,
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
targetUserIds, false);
}
} catch (RemoteException ex) {
// Shouldn't happen as AMS is in the same process.
}
}
});
}
@Override
public boolean isPackageSuspendedForUser(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();

View File

@@ -16,55 +16,129 @@
package com.android.server.pm;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidJUnit4.class)
@MediumTest
@LargeTest
public class SuspendPackagesTest {
private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
public static final String INSTRUMENTATION_PACKAGE = "com.android.frameworks.servicestests";
public static final String ACTION_REPORT_MY_PACKAGE_SUSPENDED =
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
private Context mContext;
private PackageManager mPackageManager;
private Handler mReceiverHandler;
private ComponentName mTestReceiverComponent;
private AppCommunicationReceiver mAppCommsReceiver;
private static final class AppCommunicationReceiver extends BroadcastReceiver {
private Context context;
private boolean registered;
private SynchronousQueue<Intent> intentQueue = new SynchronousQueue<>();
AppCommunicationReceiver(Context context) {
this.context = context;
}
void register(Handler handler) {
registered = true;
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_SUSPENDED);
intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
context.registerReceiver(this, intentFilter, null, handler);
}
void unregister() {
if (registered) {
context.unregisterReceiver(this);
}
}
@Override
public void onReceive(Context context, Intent intent) {
try {
intentQueue.offer(intent, 5, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
throw new RuntimeException("Receiver thread interrupted", ie);
}
}
Intent receiveIntentFromApp() {
if (!registered) {
throw new IllegalStateException("Receiver not registered");
}
final Intent intent;
try {
intent = intentQueue.poll(5, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
}
assertNotNull("No intent received from app within 5 seconds", intent);
return intent;
}
}
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mPackageManager = mContext.getPackageManager();
mPackageManager.setPackagesSuspended(PACKAGES_TO_SUSPEND, false, null, null, null);
mReceiverHandler = new Handler(Looper.getMainLooper());
mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
SuspendTestReceiver.class.getCanonicalName());
IPackageManager ipm = AppGlobals.getPackageManager();
try {
// Otherwise implicit broadcasts will not be delivered.
ipm.setPackageStoppedState(TEST_APP_PACKAGE_NAME, false, mContext.getUserId());
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
unsuspendTestPackage();
mAppCommsReceiver = new AppCommunicationReceiver(mContext);
}
/**
* Care should be taken when used with {@link #mAppCommsReceiver} in the same test as both use
* the same handler.
*/
private Bundle requestAppAction(String action) throws InterruptedException {
final AtomicReference<Bundle> result = new AtomicReference<>();
final CountDownLatch receiverLatch = new CountDownLatch(1);
@@ -98,6 +172,24 @@ public class SuspendPackagesTest {
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
private void unsuspendTestPackage() {
final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
PACKAGES_TO_SUSPEND, false, null, null, null);
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
if (expected != null) {
expected.get(""); // hack to unparcel the bundles.
}
if (received != null) {
received.get("");
}
assertTrue(message + ": [expected: " + expected + "; received: " + received + "]",
BaseBundle.kindofEquals(expected, received));
}
@Test
public void testIsPackageSuspended() {
suspendTestPackage(null, null);
@@ -109,19 +201,73 @@ public class SuspendPackagesTest {
public void testSuspendedStateFromApp() throws Exception {
Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
assertNull(resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
final PersistableBundle appExtras = getExtras("appExtras", 20, "20", 0.2);
final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
suspendTestPackage(appExtras, null);
resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
assertTrue("resultFromApp:suspended is false",
resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
final PersistableBundle receivedAppExtras =
resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
receivedAppExtras.get(""); // hack to unparcel the bundles
appExtras.get("");
assertTrue("Received app extras " + receivedAppExtras + " different to the ones supplied",
BaseBundle.kindofEquals(appExtras, receivedAppExtras));
final Bundle receivedAppExtras =
resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
assertSameExtras("Received app extras different to the ones supplied",
appExtras, receivedAppExtras);
}
@Test
public void testMyPackageSuspendedUnsuspended() {
mAppCommsReceiver.register(mReceiverHandler);
final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
suspendTestPackage(appExtras, null);
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
assertSameExtras("Received app extras different to the ones supplied", appExtras,
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
unsuspendTestPackage();
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
assertTrue("MY_PACKAGE_UNSUSPENDED delivery not reported",
ACTION_REPORT_MY_PACKAGE_UNSUSPENDED.equals(intentFromApp.getAction()));
}
@Test
public void testUpdatingAppExtras() {
mAppCommsReceiver.register(mReceiverHandler);
final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
"1", 0.1);
suspendTestPackage(extras1, null);
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
assertSameExtras("Received app extras different to the ones supplied", extras1,
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
"2", 0.2);
mPackageManager.setSuspendedPackageAppExtras(TEST_APP_PACKAGE_NAME, extras2);
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
assertSameExtras("Received app extras different to the updated extras", extras2,
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
}
@Test
public void testCannotSuspendSelf() {
final String[] unchangedPkgs = mPackageManager.setPackagesSuspended(
new String[]{mContext.getOpPackageName()}, true, null, null, null);
assertTrue(unchangedPkgs.length == 1);
assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
}
@After
public void tearDown() throws Exception {
mAppCommsReceiver.unregister();
Thread.sleep(250); // To prevent any race with the next registerReceiver
}
@FunctionalInterface
interface Condition {
boolean isTrue();
}
}

View File

@@ -17,14 +17,18 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
LOCAL_PACKAGE_NAME := SuspendTestApp
LOCAL_DEX_PREOPT := false
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)

View File

@@ -21,7 +21,12 @@
<activity android:name=".SuspendTestActivity"
android:exported="true" />
<receiver android:name=".SuspendTestReceiver"
android:exported="true" />
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
<action android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -16,12 +16,15 @@
package com.android.servicestests.apps.suspendtestapp;
import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MY_PACKAGE_SUSPENDED;
import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MY_PACKAGE_UNSUSPENDED;
import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
public class SuspendTestReceiver extends BroadcastReceiver {
@@ -34,21 +37,33 @@ public class SuspendTestReceiver extends BroadcastReceiver {
public static final String EXTRA_SUSPENDED_APP_EXTRAS =
PACKAGE_NAME + ".extra.SUSPENDED_APP_EXTRAS";
private PackageManager mPm;
@Override
public void onReceive(Context context, Intent intent) {
mPm = context.getPackageManager();
Log.d(TAG, "Received request action " + intent.getAction());
final PackageManager packageManager = context.getPackageManager();
Log.d(TAG, "Received action " + intent.getAction());
final Bundle appExtras;
switch (intent.getAction()) {
case ACTION_GET_SUSPENDED_STATE:
final Bundle result = new Bundle();
final boolean suspended = mPm.isPackageSuspended();
final PersistableBundle appExtras = mPm.getSuspendedPackageAppExtras();
final boolean suspended = packageManager.isPackageSuspended();
appExtras = packageManager.getSuspendedPackageAppExtras();
result.putBoolean(EXTRA_SUSPENDED, suspended);
result.putParcelable(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
result.putBundle(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
setResult(0, null, result);
break;
case Intent.ACTION_MY_PACKAGE_SUSPENDED:
appExtras = intent.getBundleExtra(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS);
final Intent reportSuspendIntent = new Intent(ACTION_REPORT_MY_PACKAGE_SUSPENDED)
.putExtra(EXTRA_SUSPENDED_APP_EXTRAS, appExtras)
.setPackage(INSTRUMENTATION_PACKAGE);
context.sendBroadcast(reportSuspendIntent);
break;
case Intent.ACTION_MY_PACKAGE_UNSUSPENDED:
final Intent reportUnsuspendIntent =
new Intent(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED)
.setPackage(INSTRUMENTATION_PACKAGE);
context.sendBroadcast(reportUnsuspendIntent);
break;
default:
Log.e(TAG, "Unknown action: " + intent.getAction());
}