From a2a4482c8dc27a4b6f07cb3356129fc47f53548f Mon Sep 17 00:00:00 2001 From: xshu Date: Wed, 1 Dec 2021 18:44:55 -0800 Subject: Configure allowed/excluded permission list with BroadcastOptions Add new BroadcastOptions to allow configuring the allowed permission list and excluded permission list. Bug: 197776854 Test: compile Change-Id: I20bca985eb39e199edbbae99cd54f1472dfaf399 --- core/api/system-current.txt | 2 + core/java/android/app/BroadcastOptions.java | 62 +++++++++++++++++++++++++++++ core/java/android/app/ContextImpl.java | 12 +++++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index a298354af1b3..1fc9729ee67a 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -721,6 +721,8 @@ package android.app { method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean); method public void setDontSendToRestrictedApps(boolean); method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean); + method public void setRequireAllOfPermissions(@Nullable String[]); + method public void setRequireNoneOfPermissions(@Nullable String[]); method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppAllowlist(long, int, int, @Nullable String); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) 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 5b8cc70cc0a8..3108d9178440 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -43,6 +43,8 @@ public class BroadcastOptions extends ComponentOptions { private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; private boolean mDontSendToRestrictedApps = false; private boolean mAllowBackgroundActivityStarts; + private String[] mRequireAllOfPermissions; + private String[] mRequireNoneOfPermissions; /** * How long to temporarily put an app on the power allowlist when executing this broadcast @@ -84,6 +86,20 @@ public class BroadcastOptions extends ComponentOptions { private static final String KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS = "android:broadcast.allowBackgroundActivityStarts"; + /** + * Corresponds to {@link #setRequireAllOfPermissions} + * @hide + */ + public static final String KEY_REQUIRE_ALL_OF_PERMISSIONS = + "android:broadcast.requireAllOfPermissions"; + + /** + * Corresponds to {@link #setRequireNoneOfPermissions} + * @hide + */ + public static final String KEY_REQUIRE_NONE_OF_PERMISSIONS = + "android:broadcast.requireNoneOfPermissions"; + /** * @hide * @deprecated Use {@link android.os.PowerExemptionManager# @@ -132,6 +148,8 @@ public class BroadcastOptions extends ComponentOptions { mDontSendToRestrictedApps = opts.getBoolean(KEY_DONT_SEND_TO_RESTRICTED_APPS, false); mAllowBackgroundActivityStarts = opts.getBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS, false); + mRequireAllOfPermissions = opts.getStringArray(KEY_REQUIRE_ALL_OF_PERMISSIONS); + mRequireNoneOfPermissions = opts.getStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS); } /** @@ -322,6 +340,44 @@ public class BroadcastOptions extends ComponentOptions { return mAllowBackgroundActivityStarts; } + /** + * Use this to configure a broadcast to be sent to apps that hold all permissions in + * the list. This is only for use with the {@link Context#sendBroadcast(Intent intent, + * @Nullable String receiverPermission, @Nullable Bundle options)}. + * + *

If both {@link #setRequireAllOfPermissions(String[])} and + * {@link #setRequireNoneOfPermissions(String[])} are used, then receivers must have all of the + * permissions set by {@link #setRequireAllOfPermissions(String[])}, and none of the + * permissions set by {@link #setRequireNoneOfPermissions(String[])} to get the broadcast. + * + * @param requiredPermissions a list of Strings of permission the receiver must have, or null + * to clear any previously set value. + * @hide + */ + @SystemApi + public void setRequireAllOfPermissions(@Nullable String[] requiredPermissions) { + mRequireAllOfPermissions = requiredPermissions; + } + + /** + * Use this to configure a broadcast to be sent to apps that don't hold any permissions in + * list. This is only for use with the {@link Context#sendBroadcast(Intent intent, + * @Nullable String receiverPermission, @Nullable Bundle options)}. + * + *

If both {@link #setRequireAllOfPermissions(String[])} and + * {@link #setRequireNoneOfPermissions(String[])} are used, then receivers must have all of the + * permissions set by {@link #setRequireAllOfPermissions(String[])}, and none of the + * permissions set by {@link #setRequireNoneOfPermissions(String[])} to get the broadcast. + * + * @param excludedPermissions a list of Strings of permission the receiver must not have, + * or null to clear any previously set value. + * @hide + */ + @SystemApi + public void setRequireNoneOfPermissions(@Nullable String[] excludedPermissions) { + mRequireNoneOfPermissions = excludedPermissions; + } + /** * Returns the created options as a Bundle, which can be passed to * {@link android.content.Context#sendBroadcast(android.content.Intent) @@ -351,6 +407,12 @@ public class BroadcastOptions extends ComponentOptions { if (mAllowBackgroundActivityStarts) { b.putBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS, true); } + if (mRequireAllOfPermissions != null) { + b.putStringArray(KEY_REQUIRE_ALL_OF_PERMISSIONS, mRequireAllOfPermissions); + } + if (mRequireNoneOfPermissions != null) { + b.putStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS, mRequireNoneOfPermissions); + } return b.isEmpty() ? null : b; } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 4a7361efe4cc..60229e118abc 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1272,12 +1272,22 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); String[] receiverPermissions = receiverPermission == null ? null : new String[] {receiverPermission}; + String[] excludedPermissions = null; + if (options != null) { + String[] receiverPermissionsBundle = options.getStringArray( + BroadcastOptions.KEY_REQUIRE_ALL_OF_PERMISSIONS); + if (receiverPermissionsBundle != null) { + receiverPermissions = receiverPermissionsBundle; + } + excludedPermissions = options.getStringArray( + BroadcastOptions.KEY_REQUIRE_NONE_OF_PERMISSIONS); + } try { intent.prepareToLeaveProcess(this); ActivityManager.getService().broadcastIntentWithFeature( mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, - null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false, + excludedPermissions, AppOpsManager.OP_NONE, options, false, false, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); -- cgit v1.2.3-59-g8ed1b