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

Commit 5c686e16 authored by Kweku Adams's avatar Kweku Adams Committed by Android (Google) Code Review
Browse files

Merge "Include BAL factor in UI job scheduling."

parents a74f413f bc45d452
Loading
Loading
Loading
Loading
+54 −7
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.BackgroundStartPrivileges;
import android.app.UserSwitchObserver;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
@@ -388,6 +389,12 @@ class JobConcurrencyManager {
    private final ArrayList<ContextAssignment> mRecycledPreferredUidOnly = new ArrayList<>();
    private final ArrayList<ContextAssignment> mRecycledStoppable = new ArrayList<>();
    private final AssignmentInfo mRecycledAssignmentInfo = new AssignmentInfo();
    private final SparseIntArray mRecycledPrivilegedState = new SparseIntArray();

    private static final int PRIVILEGED_STATE_UNDEFINED = 0;
    private static final int PRIVILEGED_STATE_NONE = 1;
    private static final int PRIVILEGED_STATE_BAL = 2;
    private static final int PRIVILEGED_STATE_TOP = 3;

    private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
            new Pools.SimplePool<>(MAX_RETAINED_OBJECTS);
@@ -792,7 +799,7 @@ class JobConcurrencyManager {

        cleanUpAfterAssignmentChangesLocked(
                mRecycledChanged, mRecycledIdle, mRecycledPreferredUidOnly, mRecycledStoppable,
                mRecycledAssignmentInfo);
                mRecycledAssignmentInfo, mRecycledPrivilegedState);

        noteConcurrency();
    }
@@ -915,7 +922,8 @@ class JobConcurrencyManager {
                continue;
            }

            final boolean hasImmediacyPrivilege = hasImmediacyPrivilegeLocked(nextPending);
            final boolean hasImmediacyPrivilege =
                    hasImmediacyPrivilegeLocked(nextPending, mRecycledPrivilegedState);
            if (DEBUG && isSimilarJobRunningLocked(nextPending)) {
                Slog.w(TAG, "Already running similar job to: " + nextPending);
            }
@@ -1183,7 +1191,8 @@ class JobConcurrencyManager {
            final ArraySet<ContextAssignment> idle,
            final List<ContextAssignment> preferredUidOnly,
            final List<ContextAssignment> stoppable,
            final AssignmentInfo assignmentInfo) {
            final AssignmentInfo assignmentInfo,
            final SparseIntArray privilegedState) {
        for (int s = stoppable.size() - 1; s >= 0; --s) {
            final ContextAssignment assignment = stoppable.get(s);
            assignment.clear();
@@ -1205,20 +1214,58 @@ class JobConcurrencyManager {
        stoppable.clear();
        preferredUidOnly.clear();
        assignmentInfo.clear();
        privilegedState.clear();
        mWorkCountTracker.resetStagingCount();
        mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
    }

    @VisibleForTesting
    @GuardedBy("mLock")
    boolean hasImmediacyPrivilegeLocked(@NonNull JobStatus job) {
    boolean hasImmediacyPrivilegeLocked(@NonNull JobStatus job,
            @NonNull SparseIntArray cachedPrivilegedState) {
        if (!job.shouldTreatAsExpeditedJob() && !job.shouldTreatAsUserInitiatedJob()) {
            return false;
        }
        // EJs & user-initiated jobs for the TOP app should run immediately.
        // However, even for user-initiated jobs, if the app has not recently been in TOP or BAL
        // state, we don't give the immediacy privilege so that we can try and maintain
        // reasonably concurrency behavior.
        return job.lastEvaluatedBias == JobInfo.BIAS_TOP_APP
                // TODO(): include BAL state for user-initiated jobs
                && (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob());
        if (job.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
            return true;
        }
        final int uid = job.getSourceUid();
        final int privilegedState = cachedPrivilegedState.get(uid, PRIVILEGED_STATE_UNDEFINED);
        switch (privilegedState) {
            case PRIVILEGED_STATE_TOP:
                return true;
            case PRIVILEGED_STATE_BAL:
                return job.shouldTreatAsUserInitiatedJob();
            case PRIVILEGED_STATE_NONE:
                return false;
            case PRIVILEGED_STATE_UNDEFINED:
            default:
                final ActivityManagerInternal activityManagerInternal =
                        LocalServices.getService(ActivityManagerInternal.class);
                final int procState = activityManagerInternal.getUidProcessState(uid);
                if (procState == ActivityManager.PROCESS_STATE_TOP) {
                    cachedPrivilegedState.put(uid, PRIVILEGED_STATE_TOP);
                    return true;
                }
                if (job.shouldTreatAsExpeditedJob()) {
                    // EJs only get the TOP privilege.
                    return false;
                }

                final BackgroundStartPrivileges bsp =
                        activityManagerInternal.getBackgroundStartPrivileges(uid);
                final boolean balAllowed = bsp.allowsBackgroundActivityStarts();
                if (DEBUG) {
                    Slog.d(TAG, "Job " + job.toShortString() + " bal state: " + bsp);
                }
                cachedPrivilegedState.put(uid,
                        balAllowed ? PRIVILEGED_STATE_BAL : PRIVILEGED_STATE_NONE);
                return balAllowed;
        }
    }

    @GuardedBy("mLock")
+20 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.BackgroundStartPrivileges;
import android.app.IUidObserver;
import android.app.compat.CompatChanges;
import android.app.job.IJobScheduler;
@@ -3841,6 +3842,25 @@ public class JobSchedulerService extends com.android.server.SystemService
                        return callingResult;
                    }
                }

                final int uid = sourceUid != -1 ? sourceUid : callingUid;
                final int procState = mActivityManagerInternal.getUidProcessState(uid);
                if (DEBUG) {
                    Slog.d(TAG, "Uid " + uid + " proc state="
                            + ActivityManager.procStateToString(procState));
                }
                if (procState != ActivityManager.PROCESS_STATE_TOP) {
                    final BackgroundStartPrivileges bsp =
                            mActivityManagerInternal.getBackgroundStartPrivileges(uid);
                    if (DEBUG) {
                        Slog.d(TAG, "Uid " + uid + ": " + bsp);
                    }
                    if (!bsp.allowsBackgroundActivityStarts()) {
                        Slog.e(TAG,
                                "Uid " + uid + " not in a state to schedule user-initiated jobs");
                        return JobScheduler.RESULT_FAILURE;
                    }
                }
            }
            if (jobWorkItem != null) {
                jobWorkItem.enforceValidity(rejectNegativeNetworkEstimates);
+5 −0
Original line number Diff line number Diff line
@@ -464,6 +464,11 @@ public abstract class ActivityManagerInternal {
    public abstract boolean isActivityStartsLoggingEnabled();
    /** Returns true if the background activity starts is enabled. */
    public abstract boolean isBackgroundActivityStartsEnabled();
    /**
     * Returns The current {@link BackgroundStartPrivileges} of the UID.
     */
    @NonNull
    public abstract BackgroundStartPrivileges getBackgroundStartPrivileges(int uid);
    public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing);

    /** @see com.android.server.am.ActivityManagerService#monitor */
+44 −0
Original line number Diff line number Diff line
@@ -487,6 +487,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class ActivityManagerService extends IActivityManager.Stub
@@ -6452,6 +6453,44 @@ public class ActivityManagerService extends IActivityManager.Stub
        return entry == null ? null : entry.second;
    }
    private static class GetBackgroundStartPrivilegesFunctor implements Consumer<ProcessRecord> {
        private BackgroundStartPrivileges mBackgroundStartPrivileges =
                BackgroundStartPrivileges.NONE;
        private int mUid;
        void prepare(int uid) {
            mUid = uid;
            mBackgroundStartPrivileges = BackgroundStartPrivileges.NONE;
        }
        @NonNull
        BackgroundStartPrivileges getResult() {
            return mBackgroundStartPrivileges;
        }
        public void accept(ProcessRecord pr) {
            if (pr.uid == mUid) {
                mBackgroundStartPrivileges =
                        mBackgroundStartPrivileges.merge(pr.getBackgroundStartPrivileges());
            }
        }
    }
    private final GetBackgroundStartPrivilegesFunctor mGetBackgroundStartPrivilegesFunctor =
            new GetBackgroundStartPrivilegesFunctor();
    /**
     * Returns the current complete {@link BackgroundStartPrivileges} of the UID.
     */
    @NonNull
    private BackgroundStartPrivileges getBackgroundStartPrivileges(int uid) {
        synchronized (mProcLock) {
            mGetBackgroundStartPrivilegesFunctor.prepare(uid);
            mProcessList.forEachLruProcessesLOSP(false, mGetBackgroundStartPrivilegesFunctor);
            return mGetBackgroundStartPrivilegesFunctor.getResult();
        }
    }
    /**
     * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
     * the allowlist
@@ -17851,6 +17890,11 @@ public class ActivityManagerService extends IActivityManager.Stub
            return mConstants.mFlagBackgroundActivityStartsEnabled;
        }
        @Override
        public BackgroundStartPrivileges getBackgroundStartPrivileges(int uid) {
            return ActivityManagerService.this.getBackgroundStartPrivileges(uid);
        }
        public void reportCurKeyguardUsageEvent(boolean keyguardShowing) {
            ActivityManagerService.this.reportGlobalUsageEvent(keyguardShowing
                    ? UsageEvents.Event.KEYGUARD_SHOWN
+58 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
@@ -340,6 +341,24 @@ class ProcessRecord implements WindowProcessListener {
    @GuardedBy("mService")
    private boolean mInFullBackup;

    /**
     * A set of tokens that currently contribute to this process being temporarily allowed
     * to start certain components (eg. activities or foreground services) even if it's not
     * in the foreground.
     */
    @GuardedBy("mBackgroundStartPrivileges")
    private final ArrayMap<Binder, BackgroundStartPrivileges> mBackgroundStartPrivileges =
            new ArrayMap<>();

    /**
     * The merged BackgroundStartPrivileges based on what's in {@link #mBackgroundStartPrivileges}.
     * This is lazily generated using {@link #getBackgroundStartPrivileges()}.
     */
    @Nullable
    @GuardedBy("mBackgroundStartPrivileges")
    private BackgroundStartPrivileges mBackgroundStartPrivilegesMerged =
            BackgroundStartPrivileges.NONE;

    /**
     * Controller for driving the process state on the window manager side.
     */
@@ -1325,11 +1344,50 @@ class ProcessRecord implements WindowProcessListener {
        Objects.requireNonNull(entity);
        mWindowProcessController.addOrUpdateBackgroundStartPrivileges(entity,
                backgroundStartPrivileges);
        setBackgroundStartPrivileges(entity, backgroundStartPrivileges);
    }

    void removeBackgroundStartPrivileges(Binder entity) {
        Objects.requireNonNull(entity);
        mWindowProcessController.removeBackgroundStartPrivileges(entity);
        setBackgroundStartPrivileges(entity, null);
    }

    @NonNull
    BackgroundStartPrivileges getBackgroundStartPrivileges() {
        synchronized (mBackgroundStartPrivileges) {
            if (mBackgroundStartPrivilegesMerged == null) {
                // Lazily generate the merged version when it's actually needed.
                mBackgroundStartPrivilegesMerged = BackgroundStartPrivileges.NONE;
                for (int i = mBackgroundStartPrivileges.size() - 1; i >= 0; --i) {
                    mBackgroundStartPrivilegesMerged =
                            mBackgroundStartPrivilegesMerged.merge(
                                    mBackgroundStartPrivileges.valueAt(i));
                }
            }
            return mBackgroundStartPrivilegesMerged;
        }
    }

    private void setBackgroundStartPrivileges(@NonNull Binder entity,
            @Nullable BackgroundStartPrivileges backgroundStartPrivileges) {
        synchronized (mBackgroundStartPrivileges) {
            final boolean changed;
            if (backgroundStartPrivileges == null) {
                changed = mBackgroundStartPrivileges.remove(entity) != null;
            } else {
                final BackgroundStartPrivileges oldBsp =
                        mBackgroundStartPrivileges.put(entity, backgroundStartPrivileges);
                // BackgroundStartPrivileges tries to reuse the same object and avoid creating
                // additional objects. For now, we just compare the reference to see if something
                // has changed.
                // TODO: actually compare the individual values to see if there's a change
                changed = backgroundStartPrivileges != oldBsp;
            }
            if (changed) {
                mBackgroundStartPrivilegesMerged = null;
            }
        }
    }

    @Override
Loading