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

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

Temporarily whitelist processes to open activities from background

when service-based PendingIntent was whitelisted

Extends the mechanism added for broadcasts in ag/5779089.
The process can start activity from background when whitelisted
PendingIntent-based Service was started - for the next 10 seconds,
or until the service is stopped, whichever happens sooner.

For now, all this is only wired for notifications.

Bug: 110956953
Test: atest WmTests:ActivityStarterTests
Test: manual with Calendar notifications that are known
      for doing Service trampolines
Change-Id: If6ed2f5e22403c4df5abb6cf876ae89505e57380
parent 58514eaa
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -258,8 +258,8 @@ public abstract class ActivityManagerInternal {
            Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
            boolean sticky, int userId, boolean allowBackgroundActivityStarts);
    public abstract ComponentName startServiceInPackage(int uid, Intent service,
            String resolvedType, boolean fgRequired, String callingPackage, int userId)
            throws TransactionTooLargeException;
            String resolvedType, boolean fgRequired, String callingPackage, int userId,
            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;

    public abstract void disconnectActivityFromServices(Object connectionHolder);
    public abstract void cleanUpServices(int userId, ComponentName component, Intent baseIntent);
+32 −0
Original line number Diff line number Diff line
@@ -130,6 +130,9 @@ public final class ActiveServices {
    // calling startForeground() before we ANR + stop it.
    static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;

    // For how long after a whitelisted service's start its process can start a background activity
    private static final int SERVICE_BG_ACTIVITY_START_TIMEOUT_MS = 10*1000;

    final ActivityManagerService mAm;

    // Maximum number of services that we allow to start in the background
@@ -398,6 +401,14 @@ public final class ActiveServices {
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
                callingPackage, userId, false);
    }

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            final int userId, boolean allowBackgroundActivityStarts)
            throws TransactionTooLargeException {
        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
                + " type=" + resolvedType + " args=" + service.getExtras());

@@ -622,10 +633,28 @@ public final class ActiveServices {
            }
        }

        if (allowBackgroundActivityStarts) {
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
            if (proc != null) {
                proc.addAllowBackgroundActivityStartsToken(r);
                // schedule removal of the whitelisting token after the timeout
                removeAllowBackgroundActivityStartsServiceToken(proc, r,
                        SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
            }
        }
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

    private void removeAllowBackgroundActivityStartsServiceToken(ProcessRecord proc,
            ServiceRecord r, int delayMillis) {
        mAm.mHandler.postDelayed(() -> {
            if (proc != null) {
                proc.removeAllowBackgroundActivityStartsToken(r);
            }
        }, delayMillis);
    }

    private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
            String callingPackage, int callingUid, Intent service, boolean callerFg,
            final int userId) {
@@ -752,6 +781,9 @@ public final class ActiveServices {
            if (r.record != null) {
                final long origId = Binder.clearCallingIdentity();
                try {
                    // immediately remove bg activity whitelisting token if there was one
                    removeAllowBackgroundActivityStartsServiceToken(callerApp, r.record,
                            0 /* delayMillis */);
                    stopServiceLocked(r.record);
                } finally {
                    Binder.restoreCallingIdentity(origId);
+4 −3
Original line number Diff line number Diff line
@@ -19478,8 +19478,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        @Override
        public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
                boolean fgRequired, String callingPackage, int userId)
                throws TransactionTooLargeException {
                boolean fgRequired, String callingPackage, int userId,
                boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
            synchronized(ActivityManagerService.this) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                        "startServiceInPackage: " + service + " type=" + resolvedType);
@@ -19487,7 +19487,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                ComponentName res;
                try {
                    res = mServices.startServiceLocked(null, service,
                            resolvedType, -1, uid, fgRequired, callingPackage, userId);
                            resolvedType, -1, uid, fgRequired, callingPackage, userId,
                            allowBackgroundActivityStarts);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
+7 −1
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub {

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

    final PendingIntentController controller;
    final Key key;
@@ -62,6 +63,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
    private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
    private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
    private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();
    private ArraySet<IBinder> mAllowBgActivityStartsForServiceSender = new ArraySet<>();

    String stringName;
    String lastTagPrefix;
@@ -228,6 +230,9 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
        if ((flags & FLAG_BROADCAST_SENDER) != 0) {
            mAllowBgActivityStartsForBroadcastSender.add(token);
        }
        if ((flags & FLAG_SERVICE_SENDER) != 0) {
            mAllowBgActivityStartsForServiceSender.add(token);
        }
    }

    public void registerCancelListenerLocked(IResultReceiver receiver) {
@@ -426,7 +431,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
                    try {
                        controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
                                key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
                                key.packageName, userId);
                                key.packageName, userId,
                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken));
                    } catch (RuntimeException e) {
                        Slog.w(TAG, "Unable to send startService intent", e);
                    } catch (TransactionTooLargeException e) {
+2 −0
Original line number Diff line number Diff line
@@ -1142,11 +1142,13 @@ final class ProcessRecord implements WindowProcessListener {
    }

    void addAllowBackgroundActivityStartsToken(Binder entity) {
        if (entity == null) return;
        mAllowBackgroundActivityStartsTokens.add(entity);
        mWindowProcessController.setAllowBackgroundActivityStarts(true);
    }

    void removeAllowBackgroundActivityStartsToken(Binder entity) {
        if (entity == null) return;
        mAllowBackgroundActivityStartsTokens.remove(entity);
        mWindowProcessController.setAllowBackgroundActivityStarts(
                !mAllowBackgroundActivityStartsTokens.isEmpty());
Loading