Add APIs to allow broadcaster to share identity with receivers

This commit adds APIs to allow a broadcasting app to share its
identity with the receiver(s) that will receive the broadcast and
to allow receivers to obtain the uid and package name of the
broadcasting app.

Bug: 259743961
Test: atest ShareIdentityTest
Change-Id: Ibe9df2b44e414ab92adbf44cd5b4c9eabecb7ee1
diff --git a/core/api/current.txt b/core/api/current.txt
index bca9913..b0d5e06 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5204,6 +5204,13 @@
     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 @@
     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 @@
     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 c098adb..9c7d220 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -817,7 +817,6 @@
     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 @@
     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 @@
     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 @@
     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 5f2f623..219f5f4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -165,7 +165,7 @@
     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 @@
     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 @@
     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 2a390a7..b57fb20 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -88,6 +88,16 @@
      */
     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 @@
         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 3761251..170c0b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -785,9 +785,10 @@
     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 @@
             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 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 @@
                 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 @@
         // 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 @@
             // 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 88765c3..f6992c9 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -27,6 +27,7 @@
 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 @@
  * 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 @@
     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 @@
             "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 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 @@
         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 @@
      * 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 @@
      * 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 @@
      * @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 @@
      * 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 @@
     /**
      * 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 @@
      * <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 @@
      * @see CompatChanges#isChangeEnabled
      * @see #clearRequireCompatChange()
      */
+    @SystemApi
     public void setRequireCompatChange(long changeId, boolean enabled) {
         mRequireCompatChangeId = changeId;
         mRequireCompatChangeEnabled = enabled;
@@ -593,7 +616,9 @@
     /**
      * 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 @@
     }
 
     /**
+     * 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 @@
      *                               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 @@
         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 3776369..9c262b9 100644
--- a/core/java/android/app/ComponentOptions.java
+++ b/core/java/android/app/ComponentOptions.java
@@ -20,6 +20,8 @@
 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 @@
  * 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 @@
     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 @@
      *
      * @deprecated use #setPendingIntentBackgroundActivityStartMode(int) to set the full range
      * of states
+     * @hide
      */
     @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
         mPendingIntentBalAllowed = allowed;
@@ -130,6 +150,7 @@
      * @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 @@
      * 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 @@
     /**
      * 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 @@
         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 12899f2..bed75db 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -25,6 +25,7 @@
 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 @@
     }
 
     @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 @@
             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 4f69d85..dad9b43 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -66,7 +66,8 @@
     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 @@
             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 7c22902..c13da0b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1683,12 +1683,13 @@
                 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 @@
                 }
                 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 @@
             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 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 8d7e3c4..7364d0f 100644
--- a/core/java/android/app/ReceiverInfo.aidl
+++ b/core/java/android/app/ReceiverInfo.aidl
@@ -38,6 +38,8 @@
     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 64dcc4d..3d76b28 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.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 @@
         @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 @@
             mToken = token;
             mSendingUser = userId;
             mFlags = flags;
+            mSentFromUid = sentFromUid;
+            mSentFromPackage = sentFromPackage;
         }
 
         /** @hide */
@@ -322,6 +329,16 @@
             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 @@
     }
 
     /**
+     * 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 5f1502f..ac2eae41 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2445,13 +2445,12 @@
      * @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 @@
             @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 @@
      * @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 9027e2e..a103128 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -20,6 +20,7 @@
 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 @@
         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 @@
         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 @@
                 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 b1a01cc..7290f32 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 @@
                         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 @@
                     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 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 @@
                     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 @@
                 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 @@
                             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 99e2ac7..b952ce0 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 @@
             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 @@
         } 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 @@
             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 @@
         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 226647c..153403a 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 @@
     // 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 @@
         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 @@
     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 @@
         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 @@
     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 4304377..6035ad9 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 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 @@
         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 @@
         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 082e8e0..dcb02ea 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 @@
     @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 @@
     @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 @@
             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 41ae50b..5e4ba88 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 @@
         // 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 f87785b..9e022f0 100644
--- a/test-mock/api/system-current.txt
+++ b/test-mock/api/system-current.txt
@@ -5,9 +5,7 @@
     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 {