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

Commit cdda462b authored by Kweku Adams's avatar Kweku Adams Committed by Automerger Merge Worker
Browse files

Merge "Ensure apps can't bypass FAS using UIJ." into udc-dev am: 632fa893

parents 7d25070d 632fa893
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -200,7 +200,10 @@ class JobNotificationCoordinator {
            // No more jobs using this notification. Apply the final job stop policy.
            // If the user attempted to stop the job/app, then always remove the notification
            // so the user doesn't get confused about the app state.
            // Similarly, if the user background restricted the app, remove the notification so
            // the user doesn't think the app is continuing to run in the background.
            if (details.jobEndNotificationPolicy == JOB_END_NOTIFICATION_POLICY_REMOVE
                    || stopReason == JobParameters.STOP_REASON_BACKGROUND_RESTRICTION
                    || stopReason == JobParameters.STOP_REASON_USER) {
                mNotificationManagerInternal.cancelNotification(
                        packageName, packageName, details.appUid, details.appPid, /* tag */ null,
+11 −2
Original line number Diff line number Diff line
@@ -413,16 +413,22 @@ public final class JobServiceContext implements ServiceConnection {
            final Intent intent = new Intent().setComponent(job.getServiceComponent())
                    .setFlags(Intent.FLAG_FROM_BACKGROUND);
            boolean binding = false;
            boolean startedWithForegroundFlag = false;
            try {
                final Context.BindServiceFlags bindFlags;
                if (job.shouldTreatAsUserInitiatedJob()) {
                if (job.shouldTreatAsUserInitiatedJob() && !job.isUserBgRestricted()) {
                    // If the user has bg restricted the app, don't give the job FG privileges
                    // such as bypassing data saver or getting the higher foreground proc state.
                    // If we've gotten to this point, the app is most likely in the foreground,
                    // so the job will run just fine while the user keeps the app in the foreground.
                    bindFlags = Context.BindServiceFlags.of(
                            Context.BIND_AUTO_CREATE
                                    | Context.BIND_ALMOST_PERCEPTIBLE
                                    | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS
                                    | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS
                                    | Context.BIND_NOT_APP_COMPONENT_USAGE);
                } else if (job.shouldTreatAsExpeditedJob()) {
                    startedWithForegroundFlag = true;
                } else if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) {
                    bindFlags = Context.BindServiceFlags.of(
                            Context.BIND_AUTO_CREATE
                                    | Context.BIND_NOT_FOREGROUND
@@ -535,8 +541,11 @@ public final class JobServiceContext implements ServiceConnection {
            mAvailable = false;
            mStoppedReason = null;
            mStoppedTime = 0;
            // Wait until after bindService() returns a success value to set these so we don't
            // have JobStatus objects that aren't running but have these set to true.
            job.startedAsExpeditedJob = job.shouldTreatAsExpeditedJob();
            job.startedAsUserInitiatedJob = job.shouldTreatAsUserInitiatedJob();
            job.startedWithForegroundFlag = startedWithForegroundFlag;
            return true;
        }
    }
+28 −4
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;

import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -205,8 +206,32 @@ public final class BackgroundJobsController extends StateController {
        final int uid = jobStatus.getSourceUid();
        final String packageName = jobStatus.getSourcePackageName();

        final boolean canRun = !mAppStateTracker.areJobsRestricted(uid, packageName,
                jobStatus.canRunInBatterySaver());
        final boolean isUserBgRestricted =
                !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
                        && !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName);
        // If a job started with the foreground flag, it'll cause the UID to stay active
        // and thus cause areJobsRestricted() to always return false, so if
        // areJobsRestricted() returns false and the app is BG restricted and not TOP,
        // we need to stop any jobs that started with the foreground flag so they don't
        // keep the app in an elevated proc state. If we were to get in this situation,
        // then the user restricted the app after the job started, so it's best to stop
        // the job as soon as possible, especially since the job would be visible to the
        // user (with a notification and in Task Manager).
        // There are several other reasons that uidActive can be true for an app even if its
        // proc state is less important than BFGS.
        // JobScheduler has historically (at least up through UDC) allowed the app's jobs to run
        // when its UID was active, even if it's background restricted. This has been fine because
        // JobScheduler stops the job as soon as the UID becomes inactive and the jobs themselves
        // will not keep the UID active. The logic here is to ensure that special jobs
        // (e.g. user-initiated jobs) themselves do not keep the UID active when the app is
        // background restricted.
        final boolean shouldStopImmediately = jobStatus.startedWithForegroundFlag
                && isUserBgRestricted
                && mService.getUidProcState(uid)
                        > ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
        final boolean canRun = !shouldStopImmediately
                && !mAppStateTracker.areJobsRestricted(
                        uid, packageName, jobStatus.canRunInBatterySaver());

        final boolean isActive;
        if (activeState == UNKNOWN) {
@@ -219,8 +244,7 @@ public final class BackgroundJobsController extends StateController {
        }
        boolean didChange =
                jobStatus.setBackgroundNotRestrictedConstraintSatisfied(nowElapsed, canRun,
                        !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
                        && !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName));
                        isUserBgRestricted);
        didChange |= jobStatus.setUidActive(isActive);
        return didChange;
    }
+6 −0
Original line number Diff line number Diff line
@@ -1774,6 +1774,12 @@ public final class ConnectivityController extends RestrictingController implemen
        }
        pw.println();

        if (mBackgroundMeteredAllowed.size() > 0) {
            pw.print("Background metered allowed: ");
            pw.println(mBackgroundMeteredAllowed);
            pw.println();
        }

        pw.println("Current default network callbacks:");
        pw.increaseIndent();
        for (int i = 0; i < mCurrentDefaultNetworkCallbacks.size(); i++) {
+22 −0
Original line number Diff line number Diff line
@@ -430,6 +430,13 @@ public final class JobStatus {
     * when it started running. This isn't copied over when a job is rescheduled.
     */
    public boolean startedAsUserInitiatedJob = false;
    /**
     * Whether this particular JobStatus instance started with the foreground flag
     * (or more accurately, did <b>not</b> have the
     * {@link android.content.Context#BIND_NOT_FOREGROUND} flag
     * included in its binding flags when started).
     */
    public boolean startedWithForegroundFlag = false;

    public boolean startedWithImmediacyPrivilege = false;

@@ -1606,6 +1613,10 @@ public final class JobStatus {
     * for any reason.
     */
    public boolean shouldTreatAsUserInitiatedJob() {
        // isUserBgRestricted is intentionally excluded from this method. It should be fine to
        // treat the job as a UI job while the app is TOP, but just not in the background.
        // Instead of adding a proc state check here, the parts of JS that can make the distinction
        // and care about the distinction can do the check.
        return getJob().isUserInitiated()
                && (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_USER) == 0
                && (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ) == 0;
@@ -1653,6 +1664,11 @@ public final class JobStatus {
                        && (mDynamicConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) == 0);
    }

    /** Returns whether or not the app is background restricted by the user (FAS). */
    public boolean isUserBgRestricted() {
        return mIsUserBgRestricted;
    }

    /** @return true if the constraint was changed, false otherwise. */
    boolean setChargingConstraintSatisfied(final long nowElapsed, boolean state) {
        return setConstraintSatisfied(CONSTRAINT_CHARGING, nowElapsed, state);
@@ -2802,6 +2818,12 @@ public final class JobStatus {
        }
        pw.decreaseIndent();

        pw.print("Started with foreground flag: ");
        pw.println(startedWithForegroundFlag);
        if (mIsUserBgRestricted) {
            pw.println("User BG restricted");
        }

        if (changedAuthorities != null) {
            pw.println("Changed authorities:");
            pw.increaseIndent();
Loading