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 {