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

Commit 681db90b authored by Michal Karpinski's avatar Michal Karpinski Committed by Android (Google) Code Review
Browse files

Merge "Add new BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS binding flag and the mechanism to use it"

parents 15694fcc e069b002
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -337,6 +337,15 @@ public abstract class Context {
     */
    public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;

    /**
     * Flag for {@link #bindService}: allow background activity starts from the bound service's
     * process.
     * This flag is only respected if the caller is holding
     * {@link android.Manifest.permission#START_ACTIVITIES_FROM_BACKGROUND}.
     * @hide
     */
    public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 0x00100000;

    /**
     * @hide Flag for {@link #bindService}: the service being bound to represents a
     * protected system component, so must have association restrictions applied to it.
+1 −0
Original line number Diff line number Diff line
@@ -11518,6 +11518,7 @@ public final class Settings {
         * service_min_restart_time_between     (long)
         * service_max_inactivity               (long)
         * service_bg_start_timeout             (long)
         * service_bg_activity_start_timeout    (long)
         * process_start_async                  (boolean)
         * </pre>
         *
+2 −2
Original line number Diff line number Diff line
@@ -159,8 +159,8 @@ public class TileLifecycleManager extends BroadcastReceiver implements
            mBindTryCount++;
            try {
                mIsBound = mContext.bindServiceAsUser(mIntent, this,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                        mUser);
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, mUser);
            } catch (SecurityException e) {
                Log.e(TAG, "Failed to bind to service", e);
                mIsBound = false;
+2 −1
Original line number Diff line number Diff line
@@ -91,7 +91,8 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
        if (userState == null) return;
        final long identity = Binder.clearCallingIdentity();
        try {
            int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE;
            int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
                    | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
            if (userState.getBindInstantServiceAllowed()) {
                flags |= Context.BIND_ALLOW_INSTANT;
            }
+49 −44
Original line number Diff line number Diff line
@@ -131,9 +131,6 @@ 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
@@ -333,8 +330,8 @@ public final class ActiveServices {
                            + " delayedStop=" + r.delayedStop);
                } else {
                    try {
                        startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true,
                                false);
                        startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false,
                                true);
                    } catch (TransactionTooLargeException e) {
                        // Ignore, nobody upstack cares.
                    }
@@ -637,26 +634,26 @@ 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);
            r.hasStartedWhitelistingBgActivityStarts = true;
            scheduleCleanUpHasStartedWhitelistingBgActivityStartsLocked(r);
        }
        }
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting,
                allowBackgroundActivityStarts);

        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);
    private void scheduleCleanUpHasStartedWhitelistingBgActivityStartsLocked(ServiceRecord r) {
        // if there's a request pending from the past, drop it before scheduling a new one
        if (r.startedWhitelistingBgActivityStartsCleanUp == null) {
            r.startedWhitelistingBgActivityStartsCleanUp = () -> {
                synchronized(mAm) {
                    r.setHasStartedWhitelistingBgActivityStarts(false);
                }
        }, delayMillis);
            };
        }
        mAm.mHandler.removeCallbacks(r.startedWhitelistingBgActivityStartsCleanUp);
        mAm.mHandler.postDelayed(r.startedWhitelistingBgActivityStartsCleanUp,
                mAm.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT);
    }

    private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
@@ -705,8 +702,7 @@ public final class ActiveServices {
    }

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting, boolean allowBackgroundActivityStarts)
            throws TransactionTooLargeException {
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
@@ -717,8 +713,7 @@ public final class ActiveServices {
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false,
                allowBackgroundActivityStarts);
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }
@@ -765,6 +760,12 @@ public final class ActiveServices {
                    SystemClock.uptimeMillis());
        }
        service.callStart = false;

        // the service will not necessarily be brought down, so only clear the whitelisting state
        // for start-based bg activity starts now, and drop any existing future cleanup callback
        service.setHasStartedWhitelistingBgActivityStarts(false);
        mAm.mHandler.removeCallbacks(service.startedWhitelistingBgActivityStartsCleanUp);

        bringDownServiceIfNeededLocked(service, false, false);
    }

@@ -788,9 +789,6 @@ 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);
@@ -1614,6 +1612,12 @@ public final class ActiveServices {
                            + ") set BIND_ALLOW_INSTANT when binding service " + service);
        }

        if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
            mAm.enforceCallingPermission(
                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
                    "BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS");
        }

        final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
        final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
        final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
@@ -1672,7 +1676,7 @@ public final class ActiveServices {
                                try {
                                    bringUpServiceLocked(serviceRecord,
                                            serviceIntent.getFlags(),
                                            callerFg, false, false, false);
                                            callerFg, false, false);
                                } catch (RemoteException e) {
                                    /* ignore - local call */
                                }
@@ -1762,6 +1766,9 @@ public final class ActiveServices {
            if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
                s.whitelistManager = true;
            }
            if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
                s.setHasBindingWhitelistingBgActivityStarts(true);
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
@@ -1775,7 +1782,7 @@ public final class ActiveServices {
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired, false) != null) {
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }
@@ -2445,8 +2452,7 @@ public final class ActiveServices {
            return;
        }
        try {
            bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false,
                    false);
            bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
        } catch (TransactionTooLargeException e) {
            // Ignore, it's been logged and nothing upstack cares.
        }
@@ -2491,11 +2497,8 @@ public final class ActiveServices {
    }

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired,
            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
        //Slog.i(TAG, "Bring up service:");
        //r.dump("  ");

            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
@@ -2603,13 +2606,6 @@ public final class ActiveServices {
            }
        }

        if (app != null && allowBackgroundActivityStarts) {
            app.addAllowBackgroundActivityStartsToken(r);
            // schedule removal of the whitelisting token after the timeout
            removeAllowBackgroundActivityStartsServiceToken(app, r,
                    SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
        }

        if (r.fgRequired) {
            if (DEBUG_FOREGROUND_SERVICE) {
                Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
@@ -2646,6 +2642,11 @@ public final class ActiveServices {
        }
    }

    /**
     * Note the name of this method should not be confused with the started services concept.
     * The "start" here means bring up the instance in the client, and this method is called
     * from bindService() as well.
     */
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
@@ -3085,6 +3086,10 @@ public final class ActiveServices {
                    updateWhitelistManagerLocked(s.app);
                }
            }
            // And do the same for bg activity starts whitelisting.
            if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
                s.updateHasBindingWhitelistingBgActivityStarts();
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
Loading