Loading apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +33 −16 Original line number Diff line number Diff line Loading @@ -621,6 +621,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final long nowElapsed = sElapsedRealtimeClock.millis(); final int userId = jobStatus.getSourceUserId(); Loading Loading @@ -648,6 +649,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void prepareForExecutionLocked(JobStatus jobStatus) { if (DEBUG) { Slog.d(TAG, "Prepping for " + jobStatus.toShortString()); Loading Loading @@ -676,6 +678,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void unprepareFromExecutionLocked(JobStatus jobStatus) { Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); if (timer != null) { Loading @@ -691,6 +694,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { if (jobStatus.clearTrackingController(JobStatus.TRACKING_QUOTA)) { Loading Loading @@ -796,10 +800,12 @@ public final class QuotaController extends StateController { } /** Returns the maximum amount of time this job could run for. */ @GuardedBy("mLock") public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) { if (!jobStatus.shouldTreatAsExpeditedJob()) { // If quota is currently "free", then the job can run for the full amount of time. if (mChargeTracker.isCharging() // If quota is currently "free", then the job can run for the full amount of time, // regardless of bucket (hence using charging instead of isQuotaFreeLocked()). if (mChargeTracker.isChargingLocked() || mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) { Loading @@ -810,7 +816,7 @@ public final class QuotaController extends StateController { } // Expedited job. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; } if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) { Loading @@ -828,8 +834,9 @@ public final class QuotaController extends StateController { } /** @return true if the job is within expedited job quota. */ @GuardedBy("mLock") public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) { if (isQuotaFree(jobStatus.getEffectiveStandbyBucket())) { if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) { return true; } // A job is within quota if one of the following is true: Loading Loading @@ -887,9 +894,10 @@ public final class QuotaController extends StateController { jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket); } private boolean isQuotaFree(final int standbyBucket) { @GuardedBy("mLock") private boolean isQuotaFreeLocked(final int standbyBucket) { // Quota constraint is not enforced while charging. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { // Restricted jobs require additional constraints when charging, so don't immediately // mark quota as free when charging. return standbyBucket != RESTRICTED_INDEX; Loading @@ -898,11 +906,12 @@ public final class QuotaController extends StateController { } @VisibleForTesting @GuardedBy("mLock") boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { if (standbyBucket == NEVER_INDEX) return false; if (isQuotaFree(standbyBucket)) return true; if (isQuotaFreeLocked(standbyBucket)) return true; ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); return getRemainingExecutionTimeLocked(stats) > 0 Loading Loading @@ -1556,9 +1565,9 @@ public final class QuotaController extends StateController { private void handleNewChargingStateLocked() { mTimerChargingUpdateFunctor.setStatus(sElapsedRealtimeClock.millis(), mChargeTracker.isCharging()); mChargeTracker.isChargingLocked()); if (DEBUG) { Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isCharging()); Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isChargingLocked()); } // Deal with Timers first. mEJPkgTimers.forEach(mTimerChargingUpdateFunctor); Loading Loading @@ -1827,6 +1836,7 @@ public final class QuotaController extends StateController { * Track whether we're charging. This has a slightly different definition than that of * BatteryController. */ @GuardedBy("mLock") private boolean mCharging; ChargingTracker() { Loading @@ -1846,7 +1856,8 @@ public final class QuotaController extends StateController { mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); } public boolean isCharging() { @GuardedBy("mLock") public boolean isChargingLocked() { return mCharging; } Loading Loading @@ -2055,9 +2066,12 @@ public final class QuotaController extends StateController { } return; } if (mRunningBgJobs.remove(jobStatus) && !mChargeTracker.isCharging() && mRunningBgJobs.size() == 0) { emitSessionLocked(sElapsedRealtimeClock.millis()); final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage( mPkg.packageName, mPkg.userId, nowElapsed); if (mRunningBgJobs.remove(jobStatus) && mRunningBgJobs.size() == 0 && !isQuotaFreeLocked(standbyBucket)) { emitSessionLocked(nowElapsed); cancelCutoff(); } } Loading @@ -2077,6 +2091,7 @@ public final class QuotaController extends StateController { cancelCutoff(); } @GuardedBy("mLock") private void emitSessionLocked(long nowElapsed) { if (mBgJobCount <= 0) { // Nothing to emit. Loading Loading @@ -2121,6 +2136,7 @@ public final class QuotaController extends StateController { } } @GuardedBy("mLock") private boolean shouldTrackLocked() { final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage(mPkg.packageName, Loading @@ -2132,7 +2148,7 @@ public final class QuotaController extends StateController { final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid); final boolean hasTopAppExemption = !mRegularJobTimer && (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed); return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging()) return !isQuotaFreeLocked(standbyBucket) && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption && !hasTopAppExemption; } Loading Loading @@ -4054,7 +4070,7 @@ public final class QuotaController extends StateController { @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate<JobStatus> predicate) { pw.println("Is charging: " + mChargeTracker.isCharging()); pw.println("Is charging: " + mChargeTracker.isChargingLocked()); pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis()); pw.println(); Loading Loading @@ -4231,7 +4247,8 @@ public final class QuotaController extends StateController { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.QUOTA); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging()); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isChargingLocked()); proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME, sElapsedRealtimeClock.millis()); Loading Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +33 −16 Original line number Diff line number Diff line Loading @@ -621,6 +621,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final long nowElapsed = sElapsedRealtimeClock.millis(); final int userId = jobStatus.getSourceUserId(); Loading Loading @@ -648,6 +649,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void prepareForExecutionLocked(JobStatus jobStatus) { if (DEBUG) { Slog.d(TAG, "Prepping for " + jobStatus.toShortString()); Loading Loading @@ -676,6 +678,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void unprepareFromExecutionLocked(JobStatus jobStatus) { Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); if (timer != null) { Loading @@ -691,6 +694,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { if (jobStatus.clearTrackingController(JobStatus.TRACKING_QUOTA)) { Loading Loading @@ -796,10 +800,12 @@ public final class QuotaController extends StateController { } /** Returns the maximum amount of time this job could run for. */ @GuardedBy("mLock") public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) { if (!jobStatus.shouldTreatAsExpeditedJob()) { // If quota is currently "free", then the job can run for the full amount of time. if (mChargeTracker.isCharging() // If quota is currently "free", then the job can run for the full amount of time, // regardless of bucket (hence using charging instead of isQuotaFreeLocked()). if (mChargeTracker.isChargingLocked() || mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) { Loading @@ -810,7 +816,7 @@ public final class QuotaController extends StateController { } // Expedited job. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; } if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) { Loading @@ -828,8 +834,9 @@ public final class QuotaController extends StateController { } /** @return true if the job is within expedited job quota. */ @GuardedBy("mLock") public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) { if (isQuotaFree(jobStatus.getEffectiveStandbyBucket())) { if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) { return true; } // A job is within quota if one of the following is true: Loading Loading @@ -887,9 +894,10 @@ public final class QuotaController extends StateController { jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket); } private boolean isQuotaFree(final int standbyBucket) { @GuardedBy("mLock") private boolean isQuotaFreeLocked(final int standbyBucket) { // Quota constraint is not enforced while charging. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { // Restricted jobs require additional constraints when charging, so don't immediately // mark quota as free when charging. return standbyBucket != RESTRICTED_INDEX; Loading @@ -898,11 +906,12 @@ public final class QuotaController extends StateController { } @VisibleForTesting @GuardedBy("mLock") boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { if (standbyBucket == NEVER_INDEX) return false; if (isQuotaFree(standbyBucket)) return true; if (isQuotaFreeLocked(standbyBucket)) return true; ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); return getRemainingExecutionTimeLocked(stats) > 0 Loading Loading @@ -1556,9 +1565,9 @@ public final class QuotaController extends StateController { private void handleNewChargingStateLocked() { mTimerChargingUpdateFunctor.setStatus(sElapsedRealtimeClock.millis(), mChargeTracker.isCharging()); mChargeTracker.isChargingLocked()); if (DEBUG) { Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isCharging()); Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isChargingLocked()); } // Deal with Timers first. mEJPkgTimers.forEach(mTimerChargingUpdateFunctor); Loading Loading @@ -1827,6 +1836,7 @@ public final class QuotaController extends StateController { * Track whether we're charging. This has a slightly different definition than that of * BatteryController. */ @GuardedBy("mLock") private boolean mCharging; ChargingTracker() { Loading @@ -1846,7 +1856,8 @@ public final class QuotaController extends StateController { mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); } public boolean isCharging() { @GuardedBy("mLock") public boolean isChargingLocked() { return mCharging; } Loading Loading @@ -2055,9 +2066,12 @@ public final class QuotaController extends StateController { } return; } if (mRunningBgJobs.remove(jobStatus) && !mChargeTracker.isCharging() && mRunningBgJobs.size() == 0) { emitSessionLocked(sElapsedRealtimeClock.millis()); final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage( mPkg.packageName, mPkg.userId, nowElapsed); if (mRunningBgJobs.remove(jobStatus) && mRunningBgJobs.size() == 0 && !isQuotaFreeLocked(standbyBucket)) { emitSessionLocked(nowElapsed); cancelCutoff(); } } Loading @@ -2077,6 +2091,7 @@ public final class QuotaController extends StateController { cancelCutoff(); } @GuardedBy("mLock") private void emitSessionLocked(long nowElapsed) { if (mBgJobCount <= 0) { // Nothing to emit. Loading Loading @@ -2121,6 +2136,7 @@ public final class QuotaController extends StateController { } } @GuardedBy("mLock") private boolean shouldTrackLocked() { final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage(mPkg.packageName, Loading @@ -2132,7 +2148,7 @@ public final class QuotaController extends StateController { final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid); final boolean hasTopAppExemption = !mRegularJobTimer && (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed); return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging()) return !isQuotaFreeLocked(standbyBucket) && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption && !hasTopAppExemption; } Loading Loading @@ -4054,7 +4070,7 @@ public final class QuotaController extends StateController { @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate<JobStatus> predicate) { pw.println("Is charging: " + mChargeTracker.isCharging()); pw.println("Is charging: " + mChargeTracker.isChargingLocked()); pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis()); pw.println(); Loading Loading @@ -4231,7 +4247,8 @@ public final class QuotaController extends StateController { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.QUOTA); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging()); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isChargingLocked()); proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME, sElapsedRealtimeClock.millis()); Loading