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

Commit ac116df5 authored by Michal Karpinski's avatar Michal Karpinski
Browse files

Block activity starts from background when realCallingUid is

a persistent system process and the start wasn't explicitly
whitelisted by the sender

Also, adds mechanism to temporary whitelist processes when
broadcast-based PendingIntent was whitelisted, so that
activities can be opened for the duration of the broadcast
being processed.

For now, all this is only wired for notifications.

Note: those whitelists are separate - only UI elements like
notifications will leverage both in order to support trampolines.
Other system-based PendingIntent senders should only use the
activity-based whitelist when they want an activity to be opened
from background.

Bug: 110956953
Test: atest WmTests:ActivityStarterTests
Test: manual with Play notifications that are known
      for doing trampolines

Change-Id: Ibab91cdbe7afc0aed29d430dd41327272020925b
parent 67b5e2ae
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -72,6 +72,12 @@ public abstract class ActivityManagerInternal {
    public abstract void setPendingIntentWhitelistDuration(IIntentSender target,
            IBinder whitelistToken, long duration);

    /**
     * Allows for a {@link PendingIntent} to be whitelisted to start activities from background.
     */
    public abstract void setPendingIntentAllowBgActivityStarts(
            IIntentSender target, IBinder whitelistToken, int flags);

    /**
     * Allow DeviceIdleController to tell us about what apps are whitelisted.
     */
@@ -250,7 +256,7 @@ public abstract class ActivityManagerInternal {
    public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent,
            String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
            boolean sticky, int userId);
            boolean sticky, int userId, boolean allowBackgroundActivityStarts);
    public abstract ComponentName startServiceInPackage(int uid, Intent service,
            String resolvedType, boolean fgRequired, String callingPackage, int userId)
            throws TransactionTooLargeException;
+37 −9
Original line number Diff line number Diff line
@@ -3740,10 +3740,10 @@ public class ActivityManagerService extends IActivityManager.Stub
                        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
                        broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
                                null, null, permission.ACCESS_INSTANT_APPS, null, false, false,
                                resolvedUserId);
                                resolvedUserId, false);
                    } else {
                        broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
                                null, null, null, null, false, false, resolvedUserId);
                                null, null, null, null, false, false, resolvedUserId, false);
                    }
                    if (observer != null) {
@@ -13992,7 +13992,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, -1, -1, false, null, null, OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1);
                            null, 0, null, null, false, true, true, -1, false);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
@@ -14231,6 +14231,18 @@ public class ActivityManagerService extends IActivityManager.Stub
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
        return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
            resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
            sticky, callingPid, callingUid, userId, false /* allowBackgroundActivityStarts */);
    }
    @GuardedBy("this")
    final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId,
            boolean allowBackgroundActivityStarts) {
        intent = new Intent(intent);
        final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14731,7 +14743,8 @@ public class ActivityManagerService extends IActivityManager.Stub
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId);
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
@@ -14827,7 +14840,8 @@ public class ActivityManagerService extends IActivityManager.Stub
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId);
                    resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                    + ": prev had " + queue.mOrderedBroadcasts.size());
@@ -14974,7 +14988,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
            int userId) {
            int userId, boolean allowBackgroundActivityStarts) {
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);
@@ -14984,7 +14998,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
                    resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, OP_NONE, bOptions, serialized,
                    sticky, -1, uid, userId);
                    sticky, -1, uid, userId, allowBackgroundActivityStarts);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
@@ -19039,6 +19053,19 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
        }
        @Override
        public void setPendingIntentAllowBgActivityStarts(IIntentSender target,
                IBinder whitelistToken, int flags) {
            if (!(target instanceof PendingIntentRecord)) {
                Slog.w(TAG, "setPendingIntentAllowBgActivityStarts():"
                        + " not a PendingIntentRecord: " + target);
                return;
            }
            synchronized (ActivityManagerService.this) {
                ((PendingIntentRecord) target).setAllowBgActivityStarts(whitelistToken, flags);
            }
        }
        @Override
        public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
            synchronized (ActivityManagerService.this) {
@@ -19426,11 +19453,12 @@ public class ActivityManagerService extends IActivityManager.Stub
        public int broadcastIntentInPackage(String packageName, int uid, Intent intent,
                String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
                Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
                boolean sticky, int userId) {
                boolean sticky, int userId, boolean allowBackgroundActivityStarts) {
            synchronized (ActivityManagerService.this) {
                return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                        requiredPermission, bOptions, serialized, sticky, userId);
                        requiredPermission, bOptions, serialized, sticky, userId,
                        allowBackgroundActivityStarts);
            }
        }
+6 −0
Original line number Diff line number Diff line
@@ -287,6 +287,9 @@ public final class BroadcastQueue {
        r.curApp = app;
        app.curReceivers.add(r);
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
        if (r.allowBackgroundActivityStarts) {
            app.addAllowBackgroundActivityStartsToken(r);
        }
        mService.mProcessList.updateLruProcessLocked(app, false, null);
        if (!skipOomAdj) {
            mService.updateOomAdjLocked();
@@ -415,6 +418,9 @@ public final class BroadcastQueue {
        if (state == BroadcastRecord.IDLE) {
            Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
        }
        if (r.allowBackgroundActivityStarts) {
            r.curApp.removeAllowBackgroundActivityStartsToken(r);
         }
        // If we're abandoning this broadcast before any receivers were actually spun up,
        // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply.
        if (r.nextReceiver > 0) {
+8 −1
Original line number Diff line number Diff line
@@ -81,6 +81,10 @@ final class BroadcastRecord extends Binder {
    int manifestSkipCount;  // number of manifest receivers skipped.
    BroadcastQueue queue;   // the outbound queue handling this broadcast

    // if set to true, app's process will be temporarily whitelisted to start activities
    // from background for the duration of the broadcast dispatch
    final boolean allowBackgroundActivityStarts;

    static final int IDLE = 0;
    static final int APP_RECEIVE = 1;
    static final int CALL_IN_RECEIVE = 2;
@@ -223,7 +227,8 @@ final class BroadcastRecord extends Binder {
            int _callingPid, int _callingUid, boolean _callerInstantApp, String _resolvedType,
            String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
            IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
            boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId) {
            boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
            boolean _allowBackgroundActivityStarts) {
        if (_intent == null) {
            throw new NullPointerException("Can't construct with a null intent");
        }
@@ -252,6 +257,7 @@ final class BroadcastRecord extends Binder {
        userId = _userId;
        nextReceiver = 0;
        state = IDLE;
        allowBackgroundActivityStarts = _allowBackgroundActivityStarts;
    }

    /**
@@ -295,6 +301,7 @@ final class BroadcastRecord extends Binder {
        manifestCount = from.manifestCount;
        manifestSkipCount = from.manifestSkipCount;
        queue = from.queue;
        allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
    }

    public BroadcastRecord maybeStripForHistory() {
+22 −3
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;

@@ -48,6 +49,9 @@ import java.util.Objects;
public final class PendingIntentRecord extends IIntentSender.Stub {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;

    public static final int FLAG_ACTIVITY_SENDER = 1 << 0;
    public static final int FLAG_BROADCAST_SENDER = 1 << 1;

    final PendingIntentController controller;
    final Key key;
    final int uid;
@@ -56,6 +60,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
    boolean canceled = false;
    private ArrayMap<IBinder, Long> whitelistDuration;
    private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
    private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
    private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();

    String stringName;
    String lastTagPrefix;
@@ -214,6 +220,16 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
        this.stringName = null;
    }

    void setAllowBgActivityStarts(IBinder token, int flags) {
        if (token == null) return;
        if ((flags & FLAG_ACTIVITY_SENDER) != 0) {
            mAllowBgActivityStartsForActivitySender.add(token);
        }
        if ((flags & FLAG_BROADCAST_SENDER) != 0) {
            mAllowBgActivityStartsForBroadcastSender.add(token);
        }
    }

    public void registerCancelListenerLocked(IResultReceiver receiver) {
        if (mCancelCallbacks == null) {
            mCancelCallbacks = new RemoteCallbackList<>();
@@ -370,14 +386,16 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
                            res = controller.mAtmInternal.startActivitiesInPackage(
                                    uid, key.packageName, allIntents, allResolvedTypes, resultTo,
                                    mergedOptions, userId, false /* validateIncomingUser */,
                                    this /* originatingPendingIntent */);
                                    this /* originatingPendingIntent */,
                                    mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
                        } else {
                            res = controller.mAtmInternal.startActivityInPackage(
                                    uid, callingPid, callingUid, key.packageName, finalIntent,
                                    resolvedType, resultTo, resultWho, requestCode, 0,
                                    mergedOptions, userId, null, "PendingIntentRecord",
                                    false /* validateIncomingUser */,
                                    this /* originatingPendingIntent */);
                                    this /* originatingPendingIntent */,
                                    mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
                        }
                    } catch (RuntimeException e) {
                        Slog.w(TAG, "Unable to send startActivity intent", e);
@@ -394,7 +412,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
                        int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
                                uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
                                requiredPermission, options, (finishedReceiver != null),
                                false, userId);
                                false, userId,
                                mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken));
                        if (sent == ActivityManager.BROADCAST_SUCCESS) {
                            sendFinish = false;
                        }
Loading