From 44b50853a2c075147fb59cc94aeffb468d3b4b6f Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Fri, 5 Oct 2018 15:53:50 -0700 Subject: [PATCH] Fix persisted job handling in bad-boot-RTC situations Persisted jobs were inadvertently being discarded rather than rescheduled with appropriate time constraints. The underlying bug is that the cancel-with-replacement code path was failing to manage the replacement properly, and the other code path leading to it was working around the bug by explicitly rescheduling the job following cancellation. Test: atest CtsJobSchedulerTestCases Bug: 114292041 Bug: 117346686 Change-Id: I3a77e8a38c2f7028b61791bafd9c88b7a714ff6d (cherry picked from commit 1603204ba5392d375e05ecf2c5b2fea7309f4cf1) --- .../server/job/JobSchedulerService.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 0b7c5b943e5ef..7e23ee9b4beef 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -876,14 +876,17 @@ public class JobSchedulerService extends com.android.server.SystemService // This may throw a SecurityException. jobStatus.prepareLocked(ActivityManager.getService()); - if (toCancel != null) { - cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app"); - } if (work != null) { // If work has been supplied, enqueue it into the new job. jobStatus.enqueueWorkLocked(ActivityManager.getService(), work); } - startTrackingJobLocked(jobStatus, toCancel); + + if (toCancel != null) { + // Implicitly replaces the existing job record with the new instance + cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app"); + } else { + startTrackingJobLocked(jobStatus, null); + } StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED, uId, null, jobStatus.getBatteryName(), StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED, @@ -1012,6 +1015,12 @@ public class JobSchedulerService extends com.android.server.SystemService } } + /** + * Cancel the given job, stopping it if it's currently executing. If {@code incomingJob} + * is null, the cancelled job is removed outright from the system. If + * {@code incomingJob} is non-null, it replaces {@code cancelled} in the store of + * currently scheduled jobs. + */ private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) { if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString()); cancelled.unprepareLocked(ActivityManager.getService()); @@ -1022,6 +1031,11 @@ public class JobSchedulerService extends com.android.server.SystemService } // Cancel if running. stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED, reason); + // If this is a replacement, bring in the new version of the job + if (incomingJob != null) { + if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString()); + startTrackingJobLocked(incomingJob, cancelled); + } reportActiveLocked(); }