diff options
4 files changed, 65 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index bdb5d9356a0d..ef67cbe5024b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -77,8 +77,10 @@ import static android.os.IServiceManager.DUMP_FLAG_PROTO; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD; import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION; +import static android.os.PowerExemptionManager.REASON_BOOT_COMPLETED; import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER; import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION; +import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED; import static android.os.PowerExemptionManager.REASON_PROC_STATE_BTOP; import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT; import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI; @@ -4840,6 +4842,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (!mConstants.mEnableWaitForFinishAttachApplication) { finishAttachApplicationInner(startSeq, callingUid, pid); } + maybeSendBootCompletedLocked(app); } catch (Exception e) { // We need kill the process group here. (b/148588589) Slog.wtf(TAG, "Exception thrown during bind of " + app, e); @@ -5066,6 +5069,45 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** + * Send LOCKED_BOOT_COMPLETED and BOOT_COMPLETED to the package explicitly when unstopped + */ + private void maybeSendBootCompletedLocked(ProcessRecord app) { + // Nothing to do if it wasn't previously stopped + if (!android.content.pm.Flags.stayStopped() || !app.wasForceStopped()) return; + + // Send LOCKED_BOOT_COMPLETED, if necessary + if (app.getApplicationInfo().isEncryptionAware()) { + sendBootBroadcastToAppLocked(app, new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED), + REASON_LOCKED_BOOT_COMPLETED); + } + // Send BOOT_COMPLETED if the user is unlocked + if (StorageManager.isUserKeyUnlocked(app.userId)) { + sendBootBroadcastToAppLocked(app, new Intent(Intent.ACTION_BOOT_COMPLETED), + REASON_BOOT_COMPLETED); + } + app.setWasForceStopped(false); + } + + /** Send a boot_completed broadcast to app */ + private void sendBootBroadcastToAppLocked(ProcessRecord app, Intent intent, + @PowerExemptionManager.ReasonCode int reason) { + intent.setPackage(app.info.packageName); + intent.putExtra(Intent.EXTRA_USER_HANDLE, app.userId); + intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT + | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND + | Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + final BroadcastOptions bOptions = mUserController.getTemporaryAppAllowlistBroadcastOptions( + reason); + + broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, + new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, + null, null, AppOpsManager.OP_NONE, + bOptions.toBundle(), true, + false, MY_PID, SYSTEM_UID, + SYSTEM_UID, MY_PID, app.userId); + } + @Override public void showBootMessage(final CharSequence msg, final boolean always) { if (Binder.getCallingUid() != myUid()) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 59d8e7e96ba6..f04198ed39ec 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -3257,6 +3257,17 @@ public final class ProcessList { hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName()); final ProcessStateRecord state = r.mState; + // Check if we should mark the processrecord for first launch after force-stopping + if ((r.getApplicationInfo().flags & ApplicationInfo.FLAG_STOPPED) != 0) { + final boolean wasPackageEverLaunched = mService.getPackageManagerInternal() + .wasPackageEverLaunched(r.getApplicationInfo().packageName, r.userId); + // If the package was launched in the past but is currently stopped, only then it + // should be considered as stopped after use. Do not mark it if it's the first launch. + if (wasPackageEverLaunched) { + r.setWasForceStopped(true); + } + } + if (!isolated && !isSdkSandbox && userId == UserHandle.USER_SYSTEM && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index f02b8c737f90..2c6e598ef0a4 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -438,6 +438,9 @@ class ProcessRecord implements WindowProcessListener { final ProcessRecordNode[] mLinkedNodes = new ProcessRecordNode[NUM_NODE_TYPE]; + /** Whether the app was launched from a stopped state and is being unstopped. */ + volatile boolean mWasForceStopped; + void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startUptime, long startElapsedTime) { this.mStartUid = startUid; @@ -1602,4 +1605,12 @@ class ProcessRecord implements WindowProcessListener { List<ProcessRecord> getLruProcessList() { return mService.mProcessList.getLruProcessesLOSP(); } + + public void setWasForceStopped(boolean stopped) { + mWasForceStopped = stopped; + } + + public boolean wasForceStopped() { + return mWasForceStopped; + } } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index de4ad20bdccc..0dd579fd0b15 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -3387,7 +3387,7 @@ class UserController implements Handler.Callback { } - private BroadcastOptions getTemporaryAppAllowlistBroadcastOptions( + BroadcastOptions getTemporaryAppAllowlistBroadcastOptions( @PowerWhitelistManager.ReasonCode int reasonCode) { long duration = 10_000; final ActivityManagerInternal amInternal = |