}
public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
- JobStatus jobStatus = new JobStatus(job, uId);
- if (packageName != null) {
- jobStatus.setSource(packageName, userId);
- }
+ JobStatus jobStatus = new JobStatus(job, uId, packageName, userId);
try {
if (ActivityManagerNative.getDefault().getAppStartMode(uId,
job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
continue;
}
- JobStatus copy = new JobStatus(jobStatus.getJob(), jobStatus.getUid(),
- jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
+ JobStatus copy = new JobStatus(jobStatus);
mStoreCopy.add(copy);
}
}
private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
IOException {
JobInfo.Builder jobBuilder;
- int uid, userId;
+ int uid, sourceUserId;
// Read out job identifier attributes and priority.
try {
jobBuilder.setPriority(Integer.valueOf(val));
}
val = parser.getAttributeValue(null, "sourceUserId");
- userId = val == null ? -1 : Integer.valueOf(val);
+ sourceUserId = val == null ? -1 : Integer.valueOf(val);
} catch (NumberFormatException e) {
Slog.e(TAG, "Error parsing job's required fields, skipping");
return null;
try {
String val = parser.getAttributeValue(null, "period");
final long periodMillis = Long.valueOf(val);
- jobBuilder.setPeriodic(periodMillis);
val = parser.getAttributeValue(null, "flex");
final long flexMillis = (val != null) ? Long.valueOf(val) : periodMillis;
+ jobBuilder.setPeriodic(periodMillis, flexMillis);
// As a sanity check, cap the recreated run time to be no later than flex+period
// from now. This is the latest the periodic could be pushed out. This could
// happen if the periodic ran early (at flex time before period), and then the
parser.nextTag(); // Consume </extras>
JobStatus js = new JobStatus(
- jobBuilder.build(), uid, elapsedRuntimes.first, elapsedRuntimes.second);
- if (userId != -1) {
- js.setSource(sourcePackageName, userId);
- }
+ jobBuilder.build(), uid, sourcePackageName, sourceUserId, elapsedRuntimes.first,
+ elapsedRuntimes.second);
return js;
}
final JobInfo job;
/** Uid of the package requesting this job. */
- final int uId;
+ final int callingUid;
final String name;
final String tag;
- String sourcePackageName;
- int sourceUserId = -1;
- int sourceUid = -1;
+ final String sourcePackageName;
+ final int sourceUserId;
+ final int sourceUid;
// Constraints.
final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
/** Provide a handle to the service that this job will be run on. */
public int getServiceToken() {
- return uId;
+ return callingUid;
}
- private JobStatus(JobInfo job, int uId, int numFailures) {
+ private JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
+ int numFailures) {
this.job = job;
- this.uId = uId;
- this.sourceUid = uId;
+ this.callingUid = callingUid;
this.name = job.getService().flattenToShortString();
this.tag = "*job*/" + this.name;
this.numFailures = numFailures;
+
+ int tempSourceUid = -1;
+ if (sourceUserId != -1 && sourcePackageName != null) {
+ try {
+ tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
+ sourceUserId);
+ } catch (RemoteException ex) {
+ // Can't happen, PackageManager runs in the same process.
+ }
+ }
+ if (tempSourceUid == -1) {
+ this.sourceUid = callingUid;
+ this.sourceUserId = UserHandle.getUserId(callingUid);
+ this.sourcePackageName = job.getService().getPackageName();
+ } else {
+ this.sourceUid = tempSourceUid;
+ this.sourceUserId = sourceUserId;
+ this.sourcePackageName = sourcePackageName;
+ }
}
/** Copy constructor. */
public JobStatus(JobStatus jobStatus) {
- this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getNumFailures());
- this.sourceUserId = jobStatus.sourceUserId;
- this.sourcePackageName = jobStatus.sourcePackageName;
+ this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(),
+ jobStatus.getSourceUserId(), jobStatus.getNumFailures());
this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
}
- /** Create a newly scheduled job. */
- public JobStatus(JobInfo job, int uId) {
- this(job, uId, 0);
+ /**
+ * Create a newly scheduled job.
+ * @param callingUid Uid of the package that scheduled this job.
+ * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
+ * the calling package is the source.
+ * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
+ * calling userId.
+ */
+ public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId) {
+ this(job, callingUid, sourcePackageName, sourceUserId, 0);
final long elapsedNow = SystemClock.elapsedRealtime();
* wallclock runtime rather than resetting it on every boot.
* We consider a freshly loaded job to no longer be in back-off.
*/
- public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis,
- long latestRunTimeElapsedMillis) {
- this(job, uId, 0);
+ public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
+ long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+ this(job, callingUid, sourcePackageName, sourceUserId, 0);
this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
/** Create a new job to be rescheduled with the provided parameters. */
public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int backoffAttempt) {
- this(rescheduling.job, rescheduling.getUid(), backoffAttempt);
- this.sourceUserId = rescheduling.sourceUserId;
- this.sourcePackageName = rescheduling.sourcePackageName;
+ this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(),
+ rescheduling.getSourceUserId(), backoffAttempt);
earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
}
public String getSourcePackageName() {
- return sourcePackageName != null ? sourcePackageName : job.getService().getPackageName();
+ return sourcePackageName;
}
public int getSourceUid() {
}
public int getSourceUserId() {
- if (sourceUserId == -1) {
- sourceUserId = getUserId();
- }
return sourceUserId;
}
public int getUserId() {
- return UserHandle.getUserId(uId);
+ return UserHandle.getUserId(callingUid);
}
public int getUid() {
- return uId;
+ return callingUid;
}
public String getName() {
}
public boolean matches(int uid, int jobId) {
- return this.job.getId() == jobId && this.uId == uid;
+ return this.job.getId() == jobId && this.callingUid == uid;
}
@Override
}
}
- public void setSource(String sourcePackageName, int sourceUserId) {
- this.sourcePackageName = sourcePackageName;
- this.sourceUserId = sourceUserId;
- try {
- sourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
- sourceUserId);
- } catch (RemoteException ex) {
- // Can't happen, PackageManager runs in the same process.
- }
- if (sourceUid == -1) {
- sourceUid = uId;
- this.sourceUserId = getUserId();
- this.sourcePackageName = null;
- }
- }
-
/**
* Convenience function to identify a job uniquely without pulling all the data that
* {@link #toString()} returns.
sb.append(" jId=");
sb.append(job.getId());
sb.append(" uid=");
- UserHandle.formatUid(sb, uId);
+ UserHandle.formatUid(sb, callingUid);
sb.append(' ');
sb.append(job.getService().flattenToShortString());
return sb.toString();
// Dumpsys infrastructure
public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); UserHandle.formatUid(pw, uId);
+ pw.print(prefix); UserHandle.formatUid(pw, callingUid);
pw.print(" tag="); pw.println(tag);
pw.print(prefix);
pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
.setMinimumLatency(runFromMillis)
.setPersisted(true)
.build();
- final JobStatus ts = new JobStatus(task, SOME_UID);
+ final JobStatus ts = new JobStatus(task, SOME_UID, null, -1);
mTaskStoreUnderTest.add(ts);
Thread.sleep(IO_WAIT);
// Manually load tasks from xml file.
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPersisted(true)
.build();
- final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID);
- final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID);
+ final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID, null, -1);
+ final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID, null, -1);
mTaskStoreUnderTest.add(taskStatus1);
mTaskStoreUnderTest.add(taskStatus2);
Thread.sleep(IO_WAIT);
extras.putInt("into", 3);
b.setExtras(extras);
final JobInfo task = b.build();
- JobStatus taskStatus = new JobStatus(task, SOME_UID);
+ JobStatus taskStatus = new JobStatus(task, SOME_UID, null, -1);
mTaskStoreUnderTest.add(taskStatus);
Thread.sleep(IO_WAIT);
JobStatus loaded = jobStatusSet.iterator().next();
assertTasksEqual(task, loaded.getJob());
}
+ public void testWritingTaskWithSourcePackage() throws Exception {
+ JobInfo.Builder b = new Builder(8, mComponent)
+ .setRequiresDeviceIdle(true)
+ .setPeriodic(10000L)
+ .setRequiresCharging(true)
+ .setPersisted(true);
+ JobStatus taskStatus = new JobStatus(b.build(), SOME_UID, "com.google.android.gms", 0);
+
+ mTaskStoreUnderTest.add(taskStatus);
+ Thread.sleep(IO_WAIT);
+
+ final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+ assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
+ JobStatus loaded = jobStatusSet.iterator().next();
+ assertEquals("Source package not equal.", loaded.getSourcePackageName(),
+ taskStatus.getSourcePackageName());
+ assertEquals("Source user not equal.", loaded.getSourceUserId(),
+ taskStatus.getSourceUserId());
+ }
+
+ public void testWritingTaskWithFlex() throws Exception {
+ JobInfo.Builder b = new Builder(8, mComponent)
+ .setRequiresDeviceIdle(true)
+ .setPeriodic(5*60*60*1000, 1*60*60*1000)
+ .setRequiresCharging(true)
+ .setPersisted(true);
+ JobStatus taskStatus = new JobStatus(b.build(), SOME_UID, null, -1);
+
+ mTaskStoreUnderTest.add(taskStatus);
+ Thread.sleep(IO_WAIT);
+
+ final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+ assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
+ JobStatus loaded = jobStatusSet.iterator().next();
+ assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(),
+ taskStatus.getJob().getIntervalMillis());
+ assertEquals("Flex not equal.", loaded.getJob().getFlexMillis(),
+ taskStatus.getJob().getFlexMillis());
+ }
public void testMassivePeriodClampedOnRead() throws Exception {
- final long TEN_SECONDS = 10000L;
+ final long ONE_HOUR = 60*60*1000L; // flex
+ final long TWO_HOURS = 2 * ONE_HOUR; // period
JobInfo.Builder b = new Builder(8, mComponent)
- .setPeriodic(TEN_SECONDS)
+ .setPeriodic(TWO_HOURS, ONE_HOUR)
.setPersisted(true);
final long invalidLateRuntimeElapsedMillis =
- SystemClock.elapsedRealtime() + (TEN_SECONDS * 2) + 5000; // >2P from now.
+ SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS; // > period+flex
final long invalidEarlyRuntimeElapsedMillis =
- invalidLateRuntimeElapsedMillis - TEN_SECONDS; // Early is (late - period).
- final JobStatus js = new JobStatus(b.build(), SOME_UID,
+ invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period).
+ final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", 0 /* sourceUserId */,
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
mTaskStoreUnderTest.add(js);
// call SystemClock.elapsedRealtime after doing the disk i/o.
final long newNowElapsed = SystemClock.elapsedRealtime();
assertTrue("Early runtime wasn't correctly clamped.",
- loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS);
- // Assert late runtime was clamped to be now + period*2.
+ loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS);
+ // Assert late runtime was clamped to be now + period + flex.
assertTrue("Early runtime wasn't correctly clamped.",
- loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS * 2);
+ loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS + ONE_HOUR);
}
public void testPriorityPersisted() throws Exception {
.setOverrideDeadline(5000)
.setPriority(42)
.setPersisted(true);
- final JobStatus js = new JobStatus(b.build(), SOME_UID);
+ final JobStatus js = new JobStatus(b.build(), SOME_UID, null, -1);
mTaskStoreUnderTest.add(js);
Thread.sleep(IO_WAIT);
final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
JobInfo.Builder b = new Builder(42, mComponent)
.setOverrideDeadline(10000)
.setPersisted(false);
- JobStatus jsNonPersisted = new JobStatus(b.build(), SOME_UID);
+ JobStatus jsNonPersisted = new JobStatus(b.build(), SOME_UID, null, -1);
mTaskStoreUnderTest.add(jsNonPersisted);
b = new Builder(43, mComponent)
.setOverrideDeadline(10000)
.setPersisted(true);
- JobStatus jsPersisted = new JobStatus(b.build(), SOME_UID);
+ JobStatus jsPersisted = new JobStatus(b.build(), SOME_UID, null, -1);
mTaskStoreUnderTest.add(jsPersisted);
Thread.sleep(IO_WAIT);
final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();