Introduce a grace period for bg activity starts

We allow processes that either had an activity started in them
recently, or recently finished an activity while they were
participating in a visible task to start activities from background
within 10 seconds.

Bug: 132333960
Test: atest WmTests:ActivityStarterTests
Test: atest CtsWindowManagerDeviceTestCases:ActivityStarterTests
Test: atest BackgroundActivityLaunchTest
Test: manual with bugs on b/hotlistid:1573032
Change-Id: Ica2c1abecf881ff9bb0959f17456d816350e4e96
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 772e5e6..765c9d0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -311,6 +311,9 @@
     public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
     // How long we wait until we timeout on key dispatching during instrumentation.
     static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+    // How long we permit background activity starts after an activity in the process
+    // started or finished.
+    static final long ACTIVITY_BG_START_GRACE_PERIOD_MS = 10 * 1000;
 
     /** Used to indicate that an app transition should be animated. */
     static final boolean ANIMATE = true;
@@ -1575,6 +1578,13 @@
                     }
                 }
             }
+
+            // note down that the process has finished an activity and is in background activity
+            // starts grace period
+            if (r.app != null) {
+                r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis());
+            }
+
             final long origId = Binder.clearCallingIdentity();
             try {
                 boolean res;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 12b62b9..2ad25cf 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -34,6 +34,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
 import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
 import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
@@ -50,6 +51,7 @@
 import android.content.res.Configuration;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
@@ -163,6 +165,11 @@
     private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>();
     // The most recent top-most activity that was resumed in the process for pre-Q app.
     private ActivityRecord mPreQTopResumedActivity = null;
+    // The last time an activity was launched in the process
+    private long mLastActivityLaunchTime;
+    // The last time an activity was finished in the process while the process participated
+    // in a visible task
+    private long mLastActivityFinishTime;
 
     // Last configuration that was reported to the process.
     private final Configuration mLastReportedConfiguration;
@@ -372,6 +379,20 @@
         return mUsingWrapper;
     }
 
+    void setLastActivityLaunchTime(long launchTime) {
+        if (launchTime <= mLastActivityLaunchTime) {
+            return;
+        }
+        mLastActivityLaunchTime = launchTime;
+    }
+
+    void setLastActivityFinishTimeIfNeeded(long finishTime) {
+        if (finishTime <= mLastActivityFinishTime || !hasActivityInVisibleTask()) {
+            return;
+        }
+        mLastActivityFinishTime = finishTime;
+    }
+
     public void setAllowBackgroundActivityStarts(boolean allowBackgroundActivityStarts) {
         mAllowBackgroundActivityStarts = allowBackgroundActivityStarts;
     }
@@ -381,6 +402,12 @@
         if (mAllowBackgroundActivityStarts) {
             return true;
         }
+        // allow if any activity in the caller has either started or finished very recently
+        final long now = SystemClock.uptimeMillis();
+        if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS
+                || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) {
+            return true;
+        }
         // allow if the proc is instrumenting with background activity starts privs
         if (mInstrumentingWithBackgroundActivityStartPrivileges) {
             return true;
@@ -457,6 +484,8 @@
     }
 
     void addActivityIfNeeded(ActivityRecord r) {
+        // even if we already track this activity, note down that it has been launched
+        setLastActivityLaunchTime(r.lastLaunchTime);
         if (mActivities.contains(r)) {
             return;
         }