From 6771c6c923d1428cacc249fe16f3474182b595d1 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Mon, 13 Dec 2021 11:18:28 -0800 Subject: [PATCH] Create start and running bills for all priorities. Create explicit start and running bills for each priority so we can better determine when a job is allowed to run based on TARE policies. Also defer min and low priority jobs more by ensuring an app can pay for higher priority jobs before we run the lower priority jobs. Bug: 158300259 Bug: 205714315 Test: See additional bills registered in dumpsys Change-Id: I901d4d7cc6d02fc0b2084d90d7fe7a199148cb3b --- .../job/controllers/TareController.java | 262 +++++++++++++++--- 1 file changed, 227 insertions(+), 35 deletions(-) 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 be3a3ee2921b5..bc7b49eff5d27 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 @@ -19,6 +19,7 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.NonNull; +import android.app.job.JobInfo; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; @@ -48,6 +49,56 @@ public class TareController extends StateController { private static final boolean DEBUG = JobSchedulerService.DEBUG || Log.isLoggable(TAG, Log.DEBUG); + /** + * Bill to use while we're waiting to start a min priority 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. We don't want min priority jobs to use up all available credits, + * so we make sure to only run them while there are enough credits to run higher priority jobs. + */ + private static final ActionBill BILL_JOB_START_MIN = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START, 1, 0), + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 120_000L) + )); + + /** + * Bill to use when a min priority job is currently running. We don't want min priority jobs + * to use up remaining credits, so we make sure to only run them while there are enough + * credits to run higher priority jobs. We stop the job when the app's credits get too low. + */ + private static final ActionBill BILL_JOB_RUNNING_MIN = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 60_000L) + )); + + /** + * Bill to use while we're waiting to start a low priority 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. We don't want low priority jobs to use up all available credits, + * so we make sure to only run them while there are enough credits to run higher priority jobs. + */ + private static final ActionBill BILL_JOB_START_LOW = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START, 1, 0), + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 60_000L) + )); + + /** + * Bill to use when a low priority job is currently running. We don't want low priority jobs + * to use up all available credits, so we make sure to only run them while there are enough + * credits to run higher priority jobs. We stop the job when the app's credits get too low. + */ + private static final ActionBill BILL_JOB_RUNNING_LOW = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 30_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. @@ -61,9 +112,9 @@ public class TareController extends StateController { )); /** - * Bill to use when a default is currently running. We want to track and make sure the app can - * continue to pay for 1 more second of execution time. We stop the job when the app can no - * longer pay for that time. + * Bill to use when a default priority job is currently running. We want to track and make + * sure the app can continue to pay for 1 more second of execution time. We stop the job when + * the app can no longer pay for that time. */ private static final ActionBill BILL_JOB_RUNNING_DEFAULT = new ActionBill(List.of( @@ -75,7 +126,33 @@ public class TareController extends StateController { * 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. */ - private static final ActionBill BILL_JOB_START_EXPEDITED = + private static final ActionBill BILL_JOB_START_HIGH = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 1, 0), + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 30_000L) + )); + + /** + * Bill to use when a high priority job is currently running. We want to track and make sure + * the app can continue to pay for 1 more second of execution time. We stop the job when the + * app can no longer pay for that time. + */ + private static final ActionBill BILL_JOB_RUNNING_HIGH = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 1_000L) + )); + + + /** + * Bill to use while we're waiting to start a max priority job. This should only be used for + * requested-EJs that aren't allowed to run as EJs. 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. + */ + private static final ActionBill BILL_JOB_START_MAX = new ActionBill(List.of( new EconomyManagerInternal.AnticipatedAction( JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0), @@ -84,16 +161,63 @@ public class TareController extends StateController { )); /** - * Bill to use when an EJ is currently running (as an EJ). We want to track and make sure the - * app can continue to pay for 1 more second of execution time. We stop the job when the app can - * no longer pay for that time. + * Bill to use when a max priority job is currently running. This should only be used for + * requested-EJs that aren't allowed to run as EJs. We want to track and make sure + * the app can continue to pay for 1 more second of execution time. We stop the job when the + * app can no longer pay for that time. */ - private static final ActionBill BILL_JOB_RUNNING_EXPEDITED = + private static final ActionBill BILL_JOB_RUNNING_MAX = new ActionBill(List.of( new EconomyManagerInternal.AnticipatedAction( 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. + */ + private static final ActionBill BILL_JOB_START_MAX_EXPEDITED = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0), + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 30_000L) + )); + + /** + * Bill to use when a max priority EJ is currently running (as an EJ). We want to track and + * make sure the app can continue to pay for 1 more second of execution time. We stop the job + * when the app can no longer pay for that time. + */ + private static final ActionBill BILL_JOB_RUNNING_MAX_EXPEDITED = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + 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. + */ + private static final ActionBill BILL_JOB_START_HIGH_EXPEDITED = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 1, 0), + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 30_000L) + )); + + /** + * Bill to use when a high priority EJ is currently running (as an EJ). We want to track and + * make sure the app can continue to pay for 1 more second of execution time. We stop the job + * when the app can no longer pay for that time. + */ + private static final ActionBill BILL_JOB_RUNNING_HIGH_EXPEDITED = + new ActionBill(List.of( + new EconomyManagerInternal.AnticipatedAction( + JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 1_000L) + )); + private final EconomyManagerInternal mEconomyManagerInternal; private final BackgroundJobsController mBackgroundJobsController; @@ -200,10 +324,7 @@ public class TareController extends StateController { removeJobFromBillList(jobStatus, billToJobMap.keyAt(i)); } } - if (jobStatus.shouldTreatAsExpeditedJob()) { - addJobToBillList(jobStatus, BILL_JOB_RUNNING_EXPEDITED); - } - addJobToBillList(jobStatus, BILL_JOB_RUNNING_DEFAULT); + addJobToBillList(jobStatus, getRunningBill(jobStatus)); } @Override @@ -270,7 +391,7 @@ public class TareController extends StateController { if (!mIsEnabled) { return true; } - return canAffordBillLocked(jobStatus, BILL_JOB_START_EXPEDITED); + return canAffordBillLocked(jobStatus, BILL_JOB_START_MAX_EXPEDITED); } @GuardedBy("mLock") @@ -278,14 +399,9 @@ public class TareController extends StateController { if (!mIsEnabled) { return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; } - if (jobStatus.shouldTreatAsExpeditedJob()) { - return mEconomyManagerInternal.getMaxDurationMs( - jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), - BILL_JOB_RUNNING_EXPEDITED); - } return mEconomyManagerInternal.getMaxDurationMs( jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), - BILL_JOB_RUNNING_DEFAULT); + getRunningBill(jobStatus)); } @GuardedBy("mLock") @@ -336,12 +452,56 @@ public class TareController extends StateController { // TODO: factor in network cost when available final ArraySet bills = new ArraySet<>(); if (jobStatus.isRequestedExpeditedJob()) { - bills.add(BILL_JOB_START_EXPEDITED); + if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) { + bills.add(BILL_JOB_START_MAX_EXPEDITED); + } else { + bills.add(BILL_JOB_START_HIGH_EXPEDITED); + } + } + switch (jobStatus.getEffectivePriority()) { + case JobInfo.PRIORITY_HIGH: + bills.add(BILL_JOB_START_HIGH); + break; + case JobInfo.PRIORITY_DEFAULT: + bills.add(BILL_JOB_START_DEFAULT); + break; + case JobInfo.PRIORITY_LOW: + bills.add(BILL_JOB_START_LOW); + break; + case JobInfo.PRIORITY_MIN: + bills.add(BILL_JOB_START_MIN); + break; } - bills.add(BILL_JOB_START_DEFAULT); return bills; } + @NonNull + private ActionBill getRunningBill(JobStatus jobStatus) { + // TODO: factor in network cost when available + if (jobStatus.shouldTreatAsExpeditedJob()) { + if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) { + return BILL_JOB_RUNNING_MAX_EXPEDITED; + } else { + return BILL_JOB_RUNNING_HIGH_EXPEDITED; + } + } + switch (jobStatus.getEffectivePriority()) { + case JobInfo.PRIORITY_MAX: + return BILL_JOB_RUNNING_MAX; + case JobInfo.PRIORITY_HIGH: + return BILL_JOB_RUNNING_HIGH; + case JobInfo.PRIORITY_LOW: + return BILL_JOB_RUNNING_LOW; + case JobInfo.PRIORITY_MIN: + return BILL_JOB_RUNNING_MIN; + default: + Slog.wtf(TAG, "Got unexpected priority: " + jobStatus.getEffectivePriority()); + // Intentional fallthrough + case JobInfo.PRIORITY_DEFAULT: + return BILL_JOB_RUNNING_DEFAULT; + } + } + @GuardedBy("mLock") private boolean canAffordBillLocked(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) { if (!mIsEnabled) { @@ -370,11 +530,17 @@ public class TareController extends StateController { if (!mIsEnabled) { return true; } + if (!jobStatus.isRequestedExpeditedJob()) { + return false; + } if (mService.isCurrentlyRunningLocked(jobStatus)) { - return canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_EXPEDITED); + return canAffordBillLocked(jobStatus, getRunningBill(jobStatus)); } - return canAffordBillLocked(jobStatus, BILL_JOB_START_EXPEDITED); + if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) { + return canAffordBillLocked(jobStatus, BILL_JOB_START_MAX_EXPEDITED); + } + return canAffordBillLocked(jobStatus, BILL_JOB_START_HIGH_EXPEDITED); } @GuardedBy("mLock") @@ -384,18 +550,20 @@ public class TareController extends StateController { } if (mService.isCurrentlyRunningLocked(jobStatus)) { if (jobStatus.isRequestedExpeditedJob()) { - return canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_EXPEDITED) + return canAffordBillLocked(jobStatus, getRunningBill(jobStatus)) || canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_DEFAULT); } - return canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_DEFAULT); + return canAffordBillLocked(jobStatus, getRunningBill(jobStatus)); } - if (jobStatus.isRequestedExpeditedJob() - && canAffordBillLocked(jobStatus, BILL_JOB_START_EXPEDITED)) { - return true; + final ArraySet bills = getPossibleStartBills(jobStatus); + for (int i = 0; i < bills.size(); ++i) { + ActionBill bill = bills.valueAt(i); + if (canAffordBillLocked(jobStatus, bill)) { + return true; + } } - - return canAffordBillLocked(jobStatus, BILL_JOB_START_DEFAULT); + return false; } /** @@ -417,11 +585,23 @@ public class TareController extends StateController { @NonNull private String getBillName(@NonNull ActionBill bill) { - if (bill.equals(BILL_JOB_START_EXPEDITED)) { - return "EJ_START_BILL"; + if (bill.equals(BILL_JOB_START_MAX_EXPEDITED)) { + return "EJ_MAX_START_BILL"; } - if (bill.equals(BILL_JOB_RUNNING_EXPEDITED)) { - return "EJ_RUNNING_BILL"; + if (bill.equals(BILL_JOB_RUNNING_MAX_EXPEDITED)) { + return "EJ_MAX_RUNNING_BILL"; + } + if (bill.equals(BILL_JOB_START_HIGH_EXPEDITED)) { + return "EJ_HIGH_START_BILL"; + } + if (bill.equals(BILL_JOB_RUNNING_HIGH_EXPEDITED)) { + return "EJ_HIGH_RUNNING_BILL"; + } + if (bill.equals(BILL_JOB_START_HIGH)) { + return "HIGH_START_BILL"; + } + if (bill.equals(BILL_JOB_RUNNING_HIGH)) { + return "HIGH_RUNNING_BILL"; } if (bill.equals(BILL_JOB_START_DEFAULT)) { return "DEFAULT_START_BILL"; @@ -429,7 +609,19 @@ public class TareController extends StateController { if (bill.equals(BILL_JOB_RUNNING_DEFAULT)) { return "DEFAULT_RUNNING_BILL"; } - return "UNKNOWN_BILL (" + bill.toString() + ")"; + if (bill.equals(BILL_JOB_START_LOW)) { + return "LOW_START_BILL"; + } + if (bill.equals(BILL_JOB_RUNNING_LOW)) { + return "LOW_RUNNING_BILL"; + } + if (bill.equals(BILL_JOB_START_MIN)) { + return "MIN_START_BILL"; + } + if (bill.equals(BILL_JOB_RUNNING_MIN)) { + return "MIN_RUNNING_BILL"; + } + return "UNKNOWN_BILL (" + bill + ")"; } @Override