diff options
21 files changed, 343 insertions, 81 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index bca9913ff94e..b0d5e06982dd 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -5204,6 +5204,13 @@ package android.app { field @NonNull public static final android.os.Parcelable.Creator<android.app.BackgroundServiceStartNotAllowedException> CREATOR; } + public class BroadcastOptions { + method public boolean isShareIdentityEnabled(); + method @NonNull public static android.app.BroadcastOptions makeBasic(); + method @NonNull public android.app.BroadcastOptions setShareIdentityEnabled(boolean); + method @NonNull public android.os.Bundle toBundle(); + } + public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener { ctor public DatePickerDialog(@NonNull android.content.Context); ctor public DatePickerDialog(@NonNull android.content.Context, @StyleRes int); @@ -9567,6 +9574,8 @@ package android.content { method public final int getResultCode(); method public final String getResultData(); method public final android.os.Bundle getResultExtras(boolean); + method @Nullable public String getSentFromPackage(); + method public int getSentFromUid(); method public final android.content.BroadcastReceiver.PendingResult goAsync(); method public final boolean isInitialStickyBroadcast(); method public final boolean isOrderedBroadcast(); @@ -10167,11 +10176,14 @@ package android.content { method public abstract void revokeUriPermission(String, android.net.Uri, int); method public abstract void sendBroadcast(@RequiresPermission android.content.Intent); method public abstract void sendBroadcast(@RequiresPermission android.content.Intent, @Nullable String); + method public void sendBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle); method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle); method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String); method public void sendBroadcastWithMultiplePermissions(@NonNull android.content.Intent, @NonNull String[]); method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String); + method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle); method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); + method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index c098adb7ea5d..9c7d2205f055 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -817,7 +817,6 @@ package android.app { method public int getPendingIntentBackgroundActivityStartMode(); method public boolean isDeferUntilActive(); method @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed(); - method public static android.app.BroadcastOptions makeBasic(); method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public void recordResponseEventWhileInBackground(@IntRange(from=0) long); method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean); method @NonNull public android.app.BroadcastOptions setDeferUntilActive(boolean); @@ -832,7 +831,6 @@ package android.app { 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(); field public static final int DELIVERY_GROUP_POLICY_ALL = 0; // 0x0 field public static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1; // 0x1 } @@ -3232,10 +3230,8 @@ package android.content { method public abstract boolean isCredentialProtectedStorage(); method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler); method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int); - method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle); method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions); - method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle); field public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context"; @@ -3298,9 +3294,7 @@ package android.content { method public android.content.Context createCredentialProtectedStorageContext(); method @Nullable public java.io.File getPreloadsFileCache(); method public boolean isCredentialProtectedStorage(); - method public void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle); - method public void sendOrderedBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); } public class Intent implements java.lang.Cloneable android.os.Parcelable { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 5f2f62368376..219f5f41d99b 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -165,7 +165,7 @@ package android.app { method @Nullable public String getIconResourcePackage(); } - public class ActivityOptions { + public class ActivityOptions extends android.app.ComponentOptions { method public boolean isEligibleForLegacyPermissionPrompt(); method @NonNull public static android.app.ActivityOptions makeCustomAnimation(@NonNull android.content.Context, int, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method @NonNull @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) public static android.app.ActivityOptions makeCustomTaskAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); @@ -269,7 +269,7 @@ package android.app { method public default void onOpActiveChanged(@NonNull String, int, @NonNull String, @Nullable String, boolean, int, int); } - public class BroadcastOptions { + public class BroadcastOptions extends android.app.ComponentOptions { ctor public BroadcastOptions(@NonNull android.os.Bundle); method @Deprecated public int getMaxManifestReceiverApiLevel(); method public long getTemporaryAppAllowlistDuration(); @@ -282,6 +282,12 @@ package android.app { field public static final long CHANGE_ALWAYS_ENABLED = 209888056L; // 0xc82a338L } + public class ComponentOptions { + field public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; // 0x1 + field public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; // 0x2 + field public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; // 0x0 + } + public class DownloadManager { field public static final String COLUMN_MEDIASTORE_URI = "mediastore_uri"; } diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 2a390a7dbb51..b57fb2088adc 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -88,6 +88,16 @@ public class ActivityOptions extends ComponentOptions { */ public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages"; + /** No explicit value chosen. The system will decide whether to grant privileges. */ + public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = + ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; + /** Allow the {@link PendingIntent} to use the background activity start privileges. */ + public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = + ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; + /** Deny the {@link PendingIntent} to use the background activity start privileges. */ + public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = + ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; + /** * The package name that created the options. * @hide @@ -2430,6 +2440,30 @@ public class ActivityOptions extends ComponentOptions { return super.getPendingIntentBackgroundActivityStartMode(); } + /** + * Set PendingIntent activity is allowed to be started in the background if the caller + * can start background activities. + * + * @deprecated use #setPendingIntentBackgroundActivityStartMode(int) to set the full range + * of states + */ + @Override + @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { + super.setPendingIntentBackgroundActivityLaunchAllowed(allowed); + } + + /** + * Get PendingIntent activity is allowed to be started in the background if the caller can start + * background activities. + * + * @deprecated use {@link #getPendingIntentBackgroundActivityStartMode()} since for apps + * targeting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or higher this value might + * not match the actual behavior if the value was not explicitly set. + */ + @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed() { + return super.isPendingIntentBackgroundActivityLaunchAllowed(); + } + /** @hide */ @Override public String toString() { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3761251b6cec..170c0b4e0bb1 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -785,9 +785,10 @@ public final class ActivityThread extends ClientTransactionHandler static final class ReceiverData extends BroadcastReceiver.PendingResult { public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, boolean assumeDelivered, IBinder token, - int sendingUser) { + int sendingUser, int sentFromUid, String sentFromPackage) { super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, - assumeDelivered, token, sendingUser, intent.getFlags()); + assumeDelivered, token, sendingUser, intent.getFlags(), sentFromUid, + sentFromPackage); this.intent = intent; } @@ -801,7 +802,8 @@ public final class ActivityThread extends ClientTransactionHandler return "ReceiverData{intent=" + intent + " packageName=" + info.packageName + " resultCode=" + getResultCode() + " resultData=" + getResultData() + " resultExtras=" - + getResultExtras(false) + "}"; + + getResultExtras(false) + " sentFromUid=" + + getSentFromUid() + " sentFromPackage=" + getSentFromPackage() + "}"; } } @@ -1041,10 +1043,12 @@ public final class ActivityThread extends ClientTransactionHandler public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, - boolean ordered, boolean assumeDelivered, int sendingUser, int processState) { + boolean ordered, boolean assumeDelivered, int sendingUser, int processState, + int sentFromUid, String sentFromPackage) { updateProcessState(processState, false); ReceiverData r = new ReceiverData(intent, resultCode, data, extras, - ordered, false, assumeDelivered, mAppThread.asBinder(), sendingUser); + ordered, false, assumeDelivered, mAppThread.asBinder(), sendingUser, + sentFromUid, sentFromPackage); r.info = info; sendMessage(H.RECEIVER, r); } @@ -1055,11 +1059,13 @@ public final class ActivityThread extends ClientTransactionHandler if (r.registered) { scheduleRegisteredReceiver(r.receiver, r.intent, r.resultCode, r.data, r.extras, r.ordered, r.sticky, - r.assumeDelivered, r.sendingUser, r.processState); + r.assumeDelivered, r.sendingUser, r.processState, + r.sentFromUid, r.sentFromPackage); } else { scheduleReceiver(r.intent, r.activityInfo, r.compatInfo, r.resultCode, r.data, r.extras, r.sync, - r.assumeDelivered, r.sendingUser, r.processState); + r.assumeDelivered, r.sendingUser, r.processState, + r.sentFromUid, r.sentFromPackage); } } } @@ -1289,7 +1295,8 @@ public final class ActivityThread extends ClientTransactionHandler // applies transaction ordering per object for such calls. public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, - boolean sticky, boolean assumeDelivered, int sendingUser, int processState) + boolean sticky, boolean assumeDelivered, int sendingUser, int processState, + int sentFromUid, String sentFromPackage) throws RemoteException { updateProcessState(processState, false); @@ -1299,12 +1306,19 @@ public final class ActivityThread extends ClientTransactionHandler // report an expected delivery event if (receiver instanceof LoadedApk.ReceiverDispatcher.InnerReceiver) { ((LoadedApk.ReceiverDispatcher.InnerReceiver) receiver).performReceive(intent, - resultCode, dataStr, extras, ordered, sticky, assumeDelivered, sendingUser); + resultCode, dataStr, extras, ordered, sticky, assumeDelivered, sendingUser, + sentFromUid, sentFromPackage); } else { if (!assumeDelivered) { Log.wtf(TAG, "scheduleRegisteredReceiver() called for " + receiver + " and " + intent + " without mechanism to finish delivery"); } + if (sentFromUid != Process.INVALID_UID || sentFromPackage != null) { + Log.wtf(TAG, + "scheduleRegisteredReceiver() called for " + receiver + " and " + intent + + " from " + sentFromPackage + " (UID: " + sentFromUid + + ") without mechanism to propagate the sender's identity"); + } receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky, sendingUser); } diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index 88765c3b35e2..f6992c954a3c 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -27,6 +27,7 @@ import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; import android.compat.annotation.EnabledSince; +import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; import android.os.Build; @@ -46,9 +47,7 @@ import java.util.Objects; * Helper class for building an options Bundle that can be used with * {@link android.content.Context#sendBroadcast(android.content.Intent) * Context.sendBroadcast(Intent)} and related methods. - * {@hide} */ -@SystemApi public class BroadcastOptions extends ComponentOptions { private long mTemporaryAppAllowlistDuration; private @TempAllowListType int mTemporaryAppAllowlistType; @@ -64,6 +63,7 @@ public class BroadcastOptions extends ComponentOptions { private boolean mRequireCompatChangeEnabled = true; private boolean mIsAlarmBroadcast = false; private boolean mIsDeferUntilActive = false; + private boolean mShareIdentity = false; private long mIdForResponseEvent; private @Nullable IntentFilter mRemoveMatchingFilter; private @DeliveryGroupPolicy int mDeliveryGroupPolicy; @@ -172,6 +172,12 @@ public class BroadcastOptions extends ComponentOptions { "android:broadcast.is_alarm"; /** + * Whether the broadcasting app's identity should be available to the receiver. + * @see #setShareIdentityEnabled(boolean) + */ + private static final String KEY_SHARE_IDENTITY = "android:broadcast.share_identity"; + + /** * @hide * @deprecated Use {@link android.os.PowerExemptionManager# * TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED} instead. @@ -270,7 +276,12 @@ public class BroadcastOptions extends ComponentOptions { */ public static final int DELIVERY_GROUP_POLICY_MERGED = 2; - public static BroadcastOptions makeBasic() { + /** + * Creates a basic {@link BroadcastOptions} with no options initially set. + * + * @return an instance of {@code BroadcastOptions} against which options can be set + */ + public static @NonNull BroadcastOptions makeBasic() { BroadcastOptions opts = new BroadcastOptions(); return opts; } @@ -318,6 +329,7 @@ public class BroadcastOptions extends ComponentOptions { mRequireCompatChangeEnabled = opts.getBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, true); mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT); mIsAlarmBroadcast = opts.getBoolean(KEY_ALARM_BROADCAST, false); + mShareIdentity = opts.getBoolean(KEY_SHARE_IDENTITY, false); mRemoveMatchingFilter = opts.getParcelable(KEY_REMOVE_MATCHING_FILTER, IntentFilter.class); mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY, @@ -335,8 +347,10 @@ public class BroadcastOptions extends ComponentOptions { * power allowlist when this broadcast is being delivered to it. * @param duration The duration in milliseconds; 0 means to not place on allowlist. * @deprecated use {@link #setTemporaryAppAllowlist(long, int, int, String)} instead. + * @hide */ @Deprecated + @SystemApi @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}) @@ -350,6 +364,8 @@ public class BroadcastOptions extends ComponentOptions { * Set a duration for which the system should temporary place an application on the * power allowlist when this broadcast is being delivered to it, specify the temp allowlist * type. + * @hide + * * @param duration the duration in milliseconds. * 0 means to not place on allowlist, and clears previous call to this method. * @param type one of {@link TempAllowListType}. @@ -360,6 +376,7 @@ public class BroadcastOptions extends ComponentOptions { * @param reason A human-readable reason explaining why the app is temp allowlisted. Only * used for logging purposes. Could be null or empty string. */ + @SystemApi @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}) @@ -500,7 +517,9 @@ public class BroadcastOptions extends ComponentOptions { * 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} + * @hide */ + @SystemApi public void setDontSendToRestrictedApps(boolean dontSendToRestrictedApps) { mDontSendToRestrictedApps = dontSendToRestrictedApps; } @@ -516,7 +535,9 @@ public class BroadcastOptions extends ComponentOptions { /** * Sets the process will be able to start activities from background for the duration of * the broadcast dispatch. Default value is {@code false} + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean allowBackgroundActivityStarts) { mAllowBackgroundActivityStarts = allowBackgroundActivityStarts; @@ -578,6 +599,7 @@ public class BroadcastOptions extends ComponentOptions { * <p> * This requirement applies to both manifest registered and runtime * registered receivers. + * @hide * * @param changeId the {@link ChangeId} to inspect * @param enabled the required enabled state of the inspected @@ -585,6 +607,7 @@ public class BroadcastOptions extends ComponentOptions { * @see CompatChanges#isChangeEnabled * @see #clearRequireCompatChange() */ + @SystemApi public void setRequireCompatChange(long changeId, boolean enabled) { mRequireCompatChangeId = changeId; mRequireCompatChangeEnabled = enabled; @@ -593,7 +616,9 @@ public class BroadcastOptions extends ComponentOptions { /** * Clear any previously defined requirement for this broadcast requested via * {@link #setRequireCompatChange(long, boolean)}. + * @hide */ + @SystemApi public void clearRequireCompatChange() { mRequireCompatChangeId = CHANGE_INVALID; mRequireCompatChangeEnabled = true; @@ -621,6 +646,39 @@ public class BroadcastOptions extends ComponentOptions { } /** + * Sets whether the identity of the broadcasting app should be shared with all receivers + * that will receive this broadcast. + * + * <p>Use this option when broadcasting to a receiver that needs to know the identity of the + * broadcaster; with this set to {@code true}, the receiver will have access to the broadcasting + * app's package name and uid. + * + * <p>Defaults to {@code false} if not set. + * + * @param shareIdentityEnabled whether the broadcasting app's identity should be shared with the + * receiver + * @return {@code this} {@link BroadcastOptions} instance + * @see BroadcastReceiver#getSentFromUid() + * @see BroadcastReceiver#getSentFromPackage() + */ + public @NonNull BroadcastOptions setShareIdentityEnabled(boolean shareIdentityEnabled) { + mShareIdentity = shareIdentityEnabled; + return this; + } + + /** + * Returns whether the broadcasting app has opted-in to sharing its identity with the receiver. + * + * @return {@code true} if the broadcasting app has opted in to sharing its identity + * @see #setShareIdentityEnabled(boolean) + * @see BroadcastReceiver#getSentFromUid() + * @see BroadcastReceiver#getSentFromPackage() + */ + public boolean isShareIdentityEnabled() { + return mShareIdentity; + } + + /** * Did this broadcast originate from a push message from the server? * * @return true if this broadcast is a push message, false otherwise. @@ -989,7 +1047,7 @@ public class BroadcastOptions extends ComponentOptions { * extras merger is supplied. */ @Override - public Bundle toBundle() { + public @NonNull Bundle toBundle() { Bundle b = super.toBundle(); if (isTemporaryAppAllowlistSet()) { b.putLong(KEY_TEMPORARY_APP_ALLOWLIST_DURATION, mTemporaryAppAllowlistDuration); @@ -1000,6 +1058,9 @@ public class BroadcastOptions extends ComponentOptions { if (mIsAlarmBroadcast) { b.putBoolean(KEY_ALARM_BROADCAST, true); } + if (mShareIdentity) { + b.putBoolean(KEY_SHARE_IDENTITY, true); + } if (mMinManifestReceiverApiLevel != 0) { b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel); } diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java index 3776369caf2e..9c262b9bea99 100644 --- a/core/java/android/app/ComponentOptions.java +++ b/core/java/android/app/ComponentOptions.java @@ -20,6 +20,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; +import android.annotation.TestApi; import android.os.Bundle; import java.lang.annotation.Retention; @@ -29,6 +31,10 @@ import java.lang.annotation.RetentionPolicy; * Base class for {@link ActivityOptions} and {@link BroadcastOptions}. * @hide */ +// Expose the methods and constants required to test the SystemApis in subclasses. +@TestApi +// Suppressed since lint is recommending class have a suffix of Params. +@SuppressLint("UserHandleName") public class ComponentOptions { /** @@ -57,17 +63,30 @@ public class ComponentOptions { private boolean mPendingIntentBalAllowedByPermission = false; private boolean mIsInteractive = false; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"MODE_BACKGROUND_ACTIVITY_START_"}, value = { MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED, MODE_BACKGROUND_ACTIVITY_START_ALLOWED, MODE_BACKGROUND_ACTIVITY_START_DENIED}) public @interface BackgroundActivityStartMode {} - /** No explicit value chosen. The system will decide whether to grant privileges. */ + /** + * No explicit value chosen. The system will decide whether to grant privileges. + * @hide + */ + @TestApi public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; - /** Allow the {@link PendingIntent} to use the background activity start privileges. */ + /** + * Allow the {@link PendingIntent} to use the background activity start privileges. + * @hide + */ + @TestApi public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; - /** Deny the {@link PendingIntent} to use the background activity start privileges. */ + /** + * Deny the {@link PendingIntent} to use the background activity start privileges. + * @hide + */ + @TestApi public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; ComponentOptions() { @@ -118,6 +137,7 @@ public class ComponentOptions { * * @deprecated use #setPendingIntentBackgroundActivityStartMode(int) to set the full range * of states + * @hide */ @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { mPendingIntentBalAllowed = allowed; @@ -130,6 +150,7 @@ public class ComponentOptions { * @deprecated use {@link #getPendingIntentBackgroundActivityStartMode()} since for apps * targeting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or higher this value might * not match the actual behavior if the value was not explicitly set. + * @hide */ @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed() { if (mPendingIntentBalAllowed == null) { @@ -147,6 +168,7 @@ public class ComponentOptions { * methods. A privileged sender of a PendingIntent should only grant * {@link #MODE_BACKGROUND_ACTIVITY_START_ALLOWED} if the PendingIntent is from a trusted source * and/or executed on behalf the user. + * @hide */ public @NonNull ComponentOptions setPendingIntentBackgroundActivityStartMode( @BackgroundActivityStartMode int state) { @@ -169,6 +191,7 @@ public class ComponentOptions { /** * Gets the mode for allowing or denying the senders privileges to start background activities * to the PendingIntent. + * @hide * * @see #setPendingIntentBackgroundActivityStartMode(int) */ @@ -199,6 +222,7 @@ public class ComponentOptions { return mPendingIntentBalAllowedByPermission; } + /** @hide */ public Bundle toBundle() { Bundle b = new Bundle(); if (mPendingIntentBalAllowed != null) { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 12899f2daf87..bed75db39f85 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -25,6 +25,7 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.UiContext; import android.companion.virtual.VirtualDeviceManager; import android.compat.annotation.UnsupportedAppUsage; @@ -1358,7 +1359,13 @@ class ContextImpl extends Context { } @Override + @SuppressLint("AndroidFrameworkRequiresPermission") public void sendOrderedBroadcast(Intent intent, String receiverPermission) { + sendOrderedBroadcast(intent, receiverPermission, /*options=*/ null); + } + + @Override + public void sendOrderedBroadcast(Intent intent, String receiverPermission, Bundle options) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); String[] receiverPermissions = receiverPermission == null ? null @@ -1368,8 +1375,8 @@ class ContextImpl extends Context { ActivityManager.getService().broadcastIntentWithFeature( mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, - null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, false, - getUserId()); + null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, options, true, + false, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 4f69d85fdbdb..dad9b435e9e7 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -66,7 +66,8 @@ oneway interface IApplicationThread { void scheduleReceiver(in Intent intent, in ActivityInfo info, in CompatibilityInfo compatInfo, int resultCode, in String data, in Bundle extras, boolean ordered, - boolean assumeDelivered, int sendingUser, int processState); + boolean assumeDelivered, int sendingUser, int processState, int sentFromUid, + in String sentFromPackage); void scheduleReceiverList(in List<ReceiverInfo> info); @@ -102,7 +103,8 @@ oneway interface IApplicationThread { in String[] args); void scheduleRegisteredReceiver(IIntentReceiver receiver, in Intent intent, int resultCode, in String data, in Bundle extras, boolean ordered, - boolean sticky, boolean assumeDelivered, int sendingUser, int processState); + boolean sticky, boolean assumeDelivered, int sendingUser, int processState, + int sentFromUid, in String sentFromPackage); void scheduleLowMemory(); void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType); void setSchedulingGroup(int group); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 7c22902a25a6..c13da0b07981 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -1683,12 +1683,13 @@ public final class LoadedApk { performReceive(intent, resultCode, data, extras, ordered, sticky, BroadcastReceiver.PendingResult.guessAssumeDelivered( BroadcastReceiver.PendingResult.TYPE_REGISTERED, ordered), - sendingUser); + sendingUser, /*sentFromUid=*/ Process.INVALID_UID, + /*sentFromPackage=*/ null); } public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered, - int sendingUser) { + int sendingUser, int sentFromUid, String sentFromPackage) { final LoadedApk.ReceiverDispatcher rd; if (intent == null) { Log.wtf(TAG, "Null intent received"); @@ -1703,7 +1704,8 @@ public final class LoadedApk { } if (rd != null) { rd.performReceive(intent, resultCode, data, extras, - ordered, sticky, assumeDelivered, sendingUser); + ordered, sticky, assumeDelivered, sendingUser, + sentFromUid, sentFromPackage); } else if (!assumeDelivered) { // The activity manager dispatched a broadcast to a registered // receiver in this process, but before it could be delivered the @@ -1743,11 +1745,12 @@ public final class LoadedApk { private boolean mRunCalled; public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, - boolean ordered, boolean sticky, boolean assumeDelivered, int sendingUser) { + boolean ordered, boolean sticky, boolean assumeDelivered, int sendingUser, + int sentFromUid, String sentFromPackage) { super(resultCode, resultData, resultExtras, mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered, sticky, assumeDelivered, mAppThread.asBinder(), sendingUser, - intent.getFlags()); + intent.getFlags(), sentFromUid, sentFromPackage); mCurIntent = intent; } @@ -1871,9 +1874,9 @@ public final class LoadedApk { public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered, - int sendingUser) { + int sendingUser, int sentFromUid, String sentFromPackage) { final Args args = new Args(intent, resultCode, data, extras, ordered, - sticky, assumeDelivered, sendingUser); + sticky, assumeDelivered, sendingUser, sentFromUid, sentFromPackage); if (intent == null) { Log.wtf(TAG, "Null intent received"); } else { diff --git a/core/java/android/app/ReceiverInfo.aidl b/core/java/android/app/ReceiverInfo.aidl index 8d7e3c4bcaae..7364d0f90e92 100644 --- a/core/java/android/app/ReceiverInfo.aidl +++ b/core/java/android/app/ReceiverInfo.aidl @@ -38,6 +38,8 @@ parcelable ReceiverInfo { int sendingUser; int processState; int resultCode; + int sentFromUid = -1; + String sentFromPackage; /** * True if this instance represents a registered receiver and false if this instance diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 64dcc4d1687d..3d76b28a3ccc 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -17,6 +17,7 @@ package android.content; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.ActivityManager; import android.app.ActivityThread; @@ -26,6 +27,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.IBinder; +import android.os.Process; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; @@ -101,19 +103,22 @@ public abstract class BroadcastReceiver { @UnsupportedAppUsage boolean mFinished; String mReceiverClassName; + final int mSentFromUid; + final String mSentFromPackage; /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type, boolean ordered, boolean sticky, IBinder token, int userId, int flags) { this(resultCode, resultData, resultExtras, type, ordered, sticky, - guessAssumeDelivered(type, ordered), token, userId, flags); + guessAssumeDelivered(type, ordered), token, userId, flags, + Process.INVALID_UID, null); } /** @hide */ public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type, boolean ordered, boolean sticky, boolean assumeDelivered, IBinder token, - int userId, int flags) { + int userId, int flags, int sentFromUid, String sentFromPackage) { mResultCode = resultCode; mResultData = resultData; mResultExtras = resultExtras; @@ -124,6 +129,8 @@ public abstract class BroadcastReceiver { mToken = token; mSendingUser = userId; mFlags = flags; + mSentFromUid = sentFromUid; + mSentFromPackage = sentFromPackage; } /** @hide */ @@ -322,6 +329,16 @@ public abstract class BroadcastReceiver { return mSendingUser; } + /** @hide */ + public int getSentFromUid() { + return mSentFromUid; + } + + /** @hide */ + public String getSentFromPackage() { + return mSentFromPackage; + } + void checkSynchronousHint() { // Note that we don't assert when receiving the initial sticky value, // since that may have come from an ordered broadcast. We'll catch @@ -687,6 +704,26 @@ public abstract class BroadcastReceiver { } /** + * Returns the uid of the app that initially sent this broadcast. + * + * @return the uid of the broadcasting app or {@link Process#INVALID_UID} if the current + * receiver cannot access the identity of the broadcasting app + */ + public int getSentFromUid() { + return mPendingResult != null ? mPendingResult.mSentFromUid : Process.INVALID_UID; + } + + /** + * Returns the package name of the app that initially sent this broadcast. + * + * @return the package name of the broadcasting app or {@code null} if the current + * receiver cannot access the identity of the broadcasting app + */ + public @Nullable String getSentFromPackage() { + return mPendingResult != null ? mPendingResult.mSentFromPackage : null; + } + + /** * Control inclusion of debugging help for mismatched * calls to {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver()}. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5f1502fdcd63..ac2eae4196c1 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2445,13 +2445,12 @@ public abstract class Context { * @see #sendBroadcast(Intent) * @see #sendOrderedBroadcast(Intent, String) * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) - * @hide */ - @SuppressWarnings("HiddenAbstractMethod") - @SystemApi - public abstract void sendBroadcast(Intent intent, + public void sendBroadcast(@NonNull Intent intent, @Nullable String receiverPermission, - @Nullable Bundle options); + @Nullable Bundle options) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } /** * Like {@link #sendBroadcast(Intent, String)}, but also allows specification @@ -2487,6 +2486,32 @@ public abstract class Context { @Nullable String receiverPermission); /** + * Broadcast the given intent to all interested BroadcastReceivers, delivering + * them one at a time to allow more preferred receivers to consume the + * broadcast before it is delivered to less preferred receivers. This + * call is asynchronous; it returns immediately, and you will continue + * executing while the receivers are run. + * + * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param receiverPermission (optional) String naming a permissions that + * a receiver must hold in order to receive your broadcast. + * If null, no permission is required. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see #sendBroadcast(Intent) + * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) + */ + public void sendOrderedBroadcast(@NonNull Intent intent, @Nullable String receiverPermission, + @Nullable Bundle options) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * Version of {@link #sendBroadcast(Intent)} that allows you to * receive data back from the broadcast. This is accomplished by * supplying your own BroadcastReceiver when calling, which will be @@ -2572,14 +2597,13 @@ public abstract class Context { * @see android.content.BroadcastReceiver * @see #registerReceiver * @see android.app.Activity#RESULT_OK - * @hide */ - @SuppressWarnings("HiddenAbstractMethod") - @SystemApi - public abstract void sendOrderedBroadcast(@NonNull Intent intent, + public void sendOrderedBroadcast(@NonNull Intent intent, @Nullable String receiverPermission, @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, - int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras); + int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } /** * Like {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 9027e2e3bfe8..a10312817b2c 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -20,6 +20,7 @@ import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UiContext; @@ -537,10 +538,8 @@ public class ContextWrapper extends Context { mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions); } - /** @hide */ - @SystemApi @Override - public void sendBroadcast(Intent intent, @Nullable String receiverPermission, + public void sendBroadcast(@NonNull Intent intent, @Nullable String receiverPermission, @Nullable Bundle options) { mBase.sendBroadcast(intent, receiverPermission, options); } @@ -557,6 +556,14 @@ public class ContextWrapper extends Context { mBase.sendOrderedBroadcast(intent, receiverPermission); } + @SuppressLint("AndroidFrameworkRequiresPermission") + @Override + public void sendOrderedBroadcast(@NonNull Intent intent, + @Nullable String receiverPermission, + @Nullable Bundle options) { + mBase.sendOrderedBroadcast(intent, receiverPermission, options); + } + @Override public void sendOrderedBroadcast( Intent intent, @Nullable String receiverPermission, @@ -567,11 +574,9 @@ public class ContextWrapper extends Context { initialData, initialExtras); } - /** @hide */ - @SystemApi @Override public void sendOrderedBroadcast( - Intent intent, @Nullable String receiverPermission, @Nullable Bundle options, + @NonNull Intent intent, @Nullable String receiverPermission, @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { mBase.sendOrderedBroadcast(intent, receiverPermission, diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java index b1a01cc02f2a..7290f329aa97 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java @@ -273,7 +273,8 @@ public class BroadcastQueueImpl extends BroadcastQueue { performReceiveLocked(oldRecord.resultToApp, oldRecord.resultTo, oldRecord.intent, Activity.RESULT_CANCELED, null, null, - false, false, oldRecord.userId, oldRecord.callingUid, r.callingUid, + false, false, r.shareIdentity, oldRecord.userId, + oldRecord.callingUid, r.callingUid, r.callerPackage, SystemClock.uptimeMillis() - oldRecord.enqueueTime, 0); } catch (RemoteException e) { Slog.w(TAG, "Failure [" @@ -402,7 +403,9 @@ public class BroadcastQueueImpl extends BroadcastQueue { prepareReceiverIntent(r.intent, r.curFilteredExtras), r.curReceiver, null /* compatInfo (unused but need to keep method signature) */, r.resultCode, r.resultData, r.resultExtras, r.ordered, assumeDelivered, - r.userId, app.mState.getReportedProcState())); + r.userId, r.shareIdentity ? r.callingUid : Process.INVALID_UID, + r.shareIdentity ? r.callerPackage : null, + app.mState.getReportedProcState())); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; @@ -726,9 +729,15 @@ public class BroadcastQueueImpl extends BroadcastQueue { public void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, - boolean ordered, boolean sticky, int sendingUser, - int receiverUid, int callingUid, long dispatchDelay, - long receiveDelay) throws RemoteException { + boolean ordered, boolean sticky, boolean shareIdentity, int sendingUser, + int receiverUid, int callingUid, String callingPackage, + long dispatchDelay, long receiveDelay) throws RemoteException { + // If the broadcaster opted-in to sharing their identity, then expose package visibility for + // the receiver. + if (shareIdentity) { + mService.mPackageManagerInt.grantImplicitAccess(sendingUser, intent, + UserHandle.getAppId(receiverUid), callingUid, true); + } // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null) { final IApplicationThread thread = app.getThread(); @@ -740,6 +749,8 @@ public class BroadcastQueueImpl extends BroadcastQueue { thread.scheduleReceiverList(mReceiverBatch.registeredReceiver( receiver, intent, resultCode, data, extras, ordered, sticky, assumeDelivered, sendingUser, + shareIdentity ? callingUid : Process.INVALID_UID, + shareIdentity ? callingPackage : null, app.mState.getReportedProcState())); } catch (RemoteException ex) { // Failed to call into the process. It's either dying or wedged. Kill it gently. @@ -845,8 +856,8 @@ public class BroadcastQueueImpl extends BroadcastQueue { maybeReportBroadcastDispatchedEventLocked(r, filter.owningUid); performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, prepareReceiverIntent(r.intent, filteredExtras), r.resultCode, r.resultData, - r.resultExtras, r.ordered, r.initialSticky, r.userId, - filter.receiverList.uid, r.callingUid, + r.resultExtras, r.ordered, r.initialSticky, r.shareIdentity, r.userId, + filter.receiverList.uid, r.callingUid, r.callerPackage, r.dispatchTime - r.enqueueTime, r.receiverTime - r.dispatchTime); // parallel broadcasts are fire-and-forget, not bookended by a call to @@ -1130,8 +1141,8 @@ public class BroadcastQueueImpl extends BroadcastQueue { r.mIsReceiverAppRunning = true; performReceiveLocked(r.resultToApp, r.resultTo, new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, false, false, r.userId, - r.callingUid, r.callingUid, + r.resultData, r.resultExtras, false, false, r.shareIdentity, + r.userId, r.callingUid, r.callingUid, r.callerPackage, r.dispatchTime - r.enqueueTime, now - r.dispatchTime); logBootCompletedBroadcastCompletionLatencyIfPossible(r); diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 99e2ac71168b..b952ce0946e0 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -893,6 +893,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { batch.schedule(((BroadcastFilter) receiver).receiverList.receiver, receiverIntent, r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky, assumeDelivered, r.userId, + r.shareIdentity ? r.callingUid : Process.INVALID_UID, + r.shareIdentity ? r.callerPackage : null, app.mState.getReportedProcState(), r, index); // TODO: consider making registered receivers of unordered // broadcasts report results to detect ANRs @@ -903,7 +905,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } else { batch.schedule(receiverIntent, ((ResolveInfo) receiver).activityInfo, null, r.resultCode, r.resultData, r.resultExtras, r.ordered, assumeDelivered, - r.userId, app.mState.getReportedProcState(), r, index); + r.userId, r.shareIdentity ? r.callingUid : Process.INVALID_UID, + r.shareIdentity ? r.callerPackage : null, + app.mState.getReportedProcState(), r, index); if (assumeDelivered) { batch.success(r, index, BroadcastRecord.DELIVERY_DELIVERED, "assuming delivered"); return true; @@ -946,6 +950,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue { final BroadcastRecord r = cookie.r; final int index = cookie.index; final Object receiver = r.receivers.get(index); + + if (r.shareIdentity) { + mService.mPackageManagerInt.grantImplicitAccess(r.userId, r.intent, + UserHandle.getAppId(app.uid), r.callingUid, true); + } if (receiver instanceof BroadcastFilter) { notifyScheduleRegisteredReceiver(queue.app, r, (BroadcastFilter) receiver); } else { @@ -1055,12 +1064,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (thread != null) { mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily( app, OOM_ADJ_REASON_FINISH_RECEIVER); + if (r.shareIdentity) { + mService.mPackageManagerInt.grantImplicitAccess(r.userId, r.intent, + UserHandle.getAppId(app.uid), r.callingUid, true); + } try { final boolean assumeDelivered = true; thread.scheduleReceiverList(mReceiverBatch.registeredReceiver( r.resultTo, r.intent, r.resultCode, r.resultData, r.resultExtras, false, r.initialSticky, - assumeDelivered, r.userId, app.mState.getReportedProcState())); + assumeDelivered, r.userId, + r.shareIdentity ? r.callingUid : Process.INVALID_UID, + r.shareIdentity ? r.callerPackage : null, + app.mState.getReportedProcState())); } catch (RemoteException e) { final String msg = "Failed to schedule result of " + r + " via " + app + ": " + e; logw(msg); diff --git a/services/core/java/com/android/server/am/BroadcastReceiverBatch.java b/services/core/java/com/android/server/am/BroadcastReceiverBatch.java index 226647c77ca3..153403a037a2 100644 --- a/services/core/java/com/android/server/am/BroadcastReceiverBatch.java +++ b/services/core/java/com/android/server/am/BroadcastReceiverBatch.java @@ -171,8 +171,8 @@ final class BroadcastReceiverBatch { // Add a ReceiverInfo for a registered receiver. void schedule(@Nullable IIntentReceiver receiver, Intent intent, int resultCode, @Nullable String data, @Nullable Bundle extras, boolean ordered, - boolean sticky, boolean assumeDelivered, int sendingUser, int processState, - @Nullable BroadcastRecord r, int index) { + boolean sticky, boolean assumeDelivered, int sendingUser, int callingUid, + String callingPackage, int processState, @Nullable BroadcastRecord r, int index) { ReceiverInfo ri = new ReceiverInfo(); ri.intent = intent; ri.data = data; @@ -185,6 +185,9 @@ final class BroadcastReceiverBatch { ri.receiver = receiver; ri.ordered = ordered; ri.sticky = sticky; + ri.sentFromUid = callingUid; + ri.sentFromPackage = callingPackage; + mReceivers.add(ri); mCookies.add(cookiePool.next().set(r, index)); } @@ -192,7 +195,8 @@ final class BroadcastReceiverBatch { void schedule(@Nullable Intent intent, @Nullable ActivityInfo activityInfo, @Nullable CompatibilityInfo compatInfo, int resultCode, @Nullable String data, @Nullable Bundle extras, boolean sync, boolean assumeDelivered, int sendingUser, - int processState, @Nullable BroadcastRecord r, int index) { + int callingUid, @Nullable String callingPackage, int processState, + @Nullable BroadcastRecord r, int index) { ReceiverInfo ri = new ReceiverInfo(); ri.intent = intent; ri.data = data; @@ -205,6 +209,8 @@ final class BroadcastReceiverBatch { ri.activityInfo = activityInfo; ri.compatInfo = compatInfo; ri.sync = sync; + ri.sentFromUid = callingUid; + ri.sentFromPackage = callingPackage; mReceivers.add(ri); mCookies.add(cookiePool.next().set(r, index)); } @@ -217,20 +223,21 @@ final class BroadcastReceiverBatch { ArrayList<ReceiverInfo> registeredReceiver(@Nullable IIntentReceiver receiver, @Nullable Intent intent, int resultCode, @Nullable String data, @Nullable Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered, - int sendingUser, int processState) { + int sendingUser, int callingUid, String callingPackage, int processState) { reset(); schedule(receiver, intent, resultCode, data, extras, ordered, sticky, assumeDelivered, - sendingUser, processState, null, 0); + sendingUser, callingUid, callingPackage, processState, null, 0); return receivers(); } ArrayList<ReceiverInfo> manifestReceiver(@Nullable Intent intent, @Nullable ActivityInfo activityInfo, @Nullable CompatibilityInfo compatInfo, int resultCode, @Nullable String data, @Nullable Bundle extras, boolean sync, - boolean assumeDelivered, int sendingUser, int processState) { + boolean assumeDelivered, int sendingUser, int callingUid, String callingPackage, + int processState) { reset(); schedule(intent, activityInfo, compatInfo, resultCode, data, extras, sync, assumeDelivered, - sendingUser, processState, null, 0); + sendingUser, callingUid, callingPackage, processState, null, 0); return receivers(); } diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 4304377a015f..6035ad9ca50e 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -89,6 +89,7 @@ final class BroadcastRecord extends Binder { final boolean initialSticky; // initial broadcast from register to sticky? final boolean prioritized; // contains more than one priority tranche final boolean deferUntilActive; // infinitely deferrable broadcast + final boolean shareIdentity; // whether the broadcaster's identity should be shared final int userId; // user id this broadcast was for final @Nullable String resolvedType; // the resolved data type final @Nullable String[] requiredPermissions; // permissions the caller has required @@ -417,6 +418,7 @@ final class BroadcastRecord extends Binder { pushMessage = options != null && options.isPushMessagingBroadcast(); pushMessageOverQuota = options != null && options.isPushMessagingOverQuotaBroadcast(); interactive = options != null && options.isInteractive(); + shareIdentity = options != null && options.isShareIdentityEnabled(); this.filterExtrasForReceiver = filterExtrasForReceiver; } @@ -481,6 +483,7 @@ final class BroadcastRecord extends Binder { pushMessage = from.pushMessage; pushMessageOverQuota = from.pushMessageOverQuota; interactive = from.interactive; + shareIdentity = from.shareIdentity; filterExtrasForReceiver = from.filterExtrasForReceiver; } diff --git a/services/core/java/com/android/server/am/SameProcessApplicationThread.java b/services/core/java/com/android/server/am/SameProcessApplicationThread.java index 082e8e04479b..dcb02ea8989e 100644 --- a/services/core/java/com/android/server/am/SameProcessApplicationThread.java +++ b/services/core/java/com/android/server/am/SameProcessApplicationThread.java @@ -48,11 +48,12 @@ public class SameProcessApplicationThread extends IApplicationThread.Default { @Override public void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, boolean ordered, boolean assumeDelivered, - int sendingUser, int processState) { + int sendingUser, int processState, int sentFromUid, String sentFromPackage) { mHandler.post(() -> { try { mWrapped.scheduleReceiver(intent, info, compatInfo, resultCode, data, extras, - ordered, assumeDelivered, sendingUser, processState); + ordered, assumeDelivered, sendingUser, processState, sentFromUid, + sentFromPackage); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -62,11 +63,12 @@ public class SameProcessApplicationThread extends IApplicationThread.Default { @Override public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered, - int sendingUser, int processState) { + int sendingUser, int processState, int sentFromUid, String sentFromPackage) { mHandler.post(() -> { try { mWrapped.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, - ordered, sticky, assumeDelivered, sendingUser, processState); + ordered, sticky, assumeDelivered, sendingUser, processState, sentFromUid, + sentFromPackage); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -80,11 +82,11 @@ public class SameProcessApplicationThread extends IApplicationThread.Default { if (r.registered) { scheduleRegisteredReceiver(r.receiver, r.intent, r.resultCode, r.data, r.extras, r.ordered, r.sticky, r.assumeDelivered, - r.sendingUser, r.processState); + r.sendingUser, r.processState, r.sentFromUid, r.sentFromPackage); } else { scheduleReceiver(r.intent, r.activityInfo, r.compatInfo, r.resultCode, r.data, r.extras, r.sync, r.assumeDelivered, - r.sendingUser, r.processState); + r.sendingUser, r.processState, r.sentFromUid, r.sentFromPackage); } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java index 41ae50b117e8..5e4ba8888b2b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -1401,10 +1401,10 @@ public class BroadcastQueueTest { // Confirm that we saw no registered receiver traffic final IApplicationThread oldThread = oldApp.getThread(); verify(oldThread, never()).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(), - anyBoolean(), anyBoolean(), anyBoolean(), anyInt(), anyInt()); + anyBoolean(), anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyInt(), any()); final IApplicationThread newThread = newApp.getThread(); verify(newThread, never()).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(), - anyBoolean(), anyBoolean(), anyBoolean(), anyInt(), anyInt()); + anyBoolean(), anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyInt(), any()); // Confirm that we saw final manifest broadcast verifyScheduleReceiver(times(1), newApp, airplane, diff --git a/test-mock/api/system-current.txt b/test-mock/api/system-current.txt index f87785bfac18..9e022f0cb0ef 100644 --- a/test-mock/api/system-current.txt +++ b/test-mock/api/system-current.txt @@ -5,9 +5,7 @@ package android.test.mock { method public android.content.Context createCredentialProtectedStorageContext(); method public java.io.File getPreloadsFileCache(); method public boolean isCredentialProtectedStorage(); - method public void sendBroadcast(android.content.Intent, String, android.os.Bundle); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.os.Bundle); - method public void sendOrderedBroadcast(android.content.Intent, String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle); } @Deprecated public class MockPackageManager extends android.content.pm.PackageManager { |