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

Commit af111324 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "EBS: Exempt jobs scheduled for foreground apps"

parents c1ac0355 15407846
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -558,4 +558,6 @@ message JobStatusDumpProto {

    optional int64 last_successful_run_time = 22;
    optional int64 last_failed_run_time = 23;

    optional int64 internal_flags = 24;
}
+7 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.server;

import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.AppOpsManager.PackageOps;
import android.app.IActivityManager;
@@ -825,9 +826,10 @@ public class ForceAppStandbyTracker {
    /**
     * @return whether jobs should be restricted for a UID package-name.
     */
    public boolean areJobsRestricted(int uid, @NonNull String packageName) {
    public boolean areJobsRestricted(int uid, @NonNull String packageName,
            boolean hasForegroundExemption) {
        return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true,
                /* exemptOnBatterySaver =*/ false);
                hasForegroundExemption);
    }

    /**
@@ -861,7 +863,9 @@ public class ForceAppStandbyTracker {
    /**
     * @return whether a UID is in the foreground or not.
     *
     * Note clients normally shouldn't need to access it. It's only for dumpsys.
     * Note this information is based on the UID proc state callback, meaning it's updated
     * asynchronously and may subtly be stale. If the fresh data is needed, use
     * {@link ActivityManagerInternal#getUidProcessState} instead.
     */
    public boolean isInForeground(int uid) {
        if (UserHandle.isCore(uid)) {
+42 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.job.IJobScheduler;
@@ -73,8 +74,10 @@ import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.DeviceIdleController;
import com.android.server.FgThread;
import com.android.server.ForceAppStandbyTracker;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
@@ -102,6 +105,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;

/**
 * Responsible for taking jobs representing work to be performed by a client app, and determining
@@ -175,8 +179,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
    final JobSchedulerStub mJobSchedulerStub;

    PackageManagerInternal mLocalPM;
    ActivityManagerInternal mActivityManagerInternal;
    IBatteryStats mBatteryStats;
    DeviceIdleController.LocalService mLocalDeviceIdleController;
    final ForceAppStandbyTracker mForceAppStandbyTracker;

    /**
     * Set to true once we are allowed to run third party apps.
@@ -778,6 +784,22 @@ public final class JobSchedulerService extends com.android.server.SystemService
        mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userHandle);
    }

    /**
     * Return whether an UID is in the foreground or not.
     */
    private boolean isUidInForeground(int uid) {
        synchronized (mLock) {
            if (mUidPriorityOverride.get(uid, 0) > 0) {
                return true;
            }
        }
        // Note UID observer may not be called in time, so we always check with the AM.
        return mActivityManagerInternal.getUidProcessState(uid)
                <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
    }

    private final Predicate<Integer> mIsUidInForegroundPredicate = this::isUidInForeground;

    public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName,
            int userId, String tag) {
        try {
@@ -797,12 +819,25 @@ public final class JobSchedulerService extends com.android.server.SystemService
                // Fast path: we are adding work to an existing job, and the JobInfo is not
                // changing.  We can just directly enqueue this work in to the job.
                if (toCancel.getJob().equals(job)) {

                    toCancel.enqueueWorkLocked(ActivityManager.getService(), work);

                    // If any of work item is enqueued when the source is in the foreground,
                    // exempt the entire job.
                    toCancel.maybeAddForegroundExemption(mIsUidInForegroundPredicate);

                    return JobScheduler.RESULT_SUCCESS;
                }
            }

            JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);

            // Give exemption if the source is in the foreground just now.
            // Note if it's a sync job, this method is called on the handler so it's not exactly
            // the state when requestSync() was called, but that should be fine because of the
            // 1 minute foreground grace period.
            jobStatus.maybeAddForegroundExemption(mIsUidInForegroundPredicate);

            if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
            // Jobs on behalf of others don't apply to the per-app job cap
            if (ENFORCE_MAX_JOBS && packageName == null) {
@@ -1047,6 +1082,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
        super(context);

        mLocalPM = LocalServices.getService(PackageManagerInternal.class);
        mActivityManagerInternal = Preconditions.checkNotNull(
                LocalServices.getService(ActivityManagerInternal.class));

        mHandler = new JobHandler(context.getMainLooper());
        mConstants = new Constants(mHandler);
@@ -1078,6 +1115,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
        mDeviceIdleJobsController = DeviceIdleJobsController.get(this);
        mControllers.add(mDeviceIdleJobsController);

        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);

        // If the job store determined that it can't yet reschedule persisted jobs,
        // we need to start watching the clock.
        if (!mJobs.jobTimesInflatedValid()) {
@@ -1137,6 +1176,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
    public void onBootPhase(int phase) {
        if (PHASE_SYSTEM_SERVICES_READY == phase) {
            mConstants.start(getContext().getContentResolver());

            mForceAppStandbyTracker.start();

            // Register br for package removals and user removals.
            final IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+12 −2
Original line number Diff line number Diff line
@@ -72,6 +72,9 @@ import java.util.Set;
 *      This is important b/c {@link com.android.server.job.JobStore.WriteJobsMapToDiskRunnable}
 *      and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that
 *      object.
 *
 * Test:
 * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
 */
public final class JobStore {
    private static final String TAG = "JobStore";
@@ -427,6 +430,9 @@ public final class JobStore {
            out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
            out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
            out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
            if (jobStatus.getInternalFlags() != 0) {
                out.attribute(null, "internalFlags", String.valueOf(jobStatus.getInternalFlags()));
            }

            out.attribute(null, "lastSuccessfulRunTime",
                    String.valueOf(jobStatus.getLastSuccessfulRunTime()));
@@ -689,6 +695,7 @@ public final class JobStore {
            int uid, sourceUserId;
            long lastSuccessfulRunTime;
            long lastFailedRunTime;
            int internalFlags = 0;

            // Read out job identifier attributes and priority.
            try {
@@ -704,6 +711,10 @@ public final class JobStore {
                if (val != null) {
                    jobBuilder.setFlags(Integer.parseInt(val));
                }
                val = parser.getAttributeValue(null, "internalFlags");
                if (val != null) {
                    internalFlags = Integer.parseInt(val);
                }
                val = parser.getAttributeValue(null, "sourceUserId");
                sourceUserId = val == null ? -1 : Integer.parseInt(val);

@@ -718,7 +729,6 @@ public final class JobStore {
            }

            String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");

            final String sourceTag = parser.getAttributeValue(null, "sourceTag");

            int eventType;
@@ -857,7 +867,7 @@ public final class JobStore {
                    appBucket, currentHeartbeat, sourceTag,
                    elapsedRuntimes.first, elapsedRuntimes.second,
                    lastSuccessfulRunTime, lastFailedRunTime,
                    (rtcIsGood) ? null : rtcRuntimes);
                    (rtcIsGood) ? null : rtcRuntimes, internalFlags);
            return js;
        }

+3 −1
Original line number Diff line number Diff line
@@ -197,7 +197,9 @@ public final class BackgroundJobsController extends StateController {
        final int uid = jobStatus.getSourceUid();
        final String packageName = jobStatus.getSourcePackageName();

        final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName);
        final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName,
                (jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
                        != 0);

        return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
    }
Loading