diff --git a/api/system-current.txt b/api/system-current.txt index 7e95ddc0d6499..76a71cd7c44ef 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -317,6 +317,7 @@ package android.app { public class BroadcastOptions { method public static android.app.BroadcastOptions makeBasic(); + method public void setDontSendToRestrictedApps(boolean); method public void setTemporaryAppWhitelistDuration(long); method public android.os.Bundle toBundle(); } diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index b6cff385d7523..69c3632b7ab24 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -32,6 +32,7 @@ public class BroadcastOptions { private long mTemporaryAppWhitelistDuration; private int mMinManifestReceiverApiLevel = 0; private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; + private boolean mDontSendToRestrictedApps = false; /** * How long to temporarily put an app on the power whitelist when executing this broadcast @@ -52,6 +53,12 @@ public class BroadcastOptions { static final String KEY_MAX_MANIFEST_RECEIVER_API_LEVEL = "android:broadcast.maxManifestReceiverApiLevel"; + /** + * Corresponds to {@link #setMaxManifestReceiverApiLevel}. + */ + static final String KEY_DONT_SEND_TO_RESTRICTED_APPS = + "android:broadcast.dontSendToRestrictedApps"; + public static BroadcastOptions makeBasic() { BroadcastOptions opts = new BroadcastOptions(); return opts; @@ -66,6 +73,7 @@ public class BroadcastOptions { mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0); mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL, Build.VERSION_CODES.CUR_DEVELOPMENT); + mDontSendToRestrictedApps = opts.getBoolean(KEY_DONT_SEND_TO_RESTRICTED_APPS, false); } /** @@ -122,6 +130,23 @@ public class BroadcastOptions { return mMaxManifestReceiverApiLevel; } + /** + * Sets whether pending intent can be sent for an application with background restrictions + * @param dontSendToRestrictedApps if true, pending intent will not be sent for an application + * with background restrictions. Default value is {@code false} + */ + public void setDontSendToRestrictedApps(boolean dontSendToRestrictedApps) { + mDontSendToRestrictedApps = dontSendToRestrictedApps; + } + + /** + * @hide + * @return #setDontSendToRestrictedApps + */ + public boolean isDontSendToRestrictedApps() { + return mDontSendToRestrictedApps; + } + /** * Returns the created options as a Bundle, which can be passed to * {@link android.content.Context#sendBroadcast(android.content.Intent) @@ -141,6 +166,9 @@ public class BroadcastOptions { if (mMaxManifestReceiverApiLevel != Build.VERSION_CODES.CUR_DEVELOPMENT) { b.putInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL, mMaxManifestReceiverApiLevel); } + if (mDontSendToRestrictedApps) { + b.putBoolean(KEY_DONT_SEND_TO_RESTRICTED_APPS, true); + } return b.isEmpty() ? null : b; } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5e71be5312503..75bad46a5cfc3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12959,9 +12959,13 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (RemoteException exc) { // Ignore. } + return isBackgroundRestrictedNoCheck(callingUid, packageName); + } + + boolean isBackgroundRestrictedNoCheck(final int uid, final String packageName) { final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, - callingUid, packageName); - return (mode != AppOpsManager.MODE_ALLOWED); + uid, packageName); + return mode != AppOpsManager.MODE_ALLOWED; } @Override @@ -21056,6 +21060,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } + final String action = intent.getAction(); BroadcastOptions brOptions = null; if (bOptions != null) { brOptions = new BroadcastOptions(bOptions); @@ -21076,11 +21081,16 @@ public class ActivityManagerService extends IActivityManager.Stub throw new SecurityException(msg); } } + if (brOptions.isDontSendToRestrictedApps() + && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) { + Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage + + " has background restrictions"); + return ActivityManager.START_CANCELED; + } } // Verify that protected broadcasts are only being sent by system code, // and that system code is only sending protected broadcasts. - final String action = intent.getAction(); final boolean isProtectedBroadcast; try { isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);