Merge "Log a WTF message if sendBroadcast() or bindService() is called from a cached state."
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index baf5af5..81a3d53 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -20,7 +20,9 @@
 import static android.Manifest.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND;
 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
 import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
 import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
@@ -2896,6 +2898,7 @@
             }
             setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId,
                     false);
+            logBindServiceFromCachedState(callingPackage, callingUid, service);
 
             if (s.app != null) {
                 ProcessServiceRecord servicePsr = s.app.mServices;
@@ -2960,6 +2963,30 @@
         return 1;
     }
 
+    /**
+     * Log a WTF message if the bindService is called by a process from a cached proc state.
+     * This WTF log is to debug background restriction, it will be removed in before final release.
+     * @param callerPackage the caller's package name.
+     * @param callingUid the caller's UID.
+     * @param intent the service's intent.
+     */
+    private void logBindServiceFromCachedState(String callerPackage, int callingUid,
+            Intent intent) {
+        final int callerUidState = mAm.getUidStateLocked(callingUid);
+        if (callerUidState == PROCESS_STATE_NONEXISTENT
+                || callerUidState < PROCESS_STATE_CACHED_ACTIVITY) {
+            return;
+        }
+        final String msg = "bindService from cached state "
+                + "[callerPackage:" + callerPackage
+                + "; callingUid:" + callingUid
+                + "; uidState:" + ProcessList.makeProcStateString(callerUidState)
+                + "; intent:" + intent
+                + ";]";
+        Slog.wtfQuiet(TAG, msg);
+        Slog.i(TAG, msg);
+    }
+
     private void maybeLogBindCrossProfileService(
             int userId, String callingPackage, int callingUid) {
         if (UserHandle.isCore(callingUid)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0e57236..5179c0d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12682,7 +12682,8 @@
                     Intent intent = allSticky.get(i);
                     BroadcastQueue queue = broadcastQueueForIntent(intent);
                     BroadcastRecord r = new BroadcastRecord(queue, intent, null,
-                            null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
+                            null, null, -1, -1, PROCESS_STATE_NONEXISTENT, false, null, null, null,
+                            OP_NONE, null, receivers,
                             null, 0, null, null, false, true, true, -1, false, null,
                             false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                     queue.enqueueParallelBroadcastLocked(r);
@@ -12960,6 +12961,7 @@
             @Nullable int[] broadcastAllowList) {
         intent = new Intent(intent);
 
+        final int callerUidState = getUidStateLocked(realCallingUid);
         final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
         // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
         if (callerInstantApp) {
@@ -13527,7 +13529,8 @@
             }
             final BroadcastQueue queue = broadcastQueueForIntent(intent);
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
-                    callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
+                    callerFeatureId, callingPid, callingUid, callerUidState, callerInstantApp,
+                    resolvedType,
                     requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
                     resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                     allowBackgroundActivityStarts, backgroundActivityStartsToken,
@@ -13625,7 +13628,8 @@
                 || resultTo != null) {
             BroadcastQueue queue = broadcastQueueForIntent(intent);
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
-                    callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
+                    callerFeatureId, callingPid, callingUid, callerUidState, callerInstantApp,
+                    resolvedType,
                     requiredPermissions, excludedPermissions, appOp, brOptions,
                     receivers, resultTo, resultCode, resultData, resultExtras,
                     ordered, sticky, false, userId, allowBackgroundActivityStarts,
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index ed70d2b..fd64c3c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
 import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
 import static android.text.TextUtils.formatSimple;
@@ -1656,6 +1658,9 @@
             scheduleBroadcastsLocked();
             return;
         }
+
+        logSendBroadcastFromCachedState(r, component);
+
         r.manifestCount++;
 
         r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
@@ -1750,6 +1755,29 @@
         mPendingBroadcastRecvIndex = recIdx;
     }
 
+    /**
+     * Log a WTF message if the broadcast is sent by a process from a cached proc state.
+     * This WTF log is to debug background restriction, it will be removed in before final release.
+     * @param r the BroadcastRecord.
+     * @param component the broadcast's resolved ComponentName.
+     */
+    private void logSendBroadcastFromCachedState(BroadcastRecord r, ComponentName component) {
+        if (r.callerUidState == PROCESS_STATE_NONEXISTENT
+                || r.callerUidState < PROCESS_STATE_CACHED_ACTIVITY) {
+            return;
+        }
+        final String msg = "sendBroadcast from cached state"
+                + "[callerPackage:" + r.callerPackage
+                + "; callingUid:" + r.callingUid
+                + "; realCallingUid:" + r.callingUid
+                + "; uidState:" + ProcessList.makeProcStateString(r.callerUidState)
+                + "; intent:" + r.intent
+                + "; component:" + component.flattenToShortString()
+                + ";]";
+        Slog.wtfQuiet(TAG, msg);
+        Slog.i(TAG, msg);
+    }
+
     private boolean noteOpForManifestReceiver(int appOp, BroadcastRecord r, ResolveInfo info,
             ComponentName component) {
         if (info.activityInfo.attributionTags == null) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8015596..53445b3 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -55,6 +55,7 @@
     final @Nullable String callerFeatureId; // which feature in the package sent this
     final int callingPid;   // the pid of who sent this
     final int callingUid;   // the uid of who sent this
+    final int callerUidState; // the sender's UID state when sent this.
     final boolean callerInstantApp; // caller is an Instant App?
     final boolean ordered;  // serialize the send to receivers?
     final boolean sticky;   // originated from existing sticky data?
@@ -244,7 +245,7 @@
     BroadcastRecord(BroadcastQueue _queue,
             Intent _intent, ProcessRecord _callerApp, String _callerPackage,
             @Nullable String _callerFeatureId, int _callingPid, int _callingUid,
-            boolean _callerInstantApp, String _resolvedType,
+            int _callerUidState, boolean _callerInstantApp, String _resolvedType,
             String[] _requiredPermissions, String[] _excludedPermissions, int _appOp,
             BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
             String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
@@ -261,6 +262,7 @@
         callerFeatureId = _callerFeatureId;
         callingPid = _callingPid;
         callingUid = _callingUid;
+        this.callerUidState = _callerUidState;
         callerInstantApp = _callerInstantApp;
         resolvedType = _resolvedType;
         requiredPermissions = _requiredPermissions;
@@ -298,6 +300,7 @@
         callerFeatureId = from.callerFeatureId;
         callingPid = from.callingPid;
         callingUid = from.callingUid;
+        callerUidState = from.callerUidState;
         callerInstantApp = from.callerInstantApp;
         ordered = from.ordered;
         sticky = from.sticky;
@@ -362,7 +365,8 @@
 
         // build a new BroadcastRecord around that single-target list
         BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
-                callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
+                callerFeatureId, callingPid, callingUid, callerUidState, callerInstantApp,
+                resolvedType,
                 requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
                 resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
                 allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index e9b5b62..ce90d99 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
 import static org.junit.Assert.assertNull;
 
 import android.content.Intent;
@@ -181,6 +183,7 @@
                 null /* callerFeatureId */,
                 0 /* callingPid */,
                 0 /* callingUid */,
+                PROCESS_STATE_NONEXISTENT,
                 false /* callerInstantApp */,
                 null /* resolvedType */,
                 null /* requiredPermissions */,
@@ -198,6 +201,6 @@
                 userId,
                 false /* allowBackgroundActivityStarts */,
                 null /* activityStartsToken */,
-                false /* timeoutExempt */ );
+                false /* timeoutExempt */);
     }
 }