OSDN Git Service

Wire call to suspend a package
authorAndrei Stingaceanu <stg@google.com>
Thu, 26 Nov 2015 15:26:28 +0000 (15:26 +0000)
committerAndrei Stingaceanu <stg@google.com>
Wed, 16 Dec 2015 18:14:14 +0000 (18:14 +0000)
Adds APIs in DevicePolicyManager and PackageManager for allowing
a device admin to suspend a package. PackageManagerService sets
or unsets a new PackageUserState 'suspended' setting. Terminal
command to suspend/unsuspend has been added via
PackageManagerShellCommand (as root).

Next steps:
* use the new 'suspended' setting for denying access to start app
(probably in ActivityStackSupervisor)
* broadcast a PACKAGE_(UN)SUSPENDED intent for launchers to pick up
* remove app from recents (go further and kill it if it is running)
* erase existing notifications for this app

Bug: 22776576
Change-Id: I718b3498f6a53cc0c6fdfb6d15031e53ddca4353

18 files changed:
api/current.txt
api/system-current.txt
api/test-current.txt
core/java/android/app/ApplicationPackageManager.java
core/java/android/app/admin/DevicePolicyManager.java
core/java/android/app/admin/IDevicePolicyManager.aidl
core/java/android/content/pm/ApplicationInfo.java
core/java/android/content/pm/IPackageManager.aidl
core/java/android/content/pm/PackageManager.java
core/java/android/content/pm/PackageParser.java
core/java/android/content/pm/PackageUserState.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/pm/PackageManagerShellCommand.java
services/core/java/com/android/server/pm/PackageSettingBase.java
services/core/java/com/android/server/pm/Settings.java
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
test-runner/src/android/test/mock/MockPackageManager.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java

index 39a3b1e..b73214f 100644 (file)
@@ -5767,6 +5767,7 @@ package android.app.admin {
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5825,6 +5826,7 @@ package android.app.admin {
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
     method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -9097,6 +9099,7 @@ package android.content.pm {
     field public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
     field public static final int FLAG_SUPPORTS_SMALL_SCREENS = 512; // 0x200
     field public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 524288; // 0x80000
+    field public static final int FLAG_SUSPENDED = 1073741824; // 0x40000000
     field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final int FLAG_TEST_ONLY = 256; // 0x100
     field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
index 9240d4f..84dbe62 100644 (file)
@@ -5895,6 +5895,7 @@ package android.app.admin {
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5959,6 +5960,7 @@ package android.app.admin {
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
     method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -9365,6 +9367,7 @@ package android.content.pm {
     field public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
     field public static final int FLAG_SUPPORTS_SMALL_SCREENS = 512; // 0x200
     field public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 524288; // 0x80000
+    field public static final int FLAG_SUSPENDED = 1073741824; // 0x40000000
     field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final int FLAG_TEST_ONLY = 256; // 0x100
     field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
index e8d8748..390a017 100644 (file)
@@ -5767,6 +5767,7 @@ package android.app.admin {
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5825,6 +5826,7 @@ package android.app.admin {
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
     method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -9097,6 +9099,7 @@ package android.content.pm {
     field public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
     field public static final int FLAG_SUPPORTS_SMALL_SCREENS = 512; // 0x200
     field public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 524288; // 0x80000
+    field public static final int FLAG_SUSPENDED = 1073741824; // 0x40000000
     field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final int FLAG_TEST_ONLY = 256; // 0x100
     field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
index 460e68c..77721e6 100644 (file)
@@ -1858,6 +1858,16 @@ public class ApplicationPackageManager extends PackageManager {
     }
 
     @Override
+    public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+        try {
+            return mPM.setPackageSuspendedAsUser(packageName, suspended, userId);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+        return false;
+    }
+
+    @Override
     public void getPackageSizeInfo(String packageName, int userHandle,
             IPackageStatsObserver observer) {
         try {
index 08b7d62..660ce3b 100644 (file)
@@ -3092,6 +3092,48 @@ public class DevicePolicyManager {
     }
 
     /**
+     * Called by device or profile owners for setting the package suspended for this user.
+     * A suspended package will not be started by the package manager, its notifications will
+     * be hidden and it will not show up in recents. The package must already be installed.
+     *
+     * @param admin The name of the admin component to check.
+     * @param packageName The package name of the app to suspend or unsuspend.
+     * @param suspended If set to {@code true} than the package will be suspended, if set to
+     * {@code false} the package will be unsuspended.
+     * @return boolean {@code true} if the operation was successfully performed, {@code false}
+     * otherwise.
+     */
+    public boolean setPackageSuspended(@NonNull ComponentName admin, String packageName,
+            boolean suspended) {
+        if (mService != null) {
+            try {
+                return mService.setPackageSuspended(admin, packageName, suspended);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed talking with device policy service", re);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by device or profile owners to determine if a package is suspended.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param packageName The name of the package to retrieve the suspended status of.
+     * @return boolean {@code true} if the package is suspended, {@code false} otherwise.
+     */
+    public boolean getPackageSuspended(@NonNull ComponentName admin, String packageName) {
+        if (mService != null) {
+            try {
+                return mService.getPackageSuspended(admin, packageName);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Sets the enabled state of the profile. A profile should be enabled only once it is ready to
      * be used. Only the profile owner can call this.
      *
index 1708ee3..d8cc2ea 100644 (file)
@@ -130,6 +130,9 @@ interface IDevicePolicyManager {
     boolean setDeviceOwnerLockScreenInfo(in ComponentName who, String deviceOwnerInfo);
     String getDeviceOwnerLockScreenInfo();
 
+    boolean setPackageSuspended(in ComponentName admin, String packageName, boolean suspended);
+    boolean getPackageSuspended(in ComponentName admin, String packageName);
+
     boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
     void uninstallCaCerts(in ComponentName admin, in String[] aliases);
     void enforceCanManageCaCerts(in ComponentName admin);
index 1eeace1..807c0a2 100644 (file)
@@ -382,6 +382,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
     public static final int FLAG_HARDWARE_ACCELERATED = 1<<29;
 
     /**
+     * Value for {@link #flags}: true if this application's package is in
+     * the suspended state.
+     */
+    public static final int FLAG_SUSPENDED = 1<<30;
+
+    /**
      * Value for {@link #flags}: true if code from this application will need to be
      * loaded into other applications' processes. On devices that support multiple
      * instruction sets, this implies the code might be loaded into a process that's
index b947a2b..4d0d146 100644 (file)
@@ -285,6 +285,8 @@ interface IPackageManager {
 
     void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
 
+    boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId);
+
     /**
      * Backup/restore support - only the system uid may use these.
      */
index c40c8a6..3e7deb9 100644 (file)
@@ -4684,6 +4684,21 @@ public abstract class PackageManager {
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * Puts the package in a suspended state, making the package un-runnable,
+     * but it doesn't remove the data or the actual package file. The application notifications
+     * will be hidden and also the application will not show up in recents.
+     *
+     * @param packageName The name of the package to set the suspended status.
+     * @param suspended If set to {@code true} than the package will be suspended, if set to
+     * {@code false} the package will be unsuspended.
+     * @param userId The user id.
+     *
+     * @hide
+     */
+    public abstract boolean setPackageSuspendedAsUser(
+            String packageName, boolean suspended, int userId);
+
     /** {@hide} */
     public static boolean isMoveStatusFinished(int status) {
         return (status < 0 || status > 100);
index b79b6b6..019ed2b 100644 (file)
@@ -4883,6 +4883,11 @@ public class PackageParser {
         } else {
             ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
         }
+        if (state.suspended) {
+            ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
+        }
         if (state.hidden) {
             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
         } else {
index 9b28401..91fdf7f 100644 (file)
@@ -29,6 +29,7 @@ public class PackageUserState {
     public boolean notLaunched;
     public boolean installed;
     public boolean hidden; // Is the app restricted by owner / admin
+    public boolean suspended;
     public int enabled;
     public boolean blockUninstall;
 
@@ -43,6 +44,7 @@ public class PackageUserState {
     public PackageUserState() {
         installed = true;
         hidden = false;
+        suspended = false;
         enabled = COMPONENT_ENABLED_STATE_DEFAULT;
         domainVerificationStatus =
                 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
@@ -54,6 +56,7 @@ public class PackageUserState {
         notLaunched = o.notLaunched;
         enabled = o.enabled;
         hidden = o.hidden;
+        suspended = o.suspended;
         lastDisableAppCaller = o.lastDisableAppCaller;
         disabledComponents = o.disabledComponents != null
                 ? new ArraySet<>(o.disabledComponents) : null;
index cad3b3f..d64b898 100644 (file)
@@ -10216,6 +10216,36 @@ public class PackageManagerService extends IPackageManager.Stub {
     }
 
     @Override
+    public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true,
+                "setPackageSuspended for user " + userId);
+
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mPackages) {
+                final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+                if (pkgSetting != null) {
+                    if (pkgSetting.getSuspended(userId) != suspended) {
+                        pkgSetting.setSuspended(suspended, userId);
+                        mSettings.writePackageRestrictionsLPr(userId);
+                    }
+
+                    // TODO:
+                    // * broadcast a PACKAGE_(UN)SUSPENDED intent for launchers to pick up
+                    // * remove app from recents (kill app it if it is running)
+                    // * erase existing notifications for this app
+                    return true;
+                }
+
+                return false;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
+    @Override
     public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
@@ -13789,6 +13819,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                         true,  //stopped
                         true,  //notLaunched
                         false, //hidden
+                        false, //suspended
                         null, null, null,
                         false, // blockUninstall
                         ps.readUserState(userId).domainVerificationStatus, 0);
index b18c846..eef7d9b 100644 (file)
@@ -109,6 +109,10 @@ class PackageManagerShellCommand extends ShellCommand {
                     return runQueryIntentServices();
                 case "query-receivers":
                     return runQueryIntentReceivers();
+                case "suspend":
+                    return runSuspend(true);
+                case "unsuspend":
+                    return runSuspend(false);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -138,6 +142,41 @@ class PackageManagerShellCommand extends ShellCommand {
         return 0;
     }
 
+    private int runSuspend(boolean suspendedState) {
+        final PrintWriter pw = getOutPrintWriter();
+        int userId = UserHandle.USER_SYSTEM;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                default:
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+            }
+        }
+
+        String packageName = getNextArg();
+        if (packageName == null) {
+            pw.println("Error: package name not specified");
+            return 1;
+        }
+
+        try {
+            mInterface.setPackageSuspendedAsUser(packageName, suspendedState, userId);
+            ApplicationInfo appInfo = mInterface.getApplicationInfo(
+                    packageName, 0, userId);
+
+            pw.println("Package " + packageName + " new suspended state: "
+                    + ((appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0));
+            return 0;
+        } catch (RemoteException e) {
+            pw.println(e.toString());
+            return 1;
+        }
+    }
+
     private int runInstallAbandon() throws RemoteException {
         final int sessionId = Integer.parseInt(getNextArg());
         return doAbandonSession(sessionId);
@@ -1017,7 +1056,7 @@ class PackageManagerShellCommand extends ShellCommand {
         pw.println("  list features");
         pw.println("    Prints all features of the system.");
         pw.println("  list instrumentation [-f] [TARGET-PACKAGE]");
-        pw.println("    Prints all test packages; optionally only those targetting TARGET-PACKAGE");
+        pw.println("    Prints all test packages; optionally only those targeting TARGET-PACKAGE");
         pw.println("    Options:");
         pw.println("      -f: dump the name of the .apk file containing the test package");
         pw.println("  list libraries");
@@ -1051,6 +1090,10 @@ class PackageManagerShellCommand extends ShellCommand {
         pw.println("    Prints all services that can handle the given Intent.");
         pw.println("  query-receivers [--user USER_ID] INTENT");
         pw.println("    Prints all broadcast receivers that can handle the given Intent.");
+        pw.println("  suspend [--user USER_ID] TARGET-PACKAGE");
+        pw.println("    Suspends the specified package (as user).");
+        pw.println("  unsuspend [--user USER_ID] TARGET-PACKAGE");
+        pw.println("    Unsuspends the specified package (as user).");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
index 78328f5..1117988 100644 (file)
@@ -332,6 +332,14 @@ abstract class PackageSettingBase extends SettingBase {
         modifyUserState(userId).hidden = hidden;
     }
 
+    boolean getSuspended(int userId) {
+        return readUserState(userId).suspended;
+    }
+
+    void setSuspended(boolean suspended, int userId) {
+        modifyUserState(userId).suspended = suspended;
+    }
+
     boolean getBlockUninstall(int userId) {
         return readUserState(userId).blockUninstall;
     }
@@ -341,7 +349,7 @@ abstract class PackageSettingBase extends SettingBase {
     }
 
     void setUserState(int userId, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, boolean hidden,
+            boolean notLaunched, boolean hidden, boolean suspended,
             String lastDisableAppCaller, ArraySet<String> enabledComponents,
             ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
             int linkGeneration) {
@@ -351,6 +359,7 @@ abstract class PackageSettingBase extends SettingBase {
         state.stopped = stopped;
         state.notLaunched = notLaunched;
         state.hidden = hidden;
+        state.suspended = suspended;
         state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
index 22f8e96..ef2f29b 100644 (file)
@@ -195,6 +195,7 @@ final class Settings {
     private static final String ATTR_BLOCKED = "blocked";
     // New name for the above attribute.
     private static final String ATTR_HIDDEN = "hidden";
+    private static final String ATTR_SUSPENDED = "suspended";
     private static final String ATTR_INSTALLED = "inst";
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
     private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
@@ -661,6 +662,7 @@ final class Settings {
                                     true, // stopped,
                                     true, // notLaunched
                                     false, // hidden
+                                    false, // suspended
                                     null, null, null,
                                     false, // blockUninstall
                                     INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
@@ -1423,6 +1425,7 @@ final class Settings {
                                 false,  // stopped
                                 false,  // notLaunched
                                 false,  // hidden
+                                false,  // suspended
                                 null, null, null,
                                 false, // blockUninstall
                                 INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
@@ -1488,6 +1491,9 @@ final class Settings {
                     final String hiddenStr = parser.getAttributeValue(null, ATTR_HIDDEN);
                     hidden = hiddenStr == null
                             ? hidden : Boolean.parseBoolean(hiddenStr);
+                    final String suspendedStr = parser.getAttributeValue(null, ATTR_SUSPENDED);
+                    final boolean suspended = suspendedStr == null
+                            ? false : Boolean.parseBoolean(suspendedStr);
                     final String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
                     final boolean notLaunched = stoppedStr == null
                             ? false : Boolean.parseBoolean(notLaunchedStr);
@@ -1528,8 +1534,8 @@ final class Settings {
                     }
 
                     ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden,
-                            enabledCaller, enabledComponents, disabledComponents, blockUninstall,
-                            verifState, linkGeneration);
+                            suspended, enabledCaller, enabledComponents, disabledComponents,
+                            blockUninstall, verifState, linkGeneration);
                 } else if (tagName.equals("preferred-activities")) {
                     readPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -1763,6 +1769,7 @@ final class Settings {
                 if (ustate.stopped || ustate.notLaunched || !ustate.installed
                         || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
                         || ustate.hidden
+                        || ustate.suspended
                         || (ustate.enabledComponents != null
                                 && ustate.enabledComponents.size() > 0)
                         || (ustate.disabledComponents != null
@@ -1786,6 +1793,9 @@ final class Settings {
                     if (ustate.hidden) {
                         serializer.attribute(null, ATTR_HIDDEN, "true");
                     }
+                    if (ustate.suspended) {
+                        serializer.attribute(null, ATTR_SUSPENDED, "true");
+                    }
                     if (ustate.blockUninstall) {
                         serializer.attribute(null, ATTR_BLOCK_UNINSTALL, "true");
                     }
@@ -4022,6 +4032,7 @@ final class Settings {
                 pw.print(",");
                 pw.print(ps.getInstalled(user.id) ? "I" : "i");
                 pw.print(ps.getHidden(user.id) ? "B" : "b");
+                pw.print(ps.getSuspended(user.id) ? "SU" : "su");
                 pw.print(ps.getStopped(user.id) ? "S" : "s");
                 pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
                 pw.print(",");
@@ -4221,6 +4232,8 @@ final class Settings {
             pw.print(ps.getInstalled(user.id));
             pw.print(" hidden=");
             pw.print(ps.getHidden(user.id));
+            pw.print(" suspended=");
+            pw.print(ps.getSuspended(user.id));
             pw.print(" stopped=");
             pw.print(ps.getStopped(user.id));
             pw.print(" notLaunched=");
index bdaf0ab..810ee6b 100644 (file)
@@ -5783,6 +5783,51 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     }
 
     @Override
+    public boolean setPackageSuspended(ComponentName who, String packageName,
+            boolean suspended) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = mInjector.binderClearCallingIdentity();
+            try {
+                return mIPackageManager.setPackageSuspendedAsUser(
+                        packageName, suspended, callingUserId);
+            } catch (RemoteException re) {
+                // Shouldn't happen.
+                Slog.e(LOG_TAG, "Failed talking to the package manager", re);
+            } finally {
+                mInjector.binderRestoreCallingIdentity(id);
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public boolean getPackageSuspended(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = mInjector.binderClearCallingIdentity();
+            try {
+                ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(
+                        packageName, 0, callingUserId);
+                return appInfo != null &&
+                        (appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+            } catch (RemoteException re) {
+                // Shouldn't happen.
+                Slog.e(LOG_TAG, "Failed talking to the package manager", re);
+            } finally {
+                mInjector.binderRestoreCallingIdentity(id);
+            }
+            return false;
+        }
+    }
+
+    @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
index f7c63d1..2813df5 100644 (file)
@@ -808,6 +808,12 @@ public class MockPackageManager extends PackageManager {
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public boolean setPackageSuspendedAsUser(String packageName, boolean hidden, int userId) {
+        return false;
+    }
+
     /**
      * @hide
      */
index bab25c0..a2fad13 100644 (file)
@@ -749,6 +749,11 @@ public class BridgePackageManager extends PackageManager {
     }
 
     @Override
+    public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+        return false;
+    }
+
+    @Override
     public int getMoveStatus(int moveId) {
         return 0;
     }