summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java18
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java29
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)