Loading apex/jobscheduler/service/aconfig/job.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -109,3 +109,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "allow_cmp_exemption_for_restricted_bucket" namespace: "backstage_power" description: "Allow CMP exemption for apps in Restricted bucket due to timeout reason" bug: "409606405" metadata { purpose: PURPOSE_BUGFIX } } apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +14 −0 Original line number Diff line number Diff line Loading @@ -4725,6 +4725,20 @@ public class JobSchedulerService extends com.android.server.SystemService return bucket; } public static int standbyBucketReasonForPackage(String packageName, int userId, long elapsedNow) { int reason = sUsageStatsManagerInternal != null ? sUsageStatsManagerInternal.getAppStandbyBucketReason(packageName, userId, elapsedNow) : UsageStatsManager.REASON_MAIN_DEFAULT; if (DEBUG_STANDBY) { Slog.v(TAG, packageName + "/" + userId + " standby bucket reason: " + UsageStatsManager.reasonToString(reason)); } return reason; } static int safelyScaleBytesToKBForHistogram(long bytes) { long kilobytes = bytes / 1000; // Anything over Integer.MAX_VALUE or under Integer.MIN_VALUE isn't expected and will Loading apex/jobscheduler/service/java/com/android/server/job/JobStore.java +3 −1 Original line number Diff line number Diff line Loading @@ -1517,9 +1517,11 @@ public final class JobStore { // And now we're done final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName, sourceUserId, nowElapsed); final int appBucketReason = JobSchedulerService.standbyBucketReasonForPackage( sourcePackageName, sourceUserId, nowElapsed); JobStatus js = new JobStatus( builtJob, uid, intern(sourcePackageName), sourceUserId, appBucket, namespace, sourceTag, appBucket, appBucketReason, namespace, sourceTag, elapsedRuntimes.first, elapsedRuntimes.second, lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTime, (rtcIsGood) ? null : rtcRuntimes, internalFlags, /* dynamicConstraints */ 0); Loading apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +63 −20 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.job.controllers; import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; import static com.android.server.job.JobSchedulerService.EXEMPTED_INDEX; import static com.android.server.job.JobSchedulerService.NEVER_INDEX; Loading @@ -34,6 +36,7 @@ import android.app.job.JobScheduler; import android.app.job.JobWorkItem; import android.app.job.PendingJobReasonsInfo; import android.app.job.UserVisibleJobSummary; import android.app.usage.UsageStatsManager; import android.content.ClipData; import android.content.ComponentName; import android.net.Network; Loading Loading @@ -61,6 +64,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.modules.expresslog.Counter; import com.android.server.LocalServices; import com.android.server.job.Flags; import com.android.server.job.GrantedUriPermissions; import com.android.server.job.JobSchedulerInternal; import com.android.server.job.JobSchedulerService; Loading Loading @@ -334,6 +338,11 @@ public final class JobStatus { */ private int standbyBucket; /** * The reason why the app is in the current standby bucket. */ private int mStandbyBucketReason; /** * Whether we've logged an error due to standby bucket mismatch with active uid state. */ Loading Loading @@ -608,6 +617,8 @@ public final class JobStatus { * @param standbyBucket The standby bucket that the source package is currently assigned to, * cached here for speed of handling during runnability evaluations (and updated when bucket * assignments are changed) * @param standbyBucketReason The reason why the app is in the current standby bucket denoted * by {@code standbyBucket}. * @param namespace The custom namespace the app put this job in. * @param tag A string associated with the job for debugging/logging purposes. * @param numFailures Count of how many times this job has requested a reschedule because Loading @@ -625,7 +636,8 @@ public final class JobStatus { * @param internalFlags Non-API property flags about this job */ private JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, int standbyBucket, @Nullable String namespace, String tag, int sourceUserId, int standbyBucket, int standbyBucketReason, @Nullable String namespace, String tag, int numFailures, int mNumAbandonedFailures, int numSystemStops, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs, Loading @@ -633,6 +645,7 @@ public final class JobStatus { int dynamicConstraints) { this.callingUid = callingUid; this.standbyBucket = standbyBucket; this.mStandbyBucketReason = standbyBucketReason; mNamespace = namespace; mNamespaceHash = generateNamespaceHash(namespace); mLoggingJobId = generateLoggingId(namespace, job.getId()); Loading Loading @@ -771,8 +784,8 @@ public final class JobStatus { public JobStatus(JobStatus jobStatus) { this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), jobStatus.getStandbyBucket(), jobStatus.getNamespace(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getStandbyBucket(), jobStatus.getStandbyBucketReason(), jobStatus.getNamespace(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getNumAbandonedFailures(), jobStatus.getNumSystemStops(), jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(), Loading Loading @@ -801,14 +814,14 @@ public final class JobStatus { * standby bucket is whatever the OS thinks it should be at this moment. */ public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId, int standbyBucket, @Nullable String namespace, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, int standbyBucket, int standbyBucketReason, @Nullable String namespace, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs, Pair<Long, Long> persistedExecutionTimesUTC, int innerFlags, int dynamicConstraints) { this(job, callingUid, sourcePkgName, sourceUserId, standbyBucket, namespace, standbyBucket, standbyBucketReason, namespace, sourceTag, /* numFailures */ 0, /* numSystemStops */ 0, /* mNumAbandonedFailures */ 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, Loading Loading @@ -836,8 +849,8 @@ public final class JobStatus { long cumulativeExecutionTimeMs) { this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), rescheduling.getStandbyBucket(), rescheduling.getNamespace(), rescheduling.getSourceTag(), numFailures, rescheduling.getStandbyBucket(), rescheduling.getStandbyBucketReason(), rescheduling.getNamespace(), rescheduling.getSourceTag(), numFailures, mNumAbandonedFailures, numSystemStops, newEarliestRuntimeElapsedMillis, newLatestRuntimeElapsedMillis, Loading Loading @@ -876,8 +889,15 @@ public final class JobStatus { int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage, sourceUserId, elapsedNow); // TODO: b/409606405 - It's possible for where the standby bucket changes between the // time the bucket is queried and the reasoning for the bucket change is queried. // Although the standby bucket change callback will correct this eventually, it'd be // ideal to query the bucket and the reasoning in a single call to prevent potential // temporary inconsistent state. int standbyBucketReason = JobSchedulerService.standbyBucketReasonForPackage( jobPackage, sourceUserId, elapsedNow); return new JobStatus(job, callingUid, sourcePkg, sourceUserId, standbyBucket, namespace, tag, /* numFailures */ 0, standbyBucket, standbyBucketReason, namespace, tag, /* numFailures */ 0, /* mNumAbandonedFailures */ 0, /* numSystemStops */ 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, Loading Loading @@ -1299,16 +1319,7 @@ public final class JobStatus { return ACTIVE_INDEX; } final int bucketWithBackupExemption; if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX && mHasMediaBackupExemption) { // Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since // media backup jobs are important to the user, and the source package may not have // been used directly in a while. bucketWithBackupExemption = Math.min(WORKING_INDEX, actualBucket); } else { bucketWithBackupExemption = actualBucket; } final int bucketWithBackupExemption = getBucketWithBackupExemption(actualBucket); // If the app is considered buggy, but hasn't yet been put in the RESTRICTED bucket // (potentially because it's used frequently by the user), limit its effective bucket Loading @@ -1326,12 +1337,43 @@ public final class JobStatus { return bucketWithBackupExemption; } private int getBucketWithBackupExemption(int actualBucket) { final int standbyBucketMainReason = UsageStatsManager.getMainReason( getStandbyBucketReason()); final int bucketWithBackupExemption; final boolean isBucketEligibleForExemption; if (actualBucket == NEVER_INDEX) { isBucketEligibleForExemption = false; } else if (actualBucket == RESTRICTED_INDEX && (!Flags.allowCmpExemptionForRestrictedBucket() || standbyBucketMainReason != REASON_MAIN_TIMEOUT)) { isBucketEligibleForExemption = false; } else { isBucketEligibleForExemption = true; } if (isBucketEligibleForExemption && mHasMediaBackupExemption) { // Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since // media backup jobs are important to the user, and the source package may not have // been used directly in a while. bucketWithBackupExemption = Math.min(WORKING_INDEX, actualBucket); } else { bucketWithBackupExemption = actualBucket; } return bucketWithBackupExemption; } /** Returns the real standby bucket of the job. */ public int getStandbyBucket() { return standbyBucket; } public void setStandbyBucket(int newBucket) { /** Returns the reason for the standby bucket of the job. */ @VisibleForTesting int getStandbyBucketReason() { return mStandbyBucketReason; } public void setStandbyBucket(int newBucket, int reason) { if (newBucket == RESTRICTED_INDEX) { // Adding to the bucket. addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); Loading @@ -1341,6 +1383,7 @@ public final class JobStatus { } standbyBucket = newBucket; mStandbyBucketReason = reason; mLoggedBucketMismatch = false; } Loading apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +4 −3 Original line number Diff line number Diff line Loading @@ -2531,14 +2531,15 @@ public final class QuotaController extends StateController { // Update job bookkeeping out of band. AppSchedulingModuleThread.getHandler().post(() -> { final int bucketIndex = JobSchedulerService.standbyBucketToBucketIndex(bucket); updateStandbyBucket(userId, packageName, bucketIndex); updateStandbyBucket(userId, packageName, bucketIndex, reason); }); } } @VisibleForTesting void updateStandbyBucket( final int userId, final @NonNull String packageName, final int bucketIndex) { final int userId, final @NonNull String packageName, final int bucketIndex, final int reason) { if (DEBUG) { Slog.i(TAG, "Moving pkg " + packageToString(userId, packageName) + " to bucketIndex " + bucketIndex); Loading @@ -2563,7 +2564,7 @@ public final class QuotaController extends StateController { && bucketIndex != js.getStandbyBucket()) { restrictedChanges.add(js); } js.setStandbyBucket(bucketIndex); js.setStandbyBucket(bucketIndex, reason); } Timer timer = mPkgTimers.get(userId, packageName); if (timer != null && timer.isActive()) { Loading Loading
apex/jobscheduler/service/aconfig/job.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -109,3 +109,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "allow_cmp_exemption_for_restricted_bucket" namespace: "backstage_power" description: "Allow CMP exemption for apps in Restricted bucket due to timeout reason" bug: "409606405" metadata { purpose: PURPOSE_BUGFIX } }
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +14 −0 Original line number Diff line number Diff line Loading @@ -4725,6 +4725,20 @@ public class JobSchedulerService extends com.android.server.SystemService return bucket; } public static int standbyBucketReasonForPackage(String packageName, int userId, long elapsedNow) { int reason = sUsageStatsManagerInternal != null ? sUsageStatsManagerInternal.getAppStandbyBucketReason(packageName, userId, elapsedNow) : UsageStatsManager.REASON_MAIN_DEFAULT; if (DEBUG_STANDBY) { Slog.v(TAG, packageName + "/" + userId + " standby bucket reason: " + UsageStatsManager.reasonToString(reason)); } return reason; } static int safelyScaleBytesToKBForHistogram(long bytes) { long kilobytes = bytes / 1000; // Anything over Integer.MAX_VALUE or under Integer.MIN_VALUE isn't expected and will Loading
apex/jobscheduler/service/java/com/android/server/job/JobStore.java +3 −1 Original line number Diff line number Diff line Loading @@ -1517,9 +1517,11 @@ public final class JobStore { // And now we're done final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName, sourceUserId, nowElapsed); final int appBucketReason = JobSchedulerService.standbyBucketReasonForPackage( sourcePackageName, sourceUserId, nowElapsed); JobStatus js = new JobStatus( builtJob, uid, intern(sourcePackageName), sourceUserId, appBucket, namespace, sourceTag, appBucket, appBucketReason, namespace, sourceTag, elapsedRuntimes.first, elapsedRuntimes.second, lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTime, (rtcIsGood) ? null : rtcRuntimes, internalFlags, /* dynamicConstraints */ 0); Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +63 −20 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.job.controllers; import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; import static com.android.server.job.JobSchedulerService.EXEMPTED_INDEX; import static com.android.server.job.JobSchedulerService.NEVER_INDEX; Loading @@ -34,6 +36,7 @@ import android.app.job.JobScheduler; import android.app.job.JobWorkItem; import android.app.job.PendingJobReasonsInfo; import android.app.job.UserVisibleJobSummary; import android.app.usage.UsageStatsManager; import android.content.ClipData; import android.content.ComponentName; import android.net.Network; Loading Loading @@ -61,6 +64,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.modules.expresslog.Counter; import com.android.server.LocalServices; import com.android.server.job.Flags; import com.android.server.job.GrantedUriPermissions; import com.android.server.job.JobSchedulerInternal; import com.android.server.job.JobSchedulerService; Loading Loading @@ -334,6 +338,11 @@ public final class JobStatus { */ private int standbyBucket; /** * The reason why the app is in the current standby bucket. */ private int mStandbyBucketReason; /** * Whether we've logged an error due to standby bucket mismatch with active uid state. */ Loading Loading @@ -608,6 +617,8 @@ public final class JobStatus { * @param standbyBucket The standby bucket that the source package is currently assigned to, * cached here for speed of handling during runnability evaluations (and updated when bucket * assignments are changed) * @param standbyBucketReason The reason why the app is in the current standby bucket denoted * by {@code standbyBucket}. * @param namespace The custom namespace the app put this job in. * @param tag A string associated with the job for debugging/logging purposes. * @param numFailures Count of how many times this job has requested a reschedule because Loading @@ -625,7 +636,8 @@ public final class JobStatus { * @param internalFlags Non-API property flags about this job */ private JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, int standbyBucket, @Nullable String namespace, String tag, int sourceUserId, int standbyBucket, int standbyBucketReason, @Nullable String namespace, String tag, int numFailures, int mNumAbandonedFailures, int numSystemStops, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs, Loading @@ -633,6 +645,7 @@ public final class JobStatus { int dynamicConstraints) { this.callingUid = callingUid; this.standbyBucket = standbyBucket; this.mStandbyBucketReason = standbyBucketReason; mNamespace = namespace; mNamespaceHash = generateNamespaceHash(namespace); mLoggingJobId = generateLoggingId(namespace, job.getId()); Loading Loading @@ -771,8 +784,8 @@ public final class JobStatus { public JobStatus(JobStatus jobStatus) { this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), jobStatus.getStandbyBucket(), jobStatus.getNamespace(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getStandbyBucket(), jobStatus.getStandbyBucketReason(), jobStatus.getNamespace(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getNumAbandonedFailures(), jobStatus.getNumSystemStops(), jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(), Loading Loading @@ -801,14 +814,14 @@ public final class JobStatus { * standby bucket is whatever the OS thinks it should be at this moment. */ public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId, int standbyBucket, @Nullable String namespace, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, int standbyBucket, int standbyBucketReason, @Nullable String namespace, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs, Pair<Long, Long> persistedExecutionTimesUTC, int innerFlags, int dynamicConstraints) { this(job, callingUid, sourcePkgName, sourceUserId, standbyBucket, namespace, standbyBucket, standbyBucketReason, namespace, sourceTag, /* numFailures */ 0, /* numSystemStops */ 0, /* mNumAbandonedFailures */ 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, Loading Loading @@ -836,8 +849,8 @@ public final class JobStatus { long cumulativeExecutionTimeMs) { this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), rescheduling.getStandbyBucket(), rescheduling.getNamespace(), rescheduling.getSourceTag(), numFailures, rescheduling.getStandbyBucket(), rescheduling.getStandbyBucketReason(), rescheduling.getNamespace(), rescheduling.getSourceTag(), numFailures, mNumAbandonedFailures, numSystemStops, newEarliestRuntimeElapsedMillis, newLatestRuntimeElapsedMillis, Loading Loading @@ -876,8 +889,15 @@ public final class JobStatus { int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage, sourceUserId, elapsedNow); // TODO: b/409606405 - It's possible for where the standby bucket changes between the // time the bucket is queried and the reasoning for the bucket change is queried. // Although the standby bucket change callback will correct this eventually, it'd be // ideal to query the bucket and the reasoning in a single call to prevent potential // temporary inconsistent state. int standbyBucketReason = JobSchedulerService.standbyBucketReasonForPackage( jobPackage, sourceUserId, elapsedNow); return new JobStatus(job, callingUid, sourcePkg, sourceUserId, standbyBucket, namespace, tag, /* numFailures */ 0, standbyBucket, standbyBucketReason, namespace, tag, /* numFailures */ 0, /* mNumAbandonedFailures */ 0, /* numSystemStops */ 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, Loading Loading @@ -1299,16 +1319,7 @@ public final class JobStatus { return ACTIVE_INDEX; } final int bucketWithBackupExemption; if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX && mHasMediaBackupExemption) { // Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since // media backup jobs are important to the user, and the source package may not have // been used directly in a while. bucketWithBackupExemption = Math.min(WORKING_INDEX, actualBucket); } else { bucketWithBackupExemption = actualBucket; } final int bucketWithBackupExemption = getBucketWithBackupExemption(actualBucket); // If the app is considered buggy, but hasn't yet been put in the RESTRICTED bucket // (potentially because it's used frequently by the user), limit its effective bucket Loading @@ -1326,12 +1337,43 @@ public final class JobStatus { return bucketWithBackupExemption; } private int getBucketWithBackupExemption(int actualBucket) { final int standbyBucketMainReason = UsageStatsManager.getMainReason( getStandbyBucketReason()); final int bucketWithBackupExemption; final boolean isBucketEligibleForExemption; if (actualBucket == NEVER_INDEX) { isBucketEligibleForExemption = false; } else if (actualBucket == RESTRICTED_INDEX && (!Flags.allowCmpExemptionForRestrictedBucket() || standbyBucketMainReason != REASON_MAIN_TIMEOUT)) { isBucketEligibleForExemption = false; } else { isBucketEligibleForExemption = true; } if (isBucketEligibleForExemption && mHasMediaBackupExemption) { // Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since // media backup jobs are important to the user, and the source package may not have // been used directly in a while. bucketWithBackupExemption = Math.min(WORKING_INDEX, actualBucket); } else { bucketWithBackupExemption = actualBucket; } return bucketWithBackupExemption; } /** Returns the real standby bucket of the job. */ public int getStandbyBucket() { return standbyBucket; } public void setStandbyBucket(int newBucket) { /** Returns the reason for the standby bucket of the job. */ @VisibleForTesting int getStandbyBucketReason() { return mStandbyBucketReason; } public void setStandbyBucket(int newBucket, int reason) { if (newBucket == RESTRICTED_INDEX) { // Adding to the bucket. addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); Loading @@ -1341,6 +1383,7 @@ public final class JobStatus { } standbyBucket = newBucket; mStandbyBucketReason = reason; mLoggedBucketMismatch = false; } Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +4 −3 Original line number Diff line number Diff line Loading @@ -2531,14 +2531,15 @@ public final class QuotaController extends StateController { // Update job bookkeeping out of band. AppSchedulingModuleThread.getHandler().post(() -> { final int bucketIndex = JobSchedulerService.standbyBucketToBucketIndex(bucket); updateStandbyBucket(userId, packageName, bucketIndex); updateStandbyBucket(userId, packageName, bucketIndex, reason); }); } } @VisibleForTesting void updateStandbyBucket( final int userId, final @NonNull String packageName, final int bucketIndex) { final int userId, final @NonNull String packageName, final int bucketIndex, final int reason) { if (DEBUG) { Slog.i(TAG, "Moving pkg " + packageToString(userId, packageName) + " to bucketIndex " + bucketIndex); Loading @@ -2563,7 +2564,7 @@ public final class QuotaController extends StateController { && bucketIndex != js.getStandbyBucket()) { restrictedChanges.add(js); } js.setStandbyBucket(bucketIndex); js.setStandbyBucket(bucketIndex, reason); } Timer timer = mPkgTimers.get(userId, packageName); if (timer != null && timer.isActive()) { Loading