Loading core/java/android/app/ActivityManagerInternal.java +7 −1 Original line number Diff line number Diff line Loading @@ -226,6 +226,12 @@ public abstract class ActivityManagerInternal { */ public abstract boolean isModernQueueEnabled(); /** * Enforce capability restrictions on use of the given BroadcastOptions */ public abstract void enforceBroadcastOptionsPermissions(@Nullable Bundle options, int callingUid); /** * Returns package name given pid. * Loading Loading @@ -300,7 +306,7 @@ public abstract class ActivityManagerInternal { public abstract int handleIncomingUser(int callingPid, int callingUid, @UserIdInt int userId, boolean allowAll, int allowMode, String name, String callerPackage); /** Checks if the calling binder pid as the permission. */ /** Checks if the calling binder pid/uid has the given permission. */ @PermissionMethod public abstract void enforceCallingPermission(@PermissionName String permission, String func); Loading core/java/android/app/BroadcastOptions.java +1 −0 Original line number Diff line number Diff line Loading @@ -636,6 +636,7 @@ public class BroadcastOptions extends ComponentOptions { * @param broadcastIsInteractive * @see #isInteractiveBroadcast() */ @RequiresPermission(android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE) public void setInteractiveBroadcast(boolean broadcastIsInteractive) { mIsInteractiveBroadcast = broadcastIsInteractive; } Loading core/res/AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -3152,6 +3152,12 @@ <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/> <!-- Allows an application to hint that a broadcast is associated with an "interactive" usage scenario @hide --> <permission android:name="android.permission.BROADCAST_OPTION_INTERACTIVE" android:protectionLevel="signature|privileged" /> <!-- @SystemApi Must be required by activities that handle the intent action {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system. Loading core/tests/coretests/src/android/app/activity/BroadcastTest.java +38 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package android.app.activity; import android.app.Activity; import android.app.ActivityManager; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; Loading Loading @@ -536,4 +538,40 @@ public class BroadcastTest extends ActivityTestsBase { Log.i("foo", "Unregister exception", e); } } public void testBroadcastOption_interactive() throws Exception { final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractiveBroadcast(true); final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED); try { getContext().sendBroadcast(intent, null, options.toBundle()); fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } catch (SecurityException se) { // Expected, correct behavior - this case intentionally empty } catch (Exception e) { fail("Unexpected exception " + e.getMessage() + " thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } } public void testBroadcastOption_interactive_PendingIntent() throws Exception { final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractiveBroadcast(true); final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED); PendingIntent brPending = PendingIntent.getBroadcast(getContext(), 1, intent, PendingIntent.FLAG_IMMUTABLE); try { brPending.send(getContext(), 1, null, null, null, null, options.toBundle()); fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } catch (SecurityException se) { // Expected, correct behavior - this case intentionally empty } catch (Exception e) { fail("Unexpected exception " + e.getMessage() + " thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } finally { brPending.cancel(); } } } services/core/java/com/android/server/am/ActivityManagerService.java +26 −13 Original line number Diff line number Diff line Loading @@ -13828,6 +13828,25 @@ public class ActivityManagerService extends IActivityManager.Stub } } // Apply permission policy around the use of specific broadcast options void enforceBroadcastOptionPermissionsInternal(@Nullable Bundle options, int callingUid) { if (options != null && callingUid != Process.SYSTEM_UID) { if (options.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST)) { if (DEBUG_BROADCAST_LIGHT) { Slog.w(TAG, "Non-system caller " + callingUid + " may not flag broadcast as alarm"); } throw new SecurityException( "Non-system callers may not flag broadcasts as alarm"); } if (options.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) { enforceCallingPermission( android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE, "setInteractiveBroadcast"); } } } @GuardedBy("this") final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, String callerFeatureId, Intent intent, String resolvedType, Loading Loading @@ -14695,19 +14714,8 @@ public class ActivityManagerService extends IActivityManager.Stub // We're delivering the result to the caller final ProcessRecord resultToApp = callerApp; // Non-system callers can't declare that a broadcast is alarm-related. // The PendingIntent invocation case is handled in PendingIntentRecord. if (bOptions != null && callingUid != SYSTEM_UID) { if (bOptions.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST) || bOptions.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) { if (DEBUG_BROADCAST) { Slog.w(TAG, "Non-system caller " + callingUid + " may not flag broadcast as alarm or interactive"); } throw new SecurityException( "Non-system callers may not flag broadcasts as alarm or interactive"); } } // Permission regimes around sender-supplied broadcast options. enforceBroadcastOptionPermissionsInternal(bOptions, callingUid); final long origId = Binder.clearCallingIdentity(); try { Loading Loading @@ -16901,6 +16909,11 @@ public class ActivityManagerService extends IActivityManager.Stub return mEnableModernQueue; } @Override public void enforceBroadcastOptionsPermissions(Bundle options, int callingUid) { enforceBroadcastOptionPermissionsInternal(options, callingUid); } /** * Returns package name by pid. */ Loading
core/java/android/app/ActivityManagerInternal.java +7 −1 Original line number Diff line number Diff line Loading @@ -226,6 +226,12 @@ public abstract class ActivityManagerInternal { */ public abstract boolean isModernQueueEnabled(); /** * Enforce capability restrictions on use of the given BroadcastOptions */ public abstract void enforceBroadcastOptionsPermissions(@Nullable Bundle options, int callingUid); /** * Returns package name given pid. * Loading Loading @@ -300,7 +306,7 @@ public abstract class ActivityManagerInternal { public abstract int handleIncomingUser(int callingPid, int callingUid, @UserIdInt int userId, boolean allowAll, int allowMode, String name, String callerPackage); /** Checks if the calling binder pid as the permission. */ /** Checks if the calling binder pid/uid has the given permission. */ @PermissionMethod public abstract void enforceCallingPermission(@PermissionName String permission, String func); Loading
core/java/android/app/BroadcastOptions.java +1 −0 Original line number Diff line number Diff line Loading @@ -636,6 +636,7 @@ public class BroadcastOptions extends ComponentOptions { * @param broadcastIsInteractive * @see #isInteractiveBroadcast() */ @RequiresPermission(android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE) public void setInteractiveBroadcast(boolean broadcastIsInteractive) { mIsInteractiveBroadcast = broadcastIsInteractive; } Loading
core/res/AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -3152,6 +3152,12 @@ <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/> <!-- Allows an application to hint that a broadcast is associated with an "interactive" usage scenario @hide --> <permission android:name="android.permission.BROADCAST_OPTION_INTERACTIVE" android:protectionLevel="signature|privileged" /> <!-- @SystemApi Must be required by activities that handle the intent action {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system. Loading
core/tests/coretests/src/android/app/activity/BroadcastTest.java +38 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package android.app.activity; import android.app.Activity; import android.app.ActivityManager; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; Loading Loading @@ -536,4 +538,40 @@ public class BroadcastTest extends ActivityTestsBase { Log.i("foo", "Unregister exception", e); } } public void testBroadcastOption_interactive() throws Exception { final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractiveBroadcast(true); final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED); try { getContext().sendBroadcast(intent, null, options.toBundle()); fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } catch (SecurityException se) { // Expected, correct behavior - this case intentionally empty } catch (Exception e) { fail("Unexpected exception " + e.getMessage() + " thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } } public void testBroadcastOption_interactive_PendingIntent() throws Exception { final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractiveBroadcast(true); final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED); PendingIntent brPending = PendingIntent.getBroadcast(getContext(), 1, intent, PendingIntent.FLAG_IMMUTABLE); try { brPending.send(getContext(), 1, null, null, null, null, options.toBundle()); fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } catch (SecurityException se) { // Expected, correct behavior - this case intentionally empty } catch (Exception e) { fail("Unexpected exception " + e.getMessage() + " thrown with BroadcastOptions.setInteractiveBroadcast(true)"); } finally { brPending.cancel(); } } }
services/core/java/com/android/server/am/ActivityManagerService.java +26 −13 Original line number Diff line number Diff line Loading @@ -13828,6 +13828,25 @@ public class ActivityManagerService extends IActivityManager.Stub } } // Apply permission policy around the use of specific broadcast options void enforceBroadcastOptionPermissionsInternal(@Nullable Bundle options, int callingUid) { if (options != null && callingUid != Process.SYSTEM_UID) { if (options.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST)) { if (DEBUG_BROADCAST_LIGHT) { Slog.w(TAG, "Non-system caller " + callingUid + " may not flag broadcast as alarm"); } throw new SecurityException( "Non-system callers may not flag broadcasts as alarm"); } if (options.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) { enforceCallingPermission( android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE, "setInteractiveBroadcast"); } } } @GuardedBy("this") final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, String callerFeatureId, Intent intent, String resolvedType, Loading Loading @@ -14695,19 +14714,8 @@ public class ActivityManagerService extends IActivityManager.Stub // We're delivering the result to the caller final ProcessRecord resultToApp = callerApp; // Non-system callers can't declare that a broadcast is alarm-related. // The PendingIntent invocation case is handled in PendingIntentRecord. if (bOptions != null && callingUid != SYSTEM_UID) { if (bOptions.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST) || bOptions.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) { if (DEBUG_BROADCAST) { Slog.w(TAG, "Non-system caller " + callingUid + " may not flag broadcast as alarm or interactive"); } throw new SecurityException( "Non-system callers may not flag broadcasts as alarm or interactive"); } } // Permission regimes around sender-supplied broadcast options. enforceBroadcastOptionPermissionsInternal(bOptions, callingUid); final long origId = Binder.clearCallingIdentity(); try { Loading Loading @@ -16901,6 +16909,11 @@ public class ActivityManagerService extends IActivityManager.Stub return mEnableModernQueue; } @Override public void enforceBroadcastOptionsPermissions(Bundle options, int callingUid) { enforceBroadcastOptionPermissionsInternal(options, callingUid); } /** * Returns package name by pid. */