diff options
| author | 2019-04-05 15:51:42 -0700 | |
|---|---|---|
| committer | 2019-07-30 15:18:02 -0700 | |
| commit | ef7eef60c9c9998266a181e24765aeeb76760b6b (patch) | |
| tree | e06e8f99f32f3bcb7fd2b4b56172975cd4b49581 | |
| parent | dec3796249e0578d938c4727063cb86feaee29d2 (diff) | |
Fix job persistence & re-inflation
We were persisting jobs' battery-not-low constraints but were not
properly restoring that constraint when the job was inflated at boot.
This could result in a runtime bootloop (!) if the job had no other
constraints, requiring a factory reset to restore the device to
usability.
We now:
* properly inflate the battery-not-low constraint;
* persist & inflate the storage-not-low constraint, which previously was
being stripped entirely and could result in a similar crash-at-boot;
* ignore the job rather than crash the system if one is inflated into
a non-viable state; and
* formally test previously-untested constraint persistence
Bug: 130012063
Test: atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
Test: atest CtsJobSchedulerTestCases
Test: JobStoreTest with forced throw in JobInfo.Builder#build()
Change-Id: Ia3ab1eb16aeaa85336409368b4340622cec19f4c
Merged-In: Ia3ab1eb16aeaa85336409368b4340622cec19f4c
3 files changed, 106 insertions, 0 deletions
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index 556ffa24368f..1c1fad3beb8c 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -1592,5 +1592,15 @@ public class JobInfo implements Parcelable { } return new JobInfo(this); } + + /** + * @hide + */ + public String summarize() { + final String service = (mJobService != null) + ? mJobService.flattenToShortString() + : "null"; + return "JobInfo.Builder{job:" + mJobId + "/" + service + "}"; + } } } diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index 4f8b1dcc6bb4..dad435bf6209 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -492,6 +492,9 @@ public final class JobStore { if (jobStatus.hasBatteryNotLowConstraint()) { out.attribute(null, "battery-not-low", Boolean.toString(true)); } + if (jobStatus.hasStorageNotLowConstraint()) { + out.attribute(null, "storage-not-low", Boolean.toString(true)); + } out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS); } @@ -852,6 +855,15 @@ public final class JobStore { jobBuilder.setExtras(extras); parser.nextTag(); // Consume </extras> + final JobInfo builtJob; + try { + builtJob = jobBuilder.build(); + } catch (Exception e) { + Slog.w(TAG, "Unable to build job from XML, ignoring: " + + jobBuilder.summarize()); + return null; + } + // Migrate sync jobs forward from earlier, incomplete representation if ("android".equals(sourcePackageName) && extras != null @@ -935,6 +947,14 @@ public final class JobStore { if (val != null) { jobBuilder.setRequiresCharging(true); } + val = parser.getAttributeValue(null, "battery-not-low"); + if (val != null) { + jobBuilder.setRequiresBatteryNotLow(true); + } + val = parser.getAttributeValue(null, "storage-not-low"); + if (val != null) { + jobBuilder.setRequiresStorageNotLow(true); + } } /** diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index 543f51cba41f..6fa5cd296923 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -382,6 +382,82 @@ public class JobStoreTest { .build()); } + @Test + public void testPersistedIdleConstraint() throws Exception { + JobInfo.Builder b = new Builder(8, mComponent) + .setRequiresDeviceIdle(true) + .setPersisted(true); + JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); + + mTaskStoreUnderTest.add(taskStatus); + waitForPendingIo(); + + final JobSet jobStatusSet = new JobSet(); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); + assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); + JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); + assertEquals("Idle constraint not persisted correctly.", + loaded.getJob().isRequireDeviceIdle(), + taskStatus.getJob().isRequireDeviceIdle()); + } + + @Test + public void testPersistedChargingConstraint() throws Exception { + JobInfo.Builder b = new Builder(8, mComponent) + .setRequiresCharging(true) + .setPersisted(true); + JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); + + mTaskStoreUnderTest.add(taskStatus); + waitForPendingIo(); + + final JobSet jobStatusSet = new JobSet(); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); + assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); + JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); + assertEquals("Charging constraint not persisted correctly.", + loaded.getJob().isRequireCharging(), + taskStatus.getJob().isRequireCharging()); + } + + @Test + public void testPersistedStorageNotLowConstraint() throws Exception { + JobInfo.Builder b = new Builder(8, mComponent) + .setRequiresStorageNotLow(true) + .setPersisted(true); + JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); + + mTaskStoreUnderTest.add(taskStatus); + waitForPendingIo(); + + final JobSet jobStatusSet = new JobSet(); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); + assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); + JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); + assertEquals("Storage-not-low constraint not persisted correctly.", + loaded.getJob().isRequireStorageNotLow(), + taskStatus.getJob().isRequireStorageNotLow()); + } + + @Test + public void testPersistedBatteryNotLowConstraint() throws Exception { + JobInfo.Builder b = new Builder(8, mComponent) + .setRequiresBatteryNotLow(true) + .setPersisted(true); + JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); + + mTaskStoreUnderTest.add(taskStatus); + waitForPendingIo(); + + final JobSet jobStatusSet = new JobSet(); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); + assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); + JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); + assertEquals("Battery-not-low constraint not persisted correctly.", + loaded.getJob().isRequireBatteryNotLow(), + taskStatus.getJob().isRequireBatteryNotLow()); + } + /** * Helper function to kick a {@link JobInfo} through a persistence cycle and * assert that it's unchanged. |