Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6ee1e34 authored by Jacob Hobbie's avatar Jacob Hobbie Committed by Android (Google) Code Review
Browse files

Merge "Making runtime receivers safer by default"

parents ff928967 50324497
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -10684,6 +10684,8 @@ package android.content {
    field public static final String PERFORMANCE_HINT_SERVICE = "performance_hint";
    field public static final String POWER_SERVICE = "power";
    field public static final String PRINT_SERVICE = "print";
    field public static final int RECEIVER_EXPORTED = 2; // 0x2
    field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
    field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
    field public static final String RESTRICTIONS_SERVICE = "restrictions";
    field public static final String ROLE_SERVICE = "role";
+26 −6
Original line number Diff line number Diff line
@@ -534,8 +534,8 @@ public abstract class Context {
                    | Context.BIND_NOT_PERCEPTIBLE | Context.BIND_NOT_VISIBLE;

    /** @hide */
    @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
            RECEIVER_VISIBLE_TO_INSTANT_APPS
    @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = {
            RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface RegisterReceiverFlags {}
@@ -545,6 +545,18 @@ public abstract class Context {
     */
    public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 0x1;

    /**
     * Flag for {@link #registerReceiver}: The receiver can receive broadcasts from other Apps.
     * Has the same behavior as marking a statically registered receiver with "exported=true"
     */
    public static final int RECEIVER_EXPORTED = 0x2;

    /**
     * Flag for {@link #registerReceiver}: The receiver cannot receive broadcasts from other Apps.
     * Has the same behavior as marking a statically registered receiver with "exported=false"
     */
    public static final int RECEIVER_NOT_EXPORTED = 0x4;

    /**
     * Returns an AssetManager instance for the application's package.
     * <p>
@@ -2989,8 +3001,12 @@ public abstract class Context {
     *
     * @param receiver The BroadcastReceiver to handle the broadcast.
     * @param filter Selects the Intent broadcasts to be received.
     * @param flags Additional options for the receiver. May be 0 or
     *      {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
     * @param flags Additional options for the receiver. As of
     * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
     * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
     *            for protected broadcasts, and may additionally specify
     *            {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
     *            specified.
     *
     * @return The first sticky intent found that matches <var>filter</var>,
     *         or null if there are none.
@@ -3062,8 +3078,12 @@ public abstract class Context {
     *      no permission is required.
     * @param scheduler Handler identifying the thread that will receive
     *      the Intent.  If null, the main thread of the process will be used.
     * @param flags Additional options for the receiver. May be 0 or
     *      {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
     * @param flags Additional options for the receiver. As of
     * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
     * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
     *            for protected broadcasts, and may additionally specify
     *            {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
     *            specified.
     *
     * @return The first sticky intent found that matches <var>filter</var>,
     *         or null if there are none.
+48 −2
Original line number Diff line number Diff line
@@ -194,6 +194,9 @@ import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -543,6 +546,16 @@ public class ActivityManagerService extends IActivityManager.Stub
    static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
    static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
    /**
     * It is now required for apps to explicitly set either
     * {@link android.content.Context#RECEIVER_EXPORTED} or
     * {@link android.content.Context#RECEIVER_NOT_EXPORTED} when registering a receiver for an
     * unprotected broadcast in code.
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
    /**
     * The maximum number of bytes that {@link #setProcessStateSummary} accepts.
     *
@@ -12416,6 +12429,11 @@ public class ActivityManagerService extends IActivityManager.Stub
        ProcessRecord callerApp = null;
        final boolean visibleToInstantApps
                = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
        // Dynamic receivers are exported by default for versions prior to T
        final boolean exported =
                ((flags & Context.RECEIVER_EXPORTED) != 0
                        || (!Compatibility.isChangeEnabled(161145287)));
        int callingUid;
        int callingPid;
        boolean instantApp;
@@ -12452,8 +12470,10 @@ public class ActivityManagerService extends IActivityManager.Stub
                noAction.add(null);
                actions = noAction.iterator();
            }
            boolean onlyProtectedBroadcasts = actions.hasNext();
            // Collect stickies of users
            // Collect stickies of users and check if broadcast is only registered for protected
            // broadcasts
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                String action = actions.next();
@@ -12469,6 +12489,31 @@ public class ActivityManagerService extends IActivityManager.Stub
                        }
                    }
                }
                if (onlyProtectedBroadcasts) {
                    try {
                        onlyProtectedBroadcasts &=
                                AppGlobals.getPackageManager().isProtectedBroadcast(action);
                    } catch (RemoteException e) {
                        onlyProtectedBroadcasts = false;
                        Slog.w(TAG, "Remote exception", e);
                    }
                }
            }
            // If the change is enabled, but neither exported or not exported is set, we need to log
            // an error so the consumer can know to explicitly set the value for their flag
            if (!onlyProtectedBroadcasts && (Compatibility.isChangeEnabled(161145287)
                    && (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED))
                    == 0)) {
                Slog.e(TAG,
                        callerPackage + ": Targeting T+ (version " + Build.VERSION_CODES.TIRAMISU
                                + " and above) requires that one of RECEIVER_EXPORTED or "
                                + "RECEIVER_NOT_EXPORTED be specified when registering a receiver");
            } else if (((flags & Context.RECEIVER_EXPORTED) != 0) && (
                    (flags & Context.RECEIVER_NOT_EXPORTED) != 0)) {
                throw new IllegalArgumentException(
                        "Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED"
                                + "flag");
            }
        }
@@ -12557,7 +12602,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                        + " callerPackage is " + callerPackage);
            }
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps);
                    receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
                    exported);
            if (rl.containsFilter(filter)) {
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
+4 −1
Original line number Diff line number Diff line
@@ -34,10 +34,12 @@ final class BroadcastFilter extends IntentFilter {
    final int owningUserId;
    final boolean instantApp;
    final boolean visibleToInstantApp;
    final boolean exported;

    BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
            String _packageName, String _featureId, String _receiverId, String _requiredPermission,
            int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp) {
            int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp,
            boolean _exported) {
        super(_filter);
        receiverList = _receiverList;
        packageName = _packageName;
@@ -48,6 +50,7 @@ final class BroadcastFilter extends IntentFilter {
        owningUserId = _userId;
        instantApp = _instantApp;
        visibleToInstantApp = _visibleToInstantApp;
        exported = _exported;
    }

    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+16 −0
Original line number Diff line number Diff line
@@ -775,6 +775,22 @@ public final class BroadcastQueue {
            skip = true;
        }

        // Ensure that broadcasts are only sent to other apps if they are explicitly marked as
        // exported, or are System level broadcasts
        if (!skip && !filter.exported && Process.SYSTEM_UID != r.callingUid
                && filter.receiverList.uid != r.callingUid) {

            Slog.w(TAG, "Exported Denial: sending "
                    + r.intent.toString()
                    + ", action: " + r.intent.getAction()
                    + " from " + r.callerPackage
                    + " (uid=" + r.callingUid + ")"
                    + " due to receiver " + filter.receiverList.app
                    + " (uid " + filter.receiverList.uid + ")"
                    + " not specifying RECEIVER_EXPORTED");
            // skip = true;
        }

        if (skip) {
            r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
            return;