diff options
13 files changed, 219 insertions, 32 deletions
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 258f53d982d2..52988460606c 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -119,6 +119,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE_EXECUTING; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; @@ -1497,6 +1498,11 @@ public final class ActiveServices { FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName, serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START); mAm.mBatteryStatsService.noteServiceStartRunning(uid, packageName, serviceName); + final ProcessRecord hostApp = r.app; + final boolean wasStopped = hostApp == null ? wasStopped(r) : false; + final boolean firstLaunch = + hostApp == null ? !mAm.wasPackageEverLaunched(r.packageName, r.userId) : false; + String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false /* whileRestarting */, false /* permissionsReviewRequired */, @@ -1509,10 +1515,14 @@ public final class ActiveServices { return new ComponentName("!!", error); } - final boolean wasStopped = (r.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0; final int packageState = wasStopped ? SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED : SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL; + if (DEBUG_PROCESSES) { + Slog.d(TAG, "Logging startService for " + packageName + ", stopped=" + + wasStopped + ", firstLaunch=" + firstLaunch + ", intent=" + service + + ", r.app=" + r.app); + } FrameworkStatsLog.write(SERVICE_REQUEST_EVENT_REPORTED, uid, callingUid, service.getAction(), SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__START, false, @@ -1527,7 +1537,9 @@ public final class ActiveServices { packageName, callingPackage, callingProcessState, - r.mProcessStateOnRequest); + r.mProcessStateOnRequest, + firstLaunch, + 0L /* TODO: stoppedDuration */); if (r.startRequested && addToStarting) { boolean first = smap.mStartingBackground.size() == 0; @@ -4038,7 +4050,6 @@ public final class ActiveServices { mAm.requireAllowedAssociationsLocked(s.appInfo.packageName); } - final boolean wasStopped = (s.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0; final boolean wasStartRequested = s.startRequested; final boolean hadConnections = !s.getConnections().isEmpty(); mAm.startAssociationLocked(callerApp.uid, callerApp.processName, @@ -4113,6 +4124,10 @@ public final class ActiveServices { true); } + final boolean wasStopped = hostApp == null ? wasStopped(s) : false; + final boolean firstLaunch = + hostApp == null ? !mAm.wasPackageEverLaunched(s.packageName, s.userId) : false; + boolean needOomAdj = false; if (c.hasFlag(Context.BIND_AUTO_CREATE)) { s.lastActivity = SystemClock.uptimeMillis(); @@ -4155,6 +4170,10 @@ public final class ActiveServices { final int packageState = wasStopped ? SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED : SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL; + if (DEBUG_PROCESSES) { + Slog.d(TAG, "Logging bindService for " + s.packageName + + ", stopped=" + wasStopped + ", firstLaunch=" + firstLaunch); + } FrameworkStatsLog.write(SERVICE_REQUEST_EVENT_REPORTED, s.appInfo.uid, callingUid, ActivityManagerService.getShortAction(service.getAction()), SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__BIND, false, @@ -4169,7 +4188,9 @@ public final class ActiveServices { s.packageName, callerApp.info.packageName, callerApp.mState.getCurProcState(), - s.mProcessStateOnRequest); + s.mProcessStateOnRequest, + firstLaunch, + 0L /* TODO */); if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b + ": received=" + b.intent.received @@ -9112,4 +9133,8 @@ public final class ActiveServices { return mCachedDeviceProvisioningPackage != null && mCachedDeviceProvisioningPackage.equals(packageName); } + + private boolean wasStopped(ServiceRecord serviceRecord) { + return (serviceRecord.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0; + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5e367097b78c..7bd67453624f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5046,8 +5046,11 @@ public class ActivityManagerService extends IActivityManager.Stub * Send LOCKED_BOOT_COMPLETED and BOOT_COMPLETED to the package explicitly when unstopped */ private void maybeSendBootCompletedLocked(ProcessRecord app) { + if (!android.content.pm.Flags.stayStopped()) return; // Nothing to do if it wasn't previously stopped - if (!android.content.pm.Flags.stayStopped() || !app.wasForceStopped()) return; + if (!app.wasForceStopped() && !app.getWindowProcessController().wasForceStopped()) { + return; + } // Send LOCKED_BOOT_COMPLETED, if necessary if (app.getApplicationInfo().isEncryptionAware()) { @@ -5059,7 +5062,8 @@ public class ActivityManagerService extends IActivityManager.Stub sendBootBroadcastToAppLocked(app, new Intent(Intent.ACTION_BOOT_COMPLETED), REASON_BOOT_COMPLETED); } - app.setWasForceStopped(false); + // The stopped state is reset in ProcessRecord when the pid changes, to deal with + // any re-use of the ProcessRecord. } /** Send a boot_completed broadcast to app */ @@ -6844,6 +6848,17 @@ public class ActivityManagerService extends IActivityManager.Stub return mPermissionManagerInt; } + /** Returns whether the given package was ever launched since install */ + boolean wasPackageEverLaunched(String packageName, @UserIdInt int userId) { + boolean wasLaunched = false; + try { + wasLaunched = getPackageManagerInternal().wasPackageEverLaunched(packageName, userId); + } catch (Exception e) { + // If the package state record doesn't exist yet, assume it was never launched + } + return wasLaunched; + } + private TestUtilityService getTestUtilityServiceLocked() { if (mTestUtilityService == null) { mTestUtilityService = diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java index 1dc384d61c91..3e633ccf798c 100644 --- a/services/core/java/com/android/server/am/AppStartInfoTracker.java +++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java @@ -54,6 +54,7 @@ import com.android.internal.app.ProcessMap; import com.android.server.IoThread; import com.android.server.ServiceThread; import com.android.server.SystemServiceManager; +import com.android.server.wm.WindowProcessController; import java.io.File; import java.io.FileInputStream; @@ -385,8 +386,10 @@ public final class AppStartInfoTracker { start.setPackageName(app.info.packageName); if (android.content.pm.Flags.stayStopped()) { // TODO: Verify this is created at the right time to have the correct force-stopped - // state in the ProcessRecord. Also use the WindowProcessRecord if activity. - start.setForceStopped(app.wasForceStopped()); + // state in the ProcessRecord. + final WindowProcessController wpc = app.getWindowProcessController(); + start.setForceStopped(app.wasForceStopped() + || (wpc != null ? wpc.wasForceStopped() : false)); } } diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 298eb794c220..e98e1ba6a44e 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -182,6 +182,12 @@ class BroadcastProcessQueue { private boolean mActiveWasStopped; /** + * Flag indicating that the currently active broadcast is being dispatched + * to a package that was never launched before. + */ + private boolean mActiveFirstLaunch; + + /** * Number of consecutive urgent broadcasts that have been dispatched * since the last non-urgent dispatch. */ @@ -626,6 +632,10 @@ class BroadcastProcessQueue { mActiveWasStopped = activeWasStopped; } + public void setActiveFirstLaunch(boolean activeFirstLaunch) { + mActiveFirstLaunch = activeFirstLaunch; + } + public boolean getActiveViaColdStart() { return mActiveViaColdStart; } @@ -634,6 +644,10 @@ class BroadcastProcessQueue { return mActiveWasStopped; } + public boolean getActiveFirstLaunch() { + return mActiveFirstLaunch; + } + /** * Get package name of the first application loaded into this process. */ diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 569f9ecf5d0b..5521381e8908 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -32,6 +32,7 @@ import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVE import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO; import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList; import static com.android.server.am.BroadcastProcessQueue.reasonToString; @@ -984,6 +985,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { queue.setActiveWasStopped(true); } final int intentFlags = r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND; + final boolean firstLaunch = !mService.wasPackageEverLaunched(info.packageName, r.userId); + queue.setActiveFirstLaunch(firstLaunch); + final HostingRecord hostingRecord = new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST, component, r.intent.getAction(), r.getHostingRecordTriggerType()); final boolean isActivityCapable = (r.options != null @@ -2138,6 +2142,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue { final long dispatchDelay = r.scheduledTime[index] - r.enqueueTime; final long receiveDelay = 0; final long finishDelay = r.terminalTime[index] - r.scheduledTime[index]; + if (DEBUG_PROCESSES) { + Slog.d(TAG, "Logging broadcast for " + + (app != null ? app.info.packageName : "<null>") + + ", stopped=" + queue.getActiveWasStopped() + + ", firstLaunch=" + queue.getActiveFirstLaunch()); + } if (queue != null) { final int packageState = queue.getActiveWasStopped() ? SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED @@ -2147,7 +2157,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue { app != null ? app.info.packageName : null, r.callerPackage, r.calculateTypeForLogging(), r.getDeliveryGroupPolicy(), r.intent.getFlags(), BroadcastRecord.getReceiverPriority(receiver), r.callerProcState, - receiverProcessState); + receiverProcessState, queue.getActiveFirstLaunch(), + 0L /* TODO: stoppedDuration */); + // Reset the states after logging + queue.setActiveFirstLaunch(false); + queue.setActiveWasStopped(false); } } diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index cb7898d8b862..f76bf37e4d58 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -34,6 +34,7 @@ import static com.android.internal.util.FrameworkStatsLog.PROVIDER_ACQUISITION_E import static com.android.internal.util.FrameworkStatsLog.PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD; import static com.android.internal.util.FrameworkStatsLog.PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerService.TAG_MU; import static com.android.server.am.Flags.serviceBindingOomAdjPolicy; @@ -290,7 +291,8 @@ public class ContentProviderHelper { PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM, PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL, cpi.packageName, callingPackage, - callingProcessState, callingProcessState); + callingProcessState, callingProcessState, + false, 0L); return holder; } @@ -368,7 +370,7 @@ public class ContentProviderHelper { PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM, PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL, cpi.packageName, callingPackage, - callingProcessState, providerProcessState); + callingProcessState, providerProcessState, false, 0L); } } finally { Binder.restoreCallingIdentity(origId); @@ -546,12 +548,16 @@ public class ContentProviderHelper { PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM, PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL, cpi.packageName, callingPackage, - callingProcessState, proc.mState.getCurProcState()); + callingProcessState, proc.mState.getCurProcState(), + false, 0L); } else { - final int packageState = - ((cpr.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) + final boolean stopped = + (cpr.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0; + final int packageState = stopped ? PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED : PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL; + final boolean firstLaunch = !mService.wasPackageEverLaunched( + cpi.packageName, userId); checkTime(startTime, "getContentProviderImpl: before start process"); proc = mService.startProcessLocked( cpi.processName, cpr.appInfo, false, 0, @@ -567,12 +573,18 @@ public class ContentProviderHelper { + ": process is bad"); return null; } + if (DEBUG_PROCESSES) { + Slog.d(TAG, "Logging provider access for " + cpi.packageName + + ", stopped=" + stopped + ", firstLaunch=" + firstLaunch); + } FrameworkStatsLog.write( PROVIDER_ACQUISITION_EVENT_REPORTED, proc.uid, callingUid, PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD, packageState, cpi.packageName, callingPackage, - callingProcessState, ActivityManager.PROCESS_STATE_NONEXISTENT); + callingProcessState, ActivityManager.PROCESS_STATE_NONEXISTENT, + firstLaunch, + 0L /* TODO: stoppedDuration */); } cpr.launchingApp = proc; mLaunchingProviders.add(cpr); diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java index 30811a175bac..1a78a13cbf8c 100644 --- a/services/core/java/com/android/server/am/HostingRecord.java +++ b/services/core/java/com/android/server/am/HostingRecord.java @@ -325,4 +325,15 @@ public final class HostingRecord { return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_UNKNOWN; } } + + private static boolean isTypeActivity(String hostingType) { + return HOSTING_TYPE_ACTIVITY.equals(hostingType) + || HOSTING_TYPE_NEXT_ACTIVITY.equals(hostingType) + || HOSTING_TYPE_NEXT_TOP_ACTIVITY.equals(hostingType) + || HOSTING_TYPE_TOP_ACTIVITY.equals(hostingType); + } + + public boolean isTypeActivity() { + return isTypeActivity(mHostingType); + } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index a1fdd5070527..27d6c608cf6c 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -59,6 +59,8 @@ import static com.android.server.am.ActivityManagerService.TAG_LRU; import static com.android.server.am.ActivityManagerService.TAG_NETWORK; import static com.android.server.am.ActivityManagerService.TAG_PROCESSES; import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; +import static com.android.server.wm.WindowProcessController.STOPPED_STATE_FIRST_LAUNCH; +import static com.android.server.wm.WindowProcessController.STOPPED_STATE_FORCE_STOPPED; import android.Manifest; import android.annotation.NonNull; @@ -3327,19 +3329,24 @@ public final class ProcessList { hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName()); final ProcessStateRecord state = r.mState; + final boolean wasStopped = (info.flags & ApplicationInfo.FLAG_STOPPED) != 0; // Check if we should mark the processrecord for first launch after force-stopping - if ((r.getApplicationInfo().flags & ApplicationInfo.FLAG_STOPPED) != 0) { - try { - final boolean wasPackageEverLaunched = mService.getPackageManagerInternal() + if (wasStopped) { + // Check if the hosting record is for an activity or not. Since the stopped + // state tracking is handled differently to avoid WM calling back into AM, + // store the state in the correct record + if (hostingRecord.isTypeActivity()) { + final boolean wasPackageEverLaunched = mService .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); - } - } catch (IllegalArgumentException e) { - // App doesn't have state yet, so wasn't forcestopped + // If the package was launched in the past but is currently stopped, only then + // should it be considered as force-stopped. + @WindowProcessController.StoppedState int stoppedState = wasPackageEverLaunched + ? STOPPED_STATE_FORCE_STOPPED + : STOPPED_STATE_FIRST_LAUNCH; + r.getWindowProcessController().setStoppedState(stoppedState); + } else { + r.setWasForceStopped(true); + // first launch is computed just before logging, for non-activity types } } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 7356588b408a..9fa3a8bf6f3b 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -439,6 +439,7 @@ 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. */ + @GuardedBy("mService") volatile boolean mWasForceStopped; void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, @@ -684,6 +685,11 @@ class ProcessRecord implements WindowProcessListener { @GuardedBy({"mService", "mProcLock"}) void setPid(int pid) { + // If the pid is changing and not the first time pid is being assigned, clear stopped state + // So if the process record is re-used for a different pid, it wouldn't keep the state. + if (pid != mPid && mPid != 0) { + setWasForceStopped(false); + } mPid = pid; mWindowProcessController.setPid(pid); mShortStringName = null; diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING index feab2c05cad6..bac513221c78 100644 --- a/services/core/java/com/android/server/am/TEST_MAPPING +++ b/services/core/java/com/android/server/am/TEST_MAPPING @@ -8,6 +8,7 @@ { "include-filter": "android.app.cts.ActivityManagerProcessStateTest" }, { "include-filter": "android.app.cts.ServiceTest" }, { "include-filter": "android.app.cts.ActivityManagerFgsBgStartTest" }, + { "include-filter": "android.app.cts.ForceStopTest" }, { "include-annotation": "android.platform.test.annotations.Presubmit" }, diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 78f501ad9fed..59a56de16ce6 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -1133,10 +1133,12 @@ class ActivityMetricsLogger { isIncremental = true; isLoading = isIncrementalLoading(info.packageName, info.userId); } - final boolean stopped = (info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0; + final boolean stopped = wasStoppedNeedsLogging(info); final int packageState = stopped ? APP_START_OCCURRED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED : APP_START_OCCURRED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL; + + final boolean firstLaunch = wasFirstLaunch(info); FrameworkStatsLog.write( FrameworkStatsLog.APP_START_OCCURRED, info.applicationInfo.uid, @@ -1163,18 +1165,26 @@ class ActivityMetricsLogger { TimeUnit.NANOSECONDS.toMillis(info.timestampNs), processState, processOomAdj, - packageState); + packageState, + false, // is_xr_activity + firstLaunch, + 0L /* TODO: stoppedDuration */); + // Reset the stopped state to avoid reporting stopped again + if (info.processRecord != null) { + info.processRecord.setWasStoppedLogged(true); + } if (DEBUG_METRICS) { - Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)", + Slog.i(TAG, String.format( + "APP_START_OCCURRED(%s, %s, %s, %s, %s, wasStopped=%b, firstLaunch=%b)", info.applicationInfo.uid, info.packageName, getAppStartTransitionType(info.type, info.relaunched), info.launchedActivityName, - info.launchedActivityLaunchedFromPackage)); + info.launchedActivityLaunchedFromPackage, + stopped, firstLaunch)); } - logAppStartMemoryStateCapture(info); } @@ -1794,4 +1804,28 @@ class ActivityMetricsLogger { return -1; } } + + private boolean wasStoppedNeedsLogging(TransitionInfoSnapshot info) { + if (info.processRecord != null) { + return (info.processRecord.wasForceStopped() + || info.processRecord.wasFirstLaunch()) + && !info.processRecord.getWasStoppedLogged(); + } else { + return (info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0; + } + } + + private boolean wasFirstLaunch(TransitionInfoSnapshot info) { + if (info.processRecord != null) { + return info.processRecord.wasFirstLaunch() + && !info.processRecord.getWasStoppedLogged(); + } + try { + return !mSupervisor.mService.getPackageManagerInternalLocked() + .wasPackageEverLaunched(info.packageName, info.userId); + } catch (Exception e) { + // Couldn't find the state record, so must be a newly installed app + return true; + } + } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index ee16a37d6baf..6ac2774941e1 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -114,6 +114,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private static final long RAPID_ACTIVITY_LAUNCH_MS = 300; private static final long RESET_RAPID_ACTIVITY_LAUNCH_MS = 5 * RAPID_ACTIVITY_LAUNCH_MS; + public static final int STOPPED_STATE_NOT_STOPPED = 0; + public static final int STOPPED_STATE_FIRST_LAUNCH = 1; + public static final int STOPPED_STATE_FORCE_STOPPED = 2; + private int mRapidActivityLaunchCount; // all about the first app in the process @@ -281,6 +285,22 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio @AnimatingReason private int mAnimatingReasons; + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + STOPPED_STATE_NOT_STOPPED, + STOPPED_STATE_FIRST_LAUNCH, + STOPPED_STATE_FORCE_STOPPED + }) + public @interface StoppedState {} + + private volatile @StoppedState int mStoppedState; + + /** + * Whether the stopped state was logged for an activity start, as we don't want to log + * multiple times. + */ + private volatile boolean mWasStoppedLogged; + // The bits used for mActivityStateFlags. private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16; private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17; @@ -1928,6 +1948,29 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio && (mInfo.flags & ApplicationInfo.FLAG_FACTORY_TEST) != 0; } + /** Sets the current stopped state of the app, which is reset as soon as metrics are logged */ + public void setStoppedState(@StoppedState int stoppedState) { + mStoppedState = stoppedState; + } + + boolean getWasStoppedLogged() { + return mWasStoppedLogged; + } + + void setWasStoppedLogged(boolean logged) { + mWasStoppedLogged = logged; + } + + /** Returns whether the app had been force-stopped before this launch */ + public boolean wasForceStopped() { + return mStoppedState == STOPPED_STATE_FORCE_STOPPED; + } + + /** Returns whether this app is being launched for the first time since install */ + boolean wasFirstLaunch() { + return mStoppedState == STOPPED_STATE_FIRST_LAUNCH; + } + void setRunningRecentsAnimation(boolean running) { if (running) { addAnimatingReason(ANIMATING_REASON_LEGACY_RECENT_ANIMATION); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 079bc37b6642..a2756ffc9add 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -42,6 +42,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -1478,7 +1479,8 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest { eq(BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST), eq(BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD), anyLong(), anyLong(), anyLong(), anyInt(), nullable(String.class), - anyString(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt()), + anyString(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), + anyBoolean(), anyLong()), times(1)); } |