diff options
3 files changed, 96 insertions, 27 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 3da508d490f1..86d7a5a5a62e 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1559,6 +1559,13 @@ public class JobSchedulerService extends com.android.server.SystemService } } + /** Return the current bias of the given UID. */ + public int getUidBias(int uid) { + synchronized (mLock) { + return mUidBiasOverride.get(uid, JobInfo.BIAS_DEFAULT); + } + } + @Override public void onDeviceIdleStateChanged(boolean deviceIdle) { synchronized (mLock) { diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 9cae864576ce..00d1bfffd9a6 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -366,9 +366,6 @@ public final class JobServiceContext implements ServiceConnection { } catch (RemoteException e) { // Whatever. } - mEconomyManagerInternal.noteOngoingEventStarted( - job.getSourceUserId(), job.getSourcePackageName(), - getRunningActionId(job), String.valueOf(job.getJobId())); final String jobPackage = job.getSourcePackageName(); final int jobUserId = job.getSourceUserId(); UsageStatsManagerInternal usageStats = @@ -401,25 +398,6 @@ public final class JobServiceContext implements ServiceConnection { } } - @EconomicPolicy.AppAction - private static int getRunningActionId(@NonNull JobStatus job) { - switch (job.getEffectivePriority()) { - case JobInfo.PRIORITY_MAX: - return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING; - case JobInfo.PRIORITY_HIGH: - return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING; - case JobInfo.PRIORITY_LOW: - return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING; - case JobInfo.PRIORITY_MIN: - return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING; - default: - Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority())); - // Intentional fallthrough - case JobInfo.PRIORITY_DEFAULT: - return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING; - } - } - /** * Used externally to query the running job. Will return null if there is no job running. */ @@ -1043,9 +1021,6 @@ public final class JobServiceContext implements ServiceConnection { } catch (RemoteException e) { // Whatever. } - mEconomyManagerInternal.noteOngoingEventStopped( - mRunningJob.getSourceUserId(), mRunningJob.getSourcePackageName(), - getRunningActionId(mRunningJob), String.valueOf(mRunningJob.getJobId())); if (mParams.getStopReason() == JobParameters.STOP_REASON_TIMEOUT) { mEconomyManagerInternal.noteInstantaneousEvent( mRunningJob.getSourceUserId(), mRunningJob.getSourcePackageName(), diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java index bc7b49eff5d2..fd6aa7a1d282 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java @@ -16,6 +16,8 @@ package com.android.server.job.controllers; +import static android.app.job.JobInfo.getPriorityString; + import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.NonNull; @@ -31,6 +33,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.server.JobSchedulerBackgroundThread; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; +import com.android.server.tare.EconomicPolicy; import com.android.server.tare.EconomyManagerInternal; import com.android.server.tare.EconomyManagerInternal.ActionBill; import com.android.server.tare.JobSchedulerEconomicPolicy; @@ -195,7 +198,7 @@ public class TareController extends StateController { JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 1_000L) )); - /** + /** * Bill to use while we're waiting to start a job. If a job isn't running yet, don't consider it * eligible to run unless it can pay for a job start and at least some period of execution time. */ @@ -285,6 +288,14 @@ public class TareController extends StateController { } }; + /** + * List of jobs that started while the UID was in the TOP state. There will be no more than + * 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is + * fine. + */ + @GuardedBy("mLock") + private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>(); + @GuardedBy("mLock") private boolean mIsEnabled; @@ -299,6 +310,7 @@ public class TareController extends StateController { } @Override + @GuardedBy("mLock") public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final long nowElapsed = sElapsedRealtimeClock.millis(); jobStatus.setTareWealthConstraintSatisfied(nowElapsed, hasEnoughWealthLocked(jobStatus)); @@ -312,6 +324,7 @@ public class TareController extends StateController { } @Override + @GuardedBy("mLock") public void prepareForExecutionLocked(JobStatus jobStatus) { final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); @@ -325,12 +338,29 @@ public class TareController extends StateController { } } addJobToBillList(jobStatus, getRunningBill(jobStatus)); + + final int uid = jobStatus.getSourceUid(); + if (mService.getUidBias(uid) == JobInfo.BIAS_TOP_APP) { + if (DEBUG) { + Slog.d(TAG, jobStatus.toShortString() + " is top started job"); + } + mTopStartedJobs.add(jobStatus); + // Top jobs won't count towards quota so there's no need to involve the EconomyManager. + } else { + mEconomyManagerInternal.noteOngoingEventStarted(userId, pkgName, + getRunningActionId(jobStatus), String.valueOf(jobStatus.getJobId())); + } } @Override + @GuardedBy("mLock") public void unprepareFromExecutionLocked(JobStatus jobStatus) { final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); + mEconomyManagerInternal.noteOngoingEventStopped(userId, pkgName, + getRunningActionId(jobStatus), String.valueOf(jobStatus.getJobId())); + mTopStartedJobs.remove(jobStatus); + final ArraySet<ActionBill> bills = getPossibleStartBills(jobStatus); ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap = mRegisteredBillsAndJobs.get(userId, pkgName); @@ -347,10 +377,14 @@ public class TareController extends StateController { } @Override + @GuardedBy("mLock") public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); + mEconomyManagerInternal.noteOngoingEventStopped(userId, pkgName, + getRunningActionId(jobStatus), String.valueOf(jobStatus.getJobId())); + mTopStartedJobs.remove(jobStatus); ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap = mRegisteredBillsAndJobs.get(userId, pkgName); if (billToJobMap != null) { @@ -391,7 +425,16 @@ public class TareController extends StateController { if (!mIsEnabled) { return true; } - return canAffordBillLocked(jobStatus, BILL_JOB_START_MAX_EXPEDITED); + if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) { + return canAffordBillLocked(jobStatus, BILL_JOB_START_MAX_EXPEDITED); + } + return canAffordBillLocked(jobStatus, BILL_JOB_START_HIGH_EXPEDITED); + } + + /** @return true if the job was started while the app was in the TOP state. */ + @GuardedBy("mLock") + private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) { + return mTopStartedJobs.contains(jobStatus); } @GuardedBy("mLock") @@ -459,6 +502,9 @@ public class TareController extends StateController { } } switch (jobStatus.getEffectivePriority()) { + case JobInfo.PRIORITY_MAX: + bills.add(BILL_JOB_START_MAX); + break; case JobInfo.PRIORITY_HIGH: bills.add(BILL_JOB_START_HIGH); break; @@ -471,6 +517,10 @@ public class TareController extends StateController { case JobInfo.PRIORITY_MIN: bills.add(BILL_JOB_START_MIN); break; + default: + Slog.wtf(TAG, "Unexpected priority: " + + JobInfo.getPriorityString(jobStatus.getEffectivePriority())); + break; } return bills; } @@ -502,11 +552,36 @@ public class TareController extends StateController { } } + @EconomicPolicy.AppAction + private static int getRunningActionId(@NonNull JobStatus job) { + switch (job.getEffectivePriority()) { + case JobInfo.PRIORITY_MAX: + return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING; + case JobInfo.PRIORITY_HIGH: + return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING; + case JobInfo.PRIORITY_LOW: + return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING; + case JobInfo.PRIORITY_MIN: + return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING; + default: + Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority())); + // Intentional fallthrough + case JobInfo.PRIORITY_DEFAULT: + return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING; + } + } + @GuardedBy("mLock") private boolean canAffordBillLocked(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) { if (!mIsEnabled) { return true; } + if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP + || isTopStartedJobLocked(jobStatus)) { + // Jobs for the top app should always be allowed to run, and any jobs started while + // the app is on top shouldn't consume any credits. + return true; + } final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); ArrayMap<ActionBill, Boolean> actionAffordability = @@ -533,6 +608,12 @@ public class TareController extends StateController { if (!jobStatus.isRequestedExpeditedJob()) { return false; } + if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP + || isTopStartedJobLocked(jobStatus)) { + // Jobs for the top app should always be allowed to run, and any jobs started while + // the app is on top shouldn't consume any credits. + return true; + } if (mService.isCurrentlyRunningLocked(jobStatus)) { return canAffordBillLocked(jobStatus, getRunningBill(jobStatus)); } @@ -548,6 +629,12 @@ public class TareController extends StateController { if (!mIsEnabled) { return true; } + if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP + || isTopStartedJobLocked(jobStatus)) { + // Jobs for the top app should always be allowed to run, and any jobs started while + // the app is on top shouldn't consume any credits. + return true; + } if (mService.isCurrentlyRunningLocked(jobStatus)) { if (jobStatus.isRequestedExpeditedJob()) { return canAffordBillLocked(jobStatus, getRunningBill(jobStatus)) |