Merge "New generic background restrictions."
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
index bb4ca3d..37bf71c 100644
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ b/core/java/com/android/internal/logging/MetricsConstants.java
@@ -281,6 +281,7 @@
     public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
     public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256;
     public static final int QS_WORKMODE = 257;
+    public static final int BACKGROUND_CHECK_SUMMARY = 258;
 
     // These constants must match those in the analytic pipeline, do not edit.
     // Add temporary values to the top of MetricsLogger instead.
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2742c65..4348913 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1240,8 +1240,9 @@
                     try {
                         // Before going further -- if this app is not allowed to run in the
                         // background, then at this point we aren't going to let it period.
-                        if (!mAm.checkAllowBackgroundLocked(sInfo.applicationInfo.uid,
-                                sInfo.packageName, callingPid)) {
+                        final int allowed = mAm.checkAllowBackgroundLocked(
+                                sInfo.applicationInfo.uid, sInfo.packageName, callingPid);
+                        if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                             Slog.w(TAG, "Background execution not allowed: service "
                                     + r.intent + " to " + name.flattenToShortString()
                                     + " from pid=" + callingPid + " uid=" + callingUid
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f22062c..507233f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7463,13 +7463,11 @@
 
     public int getAppStartMode(int uid, String packageName) {
         synchronized (this) {
-            boolean bg = checkAllowBackgroundLocked(uid, packageName, -1);
-            return bg ? ActivityManager.APP_START_MODE_NORMAL
-                    : ActivityManager.APP_START_MODE_DISABLED;
+            return checkAllowBackgroundLocked(uid, packageName, -1);
         }
     }
 
-    boolean checkAllowBackgroundLocked(int uid, String packageName, int callingPid) {
+    int checkAllowBackgroundLocked(int uid, String packageName, int callingPid) {
         UidRecord uidRec = mActiveUids.get(uid);
         if (uidRec == null || uidRec.idle) {
             if (callingPid >= 0) {
@@ -7480,15 +7478,15 @@
                 if (proc != null && proc.curProcState < ActivityManager.PROCESS_STATE_RECEIVER) {
                     // Whoever is instigating this is in the foreground, so we will allow it
                     // to go through.
-                    return true;
+                    return ActivityManager.APP_START_MODE_NORMAL;
                 }
             }
             if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName)
                     != AppOpsManager.MODE_ALLOWED) {
-                return false;
+                return ActivityManager.APP_START_MODE_DELAYED;
             }
         }
-        return true;
+        return ActivityManager.APP_START_MODE_NORMAL;
     }
 
     private ProviderInfo getProviderInfoLocked(String authority, int userHandle) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index b160981..2fb71c3 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -562,8 +562,9 @@
             skip = true;
         }
         if (!skip) {
-            if (!mService.checkAllowBackgroundLocked(filter.receiverList.uid, filter.packageName,
-                    -1)) {
+            final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid,
+                    filter.packageName, -1);
+            if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                 Slog.w(TAG, "Background execution not allowed: receiving "
                         + r.intent
                         + " to " + filter.receiverList.app
@@ -1013,15 +1014,6 @@
                 skip = true;
             }
             if (!skip) {
-                if (!mService.checkAllowBackgroundLocked(info.activityInfo.applicationInfo.uid,
-                        info.activityInfo.packageName, -1)) {
-                    Slog.w(TAG, "Background execution not allowed: receiving "
-                            + r.intent + " to "
-                            + component.flattenToShortString());
-                    skip = true;
-                }
-            }
-            if (!skip) {
                 skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
                         r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
             }
@@ -1083,6 +1075,28 @@
                 }
             }
 
+            String targetProcess = info.activityInfo.processName;
+            ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
+                    info.activityInfo.applicationInfo.uid, false);
+            if (!skip) {
+                final int allowed = mService.checkAllowBackgroundLocked(
+                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1);
+                if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
+                    // We won't allow this receiver to be launched if the app has been
+                    // completely disabled from launches, or it is delayed and the broadcast
+                    // was not explicitly sent to it and this would result in a new process
+                    // for it being created.
+                    if (allowed == ActivityManager.APP_START_MODE_DISABLED
+                            || (r.intent.getComponent() == null
+                            && r.intent.getPackage() == null && app == null)) {
+                        Slog.w(TAG, "Background execution not allowed: receiving "
+                                + r.intent + " to "
+                                + component.flattenToShortString());
+                        skip = true;
+                    }
+                }
+            }
+
             if (skip) {
                 if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Skipping delivery of ordered [" + mQueueName + "] "
@@ -1095,7 +1109,6 @@
             }
 
             r.state = BroadcastRecord.APP_RECEIVE;
-            String targetProcess = info.activityInfo.processName;
             r.curComponent = component;
             final int receiverUid = info.activityInfo.applicationInfo.uid;
             // If it's a singleton, it needs to be the same app or a special app
@@ -1126,8 +1139,6 @@
             }
 
             // Is this receiver's application already running?
-            ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
-                    info.activityInfo.applicationInfo.uid, false);
             if (app != null && app.thread != null) {
                 try {
                     app.addPackage(info.activityInfo.packageName,