diff options
| author | 2023-10-10 17:53:27 +0000 | |
|---|---|---|
| committer | 2023-10-10 17:53:27 +0000 | |
| commit | 7250e65afb8d6dea501dc5a3ac6c8feaf187898c (patch) | |
| tree | 09438e5d25b8beb71bd468f93e86e522ba97b3d5 | |
| parent | 04728873a83efaa0d981d463c74ded6eb4ab803b (diff) | |
| parent | b630f15fe6340d3a6950ff6f26a84e06468289f1 (diff) | |
Merge "PACKAGE_UNSTOPPED broadcast" into main
12 files changed, 129 insertions, 21 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 8974daa515cb..a080773d98e8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -10992,6 +10992,7 @@ package android.content { field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED"; field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED"; field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED"; + field @FlaggedApi("android.content.pm.stay_stopped") public static final String ACTION_PACKAGE_UNSTOPPED = "android.intent.action.PACKAGE_UNSTOPPED"; field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED"; field public static final String ACTION_PASTE = "android.intent.action.PASTE"; field public static final String ACTION_PICK = "android.intent.action.PICK"; @@ -12673,6 +12674,7 @@ package android.content.pm { method public boolean isDeviceUpgrading(); method public abstract boolean isInstantApp(); method public abstract boolean isInstantApp(@NonNull String); + method @FlaggedApi("android.content.pm.stay_stopped") public boolean isPackageStopped(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean isPackageSuspended(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean isPackageSuspended(); method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index e5a73be5023a..21ed098f448a 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2954,6 +2954,17 @@ public class ApplicationPackageManager extends PackageManager { } } + @Override + public boolean isPackageStopped(@NonNull String packageName) throws NameNotFoundException { + try { + return mPM.isPackageStoppedForUser(packageName, getUserId()); + } catch (IllegalArgumentException ie) { + throw new NameNotFoundException(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ @Override public void setApplicationCategoryHint(String packageName, int categoryHint) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 44a9acd6ba2f..5f4c05f001ff 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2790,6 +2790,20 @@ public class Intent implements Parcelable, Cloneable { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED"; + + /** + * Broadcast Action: An application package that was previously in the stopped state has been + * started and is no longer considered stopped. + * <ul> + * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. + * </ul> + * + * <p class="note">This is a protected intent that can only be sent by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED) + public static final String ACTION_PACKAGE_UNSTOPPED = "android.intent.action.PACKAGE_UNSTOPPED"; + /** * Broadcast Action: Sent to the system rollback manager when a package * needs to have rollback enabled. diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index aca88d6af033..99264150f7d0 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -308,6 +308,8 @@ interface IPackageManager { boolean isPackageQuarantinedForUser(String packageName, int userId); + boolean isPackageStoppedForUser(String packageName, int userId); + Bundle getSuspendedPackageAppExtras(String packageName, int userId); /** diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 8fbe50c32881..45338bb2c0a2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -9878,6 +9878,18 @@ public abstract class PackageManager { } /** + * Query if an app is currently stopped. + * + * @return {@code true} if the given package is stopped, {@code false} otherwise + * @throws NameNotFoundException if the package could not be found. + * @see ApplicationInfo#FLAG_STOPPED + */ + @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED) + public boolean isPackageStopped(@NonNull String packageName) throws NameNotFoundException { + throw new UnsupportedOperationException("isPackageStopped not implemented"); + } + + /** * Query if an app is currently quarantined. * * @return {@code true} if the given package is quarantined, {@code false} otherwise @@ -9888,7 +9900,6 @@ public abstract class PackageManager { public boolean isPackageQuarantined(@NonNull String packageName) throws NameNotFoundException { throw new UnsupportedOperationException("isPackageQuarantined not implemented"); } - /** * Provide a hint of what the {@link ApplicationInfo#category} value should * be for the given package. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 298eb2f14dc6..a0b8cca58d9b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -48,6 +48,7 @@ <protected-broadcast android:name="android.intent.action.CANCEL_ENABLE_ROLLBACK" /> <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" /> + <protected-broadcast android:name="android.intent.action.PACKAGE_UNSTOPPED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" /> <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION" /> diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index cd879083927f..8df54569cccd 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -1428,6 +1428,12 @@ public abstract class PackageManagerInternal { @UserIdInt int userId); /** + * Sends the PACKAGE_RESTARTED broadcast on the package manager handler thread. + */ + public abstract void sendPackageRestartedBroadcast(@NonNull String packageName, + int uid, @Intent.Flags int flags); + + /** * Return a list of all historical install sessions for the given user. */ public abstract ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions( diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d3ce47c56e49..19879db1d22e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4160,26 +4160,34 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") private void finishForceStopPackageLocked(final String packageName, int uid) { - Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, - Uri.fromParts("package", packageName, null)); + int flags = 0; if (!mProcessesReady) { - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY - | Intent.FLAG_RECEIVER_FOREGROUND); - } - final int userId = UserHandle.getUserId(uid); - final int[] broadcastAllowList = - getPackageManagerInternal().getVisibilityAllowList(packageName, userId); - intent.putExtra(Intent.EXTRA_UID, uid); - intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - broadcastIntentLocked(null /* callerApp */, null /* callerPackage */, - null /* callerFeatureId */, intent, null /* resolvedType */, - null /* resultToApp */, null /* resultTo */, - 0 /* resultCode */, null /* resultData */, null /* resultExtras */, - null /* requiredPermissions */, null /* excludedPermissions */, - null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */, - false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(), - Binder.getCallingPid(), userId, BackgroundStartPrivileges.NONE, - broadcastAllowList, null /* filterExtrasForReceiver */); + flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND; + } + if (android.content.pm.Flags.stayStopped()) { + // Sent async using the PM handler, to maintain ordering with PACKAGE_UNSTOPPED + mPackageManagerInt.sendPackageRestartedBroadcast(packageName, + uid, flags); + } else { + Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, + Uri.fromParts("package", packageName, null)); + intent.addFlags(flags); + final int userId = UserHandle.getUserId(uid); + final int[] broadcastAllowList = + getPackageManagerInternal().getVisibilityAllowList(packageName, userId); + intent.putExtra(Intent.EXTRA_UID, uid); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + broadcastIntentLocked(null /* callerApp */, null /* callerPackage */, + null /* callerFeatureId */, intent, null /* resolvedType */, + null /* resultToApp */, null /* resultTo */, + 0 /* resultCode */, null /* resultData */, null /* resultExtras */, + null /* requiredPermissions */, null /* excludedPermissions */, + null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */, + false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(), + Binder.getCallingPid(), userId, BackgroundStartPrivileges.NONE, + broadcastAllowList, null /* filterExtrasForReceiver */); + } } private void cleanupDisabledPackageComponentsLocked( diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index f9876299e8e0..79cd2a0b236f 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -489,6 +489,9 @@ public interface Computer extends PackageDataSnapshot { boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId); + /** Check if the package is in a stopped state for a given user. */ + boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId); + boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId); @NonNull diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 5d2944e17943..7db7bf538c37 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -4938,7 +4938,7 @@ public class ComputerEngine implements Computer { int userId) { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, - false /* checkShell */, "isPackageSuspendedForUser for user " + userId); + false /* checkShell */, "when asking about packages for user " + userId); final PackageStateInternal ps = mSettings.getPackage(packageName); if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) { throw new IllegalArgumentException("Unknown target package: " + packageName); @@ -4957,6 +4957,11 @@ public class ComputerEngine implements Computer { } @Override + public boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId) { + return getUserStageOrDefaultForUser(packageName, userId).isStopped(); + } + + @Override public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId) { for (final PackageStateInternal packageState : getPackageStates().values()) { diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index 76203ac7650d..9a0306b77c41 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -961,6 +961,12 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { } @Override + public final boolean isPackageStoppedForUser(@NonNull String packageName, + @UserIdInt int userId) { + return snapshot().isPackageStoppedForUser(packageName, userId); + } + + @Override @Deprecated public final boolean isSafeMode() { // allow instant applications diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a99a0c05f3bd..6260dd583bf9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4498,6 +4498,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService boolean stopped, @UserIdInt int userId) { if (!mUserManager.exists(userId)) return; final int callingUid = Binder.getCallingUid(); + boolean wasStopped = false; if (snapshot.getInstantAppPackageName(callingUid) == null) { final int permission = mContext.checkCallingOrSelfPermission( Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); @@ -4519,6 +4520,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService ? null : packageState.getUserStateOrDefault(userId); if (packageState != null && packageUserState.isStopped() != stopped) { boolean wasNotLaunched = packageUserState.isNotLaunched(); + wasStopped = packageUserState.isStopped(); commitPackageStateMutation(null, packageName, state -> { PackageUserStateWrite userState = state.userState(userId); userState.setStopped(stopped); @@ -4550,6 +4552,24 @@ public class PackageManagerService implements PackageSender, TestUtilityService ah.setHibernatingGlobally(packageName, false); } }); + // Send UNSTOPPED broadcast if necessary + if (wasStopped && Flags.stayStopped()) { + final PackageManagerInternal pmi = + mInjector.getLocalService(PackageManagerInternal.class); + final int [] userIds = resolveUserIds(userId); + final SparseArray<int[]> broadcastAllowList = + snapshotComputer().getVisibilityAllowLists(packageName, userIds); + final Bundle extras = new Bundle(); + extras.putInt(Intent.EXTRA_UID, pmi.getPackageUid(packageName, 0, userId)); + extras.putInt(Intent.EXTRA_USER_HANDLE, userId); + mHandler.post(() -> { + mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTOPPED, + packageName, extras, + Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, + userIds, null, broadcastAllowList, null, + null); + }); + } } } @@ -6926,6 +6946,25 @@ public class PackageManagerService implements PackageSender, TestUtilityService public ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(int userId) { return mInstallerService.getHistoricalSessions(userId); } + + @Override + public void sendPackageRestartedBroadcast(@NonNull String packageName, + int uid, @Intent.Flags int flags) { + final int userId = UserHandle.getUserId(uid); + final int [] userIds = resolveUserIds(userId); + final SparseArray<int[]> broadcastAllowList = + snapshotComputer().getVisibilityAllowLists(packageName, userIds); + final Bundle extras = new Bundle(); + extras.putInt(Intent.EXTRA_UID, uid); + extras.putInt(Intent.EXTRA_USER_HANDLE, userId); + mHandler.post(() -> { + mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_RESTARTED, + packageName, extras, + flags, null, null, + userIds, null, broadcastAllowList, null, + null); + }); + } } private void setEnabledOverlayPackages(@UserIdInt int userId, |