Loading apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -3033,6 +3033,10 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; return 0; } } void resetExecutionQuota(@NonNull String pkgName, int userId) { mQuotaController.clearAppStats(pkgName, userId); } void resetScheduleQuota() { void resetScheduleQuota() { mQuotaTracker.clear(); mQuotaTracker.clear(); } } Loading apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +36 −0 Original line number Original line Diff line number Diff line Loading @@ -66,6 +66,8 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { return getJobState(pw); return getJobState(pw); case "heartbeat": case "heartbeat": return doHeartbeat(pw); return doHeartbeat(pw); case "reset-execution-quota": return resetExecutionQuota(pw); case "reset-schedule-quota": case "reset-schedule-quota": return resetScheduleQuota(pw); return resetScheduleQuota(pw); case "trigger-dock-state": case "trigger-dock-state": Loading Loading @@ -346,6 +348,40 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { return -1; return -1; } } private int resetExecutionQuota(PrintWriter pw) throws Exception { checkPermission("reset execution quota"); int userId = UserHandle.USER_SYSTEM; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-u": case "--user": userId = UserHandle.parseUserArg(getNextArgRequired()); break; default: pw.println("Error: unknown option '" + opt + "'"); return -1; } } if (userId == UserHandle.USER_CURRENT) { userId = ActivityManager.getCurrentUser(); } final String pkgName = getNextArgRequired(); final long ident = Binder.clearCallingIdentity(); try { mInternal.resetExecutionQuota(pkgName, userId); } finally { Binder.restoreCallingIdentity(ident); } return 0; } private int resetScheduleQuota(PrintWriter pw) throws Exception { private int resetScheduleQuota(PrintWriter pw) throws Exception { checkPermission("reset schedule quota"); checkPermission("reset schedule quota"); Loading apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java +5 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.job.controllers; package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.NEVER_INDEX; import android.os.SystemClock; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserHandle; import android.util.Log; import android.util.Log; Loading Loading @@ -196,6 +198,9 @@ public final class BackgroundJobsController extends StateController { } else { } else { isActive = (activeState == KNOWN_ACTIVE); isActive = (activeState == KNOWN_ACTIVE); } } if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) { Slog.wtf(TAG, "App became active but still in NEVER bucket"); } boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun); boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun); didChange |= jobStatus.setUidActive(isActive); didChange |= jobStatus.setUidActive(isActive); return didChange; return didChange; Loading apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -1271,7 +1271,8 @@ public final class JobStatus { // sessions (exempt from dynamic restrictions), we need the additional check to ensure // sessions (exempt from dynamic restrictions), we need the additional check to ensure // that NEVER jobs don't run. // that NEVER jobs don't run. // TODO: cleanup quota and standby bucket management so we don't need the additional checks // TODO: cleanup quota and standby bucket management so we don't need the additional checks if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || standbyBucket == NEVER_INDEX) { if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || getEffectiveStandbyBucket() == NEVER_INDEX) { return false; return false; } } // Deadline constraint trumps other constraints besides quota and dynamic (except for // Deadline constraint trumps other constraints besides quota and dynamic (except for Loading apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +18 −14 Original line number Original line Diff line number Diff line Loading @@ -579,12 +579,28 @@ public final class QuotaController extends StateController { Slog.wtf(TAG, "Told app removed but given null package name."); Slog.wtf(TAG, "Told app removed but given null package name."); return; return; } } final int userId = UserHandle.getUserId(uid); clearAppStats(packageName, UserHandle.getUserId(uid)); mForegroundUids.delete(uid); mUidToPackageCache.remove(uid); } @Override public void onUserRemovedLocked(int userId) { mTrackedJobs.delete(userId); mPkgTimers.delete(userId); mTimingSessions.delete(userId); mInQuotaAlarmListeners.delete(userId); mExecutionStatsCache.delete(userId); mUidToPackageCache.clear(); } /** Drop all historical stats and stop tracking any active sessions for the specified app. */ public void clearAppStats(@NonNull String packageName, int userId) { mTrackedJobs.delete(userId, packageName); mTrackedJobs.delete(userId, packageName); Timer timer = mPkgTimers.get(userId, packageName); Timer timer = mPkgTimers.get(userId, packageName); if (timer != null) { if (timer != null) { if (timer.isActive()) { if (timer.isActive()) { Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off."); Slog.e(TAG, "clearAppStats called before Timer turned off."); timer.dropEverythingLocked(); timer.dropEverythingLocked(); } } mPkgTimers.delete(userId, packageName); mPkgTimers.delete(userId, packageName); Loading @@ -596,18 +612,6 @@ public final class QuotaController extends StateController { mInQuotaAlarmListeners.delete(userId, packageName); mInQuotaAlarmListeners.delete(userId, packageName); } } mExecutionStatsCache.delete(userId, packageName); mExecutionStatsCache.delete(userId, packageName); mForegroundUids.delete(uid); mUidToPackageCache.remove(uid); } @Override public void onUserRemovedLocked(int userId) { mTrackedJobs.delete(userId); mPkgTimers.delete(userId); mTimingSessions.delete(userId); mInQuotaAlarmListeners.delete(userId); mExecutionStatsCache.delete(userId); mUidToPackageCache.clear(); } } private boolean isUidInForeground(int uid) { private boolean isUidInForeground(int uid) { Loading Loading
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -3033,6 +3033,10 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; return 0; } } void resetExecutionQuota(@NonNull String pkgName, int userId) { mQuotaController.clearAppStats(pkgName, userId); } void resetScheduleQuota() { void resetScheduleQuota() { mQuotaTracker.clear(); mQuotaTracker.clear(); } } Loading
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +36 −0 Original line number Original line Diff line number Diff line Loading @@ -66,6 +66,8 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { return getJobState(pw); return getJobState(pw); case "heartbeat": case "heartbeat": return doHeartbeat(pw); return doHeartbeat(pw); case "reset-execution-quota": return resetExecutionQuota(pw); case "reset-schedule-quota": case "reset-schedule-quota": return resetScheduleQuota(pw); return resetScheduleQuota(pw); case "trigger-dock-state": case "trigger-dock-state": Loading Loading @@ -346,6 +348,40 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { return -1; return -1; } } private int resetExecutionQuota(PrintWriter pw) throws Exception { checkPermission("reset execution quota"); int userId = UserHandle.USER_SYSTEM; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-u": case "--user": userId = UserHandle.parseUserArg(getNextArgRequired()); break; default: pw.println("Error: unknown option '" + opt + "'"); return -1; } } if (userId == UserHandle.USER_CURRENT) { userId = ActivityManager.getCurrentUser(); } final String pkgName = getNextArgRequired(); final long ident = Binder.clearCallingIdentity(); try { mInternal.resetExecutionQuota(pkgName, userId); } finally { Binder.restoreCallingIdentity(ident); } return 0; } private int resetScheduleQuota(PrintWriter pw) throws Exception { private int resetScheduleQuota(PrintWriter pw) throws Exception { checkPermission("reset schedule quota"); checkPermission("reset schedule quota"); Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java +5 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.job.controllers; package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.NEVER_INDEX; import android.os.SystemClock; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserHandle; import android.util.Log; import android.util.Log; Loading Loading @@ -196,6 +198,9 @@ public final class BackgroundJobsController extends StateController { } else { } else { isActive = (activeState == KNOWN_ACTIVE); isActive = (activeState == KNOWN_ACTIVE); } } if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) { Slog.wtf(TAG, "App became active but still in NEVER bucket"); } boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun); boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun); didChange |= jobStatus.setUidActive(isActive); didChange |= jobStatus.setUidActive(isActive); return didChange; return didChange; Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -1271,7 +1271,8 @@ public final class JobStatus { // sessions (exempt from dynamic restrictions), we need the additional check to ensure // sessions (exempt from dynamic restrictions), we need the additional check to ensure // that NEVER jobs don't run. // that NEVER jobs don't run. // TODO: cleanup quota and standby bucket management so we don't need the additional checks // TODO: cleanup quota and standby bucket management so we don't need the additional checks if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || standbyBucket == NEVER_INDEX) { if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || getEffectiveStandbyBucket() == NEVER_INDEX) { return false; return false; } } // Deadline constraint trumps other constraints besides quota and dynamic (except for // Deadline constraint trumps other constraints besides quota and dynamic (except for Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +18 −14 Original line number Original line Diff line number Diff line Loading @@ -579,12 +579,28 @@ public final class QuotaController extends StateController { Slog.wtf(TAG, "Told app removed but given null package name."); Slog.wtf(TAG, "Told app removed but given null package name."); return; return; } } final int userId = UserHandle.getUserId(uid); clearAppStats(packageName, UserHandle.getUserId(uid)); mForegroundUids.delete(uid); mUidToPackageCache.remove(uid); } @Override public void onUserRemovedLocked(int userId) { mTrackedJobs.delete(userId); mPkgTimers.delete(userId); mTimingSessions.delete(userId); mInQuotaAlarmListeners.delete(userId); mExecutionStatsCache.delete(userId); mUidToPackageCache.clear(); } /** Drop all historical stats and stop tracking any active sessions for the specified app. */ public void clearAppStats(@NonNull String packageName, int userId) { mTrackedJobs.delete(userId, packageName); mTrackedJobs.delete(userId, packageName); Timer timer = mPkgTimers.get(userId, packageName); Timer timer = mPkgTimers.get(userId, packageName); if (timer != null) { if (timer != null) { if (timer.isActive()) { if (timer.isActive()) { Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off."); Slog.e(TAG, "clearAppStats called before Timer turned off."); timer.dropEverythingLocked(); timer.dropEverythingLocked(); } } mPkgTimers.delete(userId, packageName); mPkgTimers.delete(userId, packageName); Loading @@ -596,18 +612,6 @@ public final class QuotaController extends StateController { mInQuotaAlarmListeners.delete(userId, packageName); mInQuotaAlarmListeners.delete(userId, packageName); } } mExecutionStatsCache.delete(userId, packageName); mExecutionStatsCache.delete(userId, packageName); mForegroundUids.delete(uid); mUidToPackageCache.remove(uid); } @Override public void onUserRemovedLocked(int userId) { mTrackedJobs.delete(userId); mPkgTimers.delete(userId); mTimingSessions.delete(userId); mInQuotaAlarmListeners.delete(userId); mExecutionStatsCache.delete(userId); mUidToPackageCache.clear(); } } private boolean isUidInForeground(int uid) { private boolean isUidInForeground(int uid) { Loading