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);
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);
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
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);
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);
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
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);
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);
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
}
@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 {
}
/**
+ * 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.
*
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);
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
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
+ boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId);
+
/**
* Backup/restore support - only the system uid may use these.
*/
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);
} 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 {
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;
public PackageUserState() {
installed = true;
hidden = false;
+ suspended = false;
enabled = COMPONENT_ENABLED_STATE_DEFAULT;
domainVerificationStatus =
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
notLaunched = o.notLaunched;
enabled = o.enabled;
hidden = o.hidden;
+ suspended = o.suspended;
lastDisableAppCaller = o.lastDisableAppCaller;
disabledComponents = o.disabledComponents != null
? new ArraySet<>(o.disabledComponents) : null;
}
@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,
true, //stopped
true, //notLaunched
false, //hidden
+ false, //suspended
null, null, null,
false, // blockUninstall
ps.readUserState(userId).domainVerificationStatus, 0);
return runQueryIntentServices();
case "query-receivers":
return runQueryIntentReceivers();
+ case "suspend":
+ return runSuspend(true);
+ case "unsuspend":
+ return runSuspend(false);
default:
return handleDefaultCommands(cmd);
}
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);
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");
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 , "");
}
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;
}
}
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) {
state.stopped = stopped;
state.notLaunched = notLaunched;
state.hidden = hidden;
+ state.suspended = suspended;
state.lastDisableAppCaller = lastDisableAppCaller;
state.enabledComponents = enabledComponents;
state.disabledComponents = disabledComponents;
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";
true, // stopped,
true, // notLaunched
false, // hidden
+ false, // suspended
null, null, null,
false, // blockUninstall
INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
false, // stopped
false, // notLaunched
false, // hidden
+ false, // suspended
null, null, null,
false, // blockUninstall
INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
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);
}
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)) {
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
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");
}
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(",");
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=");
}
@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();
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public boolean setPackageSuspendedAsUser(String packageName, boolean hidden, int userId) {
+ return false;
+ }
+
/**
* @hide
*/
}
@Override
+ public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+ return false;
+ }
+
+ @Override
public int getMoveStatus(int moveId) {
return 0;
}