diff options
| -rw-r--r-- | apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java | 18 | ||||
| -rw-r--r-- | apex/jobscheduler/service/java/com/android/server/job/JobStore.java | 29 |
2 files changed, 43 insertions, 4 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 671608f0b11a..43f727936b1f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -153,6 +153,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import java.util.function.Predicate; @@ -242,6 +243,7 @@ public class JobSchedulerService extends com.android.server.SystemService final Object mLock = new Object(); /** Master list of jobs. */ final JobStore mJobs; + private final CountDownLatch mJobStoreLoadedLatch; /** Tracking the standby bucket state of each app */ final StandbyTracker mStandbyTracker; /** Tracking amount of time each package runs for. */ @@ -2044,7 +2046,9 @@ public class JobSchedulerService extends com.android.server.SystemService publishLocalService(JobSchedulerInternal.class, new LocalService()); // Initialize the job store and set up any persisted jobs - mJobs = JobStore.initAndGet(this); + mJobStoreLoadedLatch = new CountDownLatch(1); + mJobs = JobStore.get(this); + mJobs.initAsync(mJobStoreLoadedLatch); mBatteryStateTracker = new BatteryStateTracker(); mBatteryStateTracker.startTracking(); @@ -2112,7 +2116,7 @@ public class JobSchedulerService extends com.android.server.SystemService // And kick off the work to update the affected jobs, using a secondary // thread instead of chugging away here on the main looper thread. - new Thread(mJobTimeUpdater, "JobSchedulerTimeSetReceiver").start(); + mJobs.runWorkAsync(mJobTimeUpdater); } } } @@ -2150,7 +2154,15 @@ public class JobSchedulerService extends com.android.server.SystemService @Override public void onBootPhase(int phase) { - if (PHASE_SYSTEM_SERVICES_READY == phase) { + if (PHASE_LOCK_SETTINGS_READY == phase) { + // This is the last phase before PHASE_SYSTEM_SERVICES_READY. We need to ensure that + // persisted jobs are loaded before we can proceed to PHASE_SYSTEM_SERVICES_READY. + try { + mJobStoreLoadedLatch.await(); + } catch (InterruptedException e) { + Slog.e(TAG, "Couldn't wait on job store loading latch"); + } + } else if (PHASE_SYSTEM_SERVICES_READY == phase) { mConstantsObserver.start(); for (StateController controller : mControllers) { controller.onSystemServicesReady(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index 9ec74e5f3cec..0dcb0b2456d6 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -70,6 +70,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.StringJoiner; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import java.util.function.Predicate; @@ -131,7 +132,7 @@ public final class JobStore { private JobStorePersistStats mPersistInfo = new JobStorePersistStats(); /** Used by the {@link JobSchedulerService} to instantiate the JobStore. */ - static JobStore initAndGet(JobSchedulerService jobManagerService) { + static JobStore get(JobSchedulerService jobManagerService) { synchronized (sSingletonLock) { if (sSingleton == null) { sSingleton = new JobStore(jobManagerService.getContext(), @@ -147,6 +148,7 @@ public final class JobStore { @VisibleForTesting public static JobStore initAndGetForTesting(Context context, File dataDir) { JobStore jobStoreUnderTest = new JobStore(context, new Object(), dataDir); + jobStoreUnderTest.init(); jobStoreUnderTest.clearForTesting(); return jobStoreUnderTest; } @@ -181,10 +183,16 @@ public final class JobStore { mXmlTimestamp = mJobsFile.exists() ? mJobsFile.getLastModifiedTime() : mJobFileDirectory.lastModified(); mRtcGood = (sSystemClock.millis() > mXmlTimestamp); + } + private void init() { readJobMapFromDisk(mJobSet, mRtcGood); } + void initAsync(CountDownLatch completionLatch) { + mIoHandler.post(new ReadJobMapFromDiskRunnable(mJobSet, mRtcGood, completionLatch)); + } + private AtomicFile createJobFile(String baseName) { return createJobFile(new File(mJobFileDirectory, baseName + ".xml")); } @@ -202,6 +210,15 @@ public final class JobStore { } /** + * Runs any necessary work asynchronously. If this is called after + * {@link #initAsync(CountDownLatch)}, this ensures the given work runs after + * the JobStore is initialized. + */ + void runWorkAsync(@NonNull Runnable r) { + mIoHandler.post(r); + } + + /** * Find all the jobs that were affected by RTC clock uncertainty at boot time. Returns * parallel lists of the existing JobStatus objects and of new, equivalent JobStatus instances * with now-corrected time bounds. @@ -998,14 +1015,21 @@ public final class JobStore { private final class ReadJobMapFromDiskRunnable implements Runnable { private final JobSet jobSet; private final boolean rtcGood; + private final CountDownLatch mCompletionLatch; /** * @param jobSet Reference to the (empty) set of JobStatus objects that back the JobStore, * so that after disk read we can populate it directly. */ ReadJobMapFromDiskRunnable(JobSet jobSet, boolean rtcIsGood) { + this(jobSet, rtcIsGood, null); + } + + ReadJobMapFromDiskRunnable(JobSet jobSet, boolean rtcIsGood, + @Nullable CountDownLatch completionLatch) { this.jobSet = jobSet; this.rtcGood = rtcIsGood; + this.mCompletionLatch = completionLatch; } @Override @@ -1088,6 +1112,9 @@ public final class JobStore { if (needFileMigration) { migrateJobFilesAsync(); } + if (mCompletionLatch != null) { + mCompletionLatch.countDown(); + } } private List<JobStatus> readJobMapImpl(InputStream fis, boolean rtcIsGood, long nowElapsed) |