Merge "Remove internal locking from JobStatus." into nyc-dev
am: 044a802b26
* commit '044a802b26557aef84da074801ee818ba24f86b6':
Remove internal locking from JobStatus.
This commit is contained in:
@@ -237,7 +237,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
|
||||
public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
|
||||
JobStatus jobStatus = new JobStatus(getLock(), job, uId, packageName, userId);
|
||||
JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId);
|
||||
try {
|
||||
if (ActivityManagerNative.getDefault().getAppStartMode(uId,
|
||||
job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
|
||||
@@ -476,7 +476,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
JobStatus job = jobs.valueAt(i);
|
||||
for (int controller=0; controller<mControllers.size(); controller++) {
|
||||
mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
|
||||
mControllers.get(controller).maybeStartTrackingJob(job, null);
|
||||
mControllers.get(controller).maybeStartTrackingJobLocked(job, null);
|
||||
}
|
||||
}
|
||||
// GO GO GO!
|
||||
@@ -491,19 +491,16 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
* about.
|
||||
*/
|
||||
private void startTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
|
||||
boolean update;
|
||||
boolean rocking;
|
||||
synchronized (mLock) {
|
||||
update = mJobs.add(jobStatus);
|
||||
rocking = mReadyToRock;
|
||||
}
|
||||
if (rocking) {
|
||||
for (int i=0; i<mControllers.size(); i++) {
|
||||
StateController controller = mControllers.get(i);
|
||||
if (update) {
|
||||
controller.maybeStopTrackingJob(jobStatus, true);
|
||||
final boolean update = mJobs.add(jobStatus);
|
||||
if (mReadyToRock) {
|
||||
for (int i = 0; i < mControllers.size(); i++) {
|
||||
StateController controller = mControllers.get(i);
|
||||
if (update) {
|
||||
controller.maybeStopTrackingJobLocked(jobStatus, true);
|
||||
}
|
||||
controller.maybeStartTrackingJobLocked(jobStatus, lastJob);
|
||||
}
|
||||
controller.maybeStartTrackingJob(jobStatus, lastJob);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,20 +510,17 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
* object removed.
|
||||
*/
|
||||
private boolean stopTrackingJob(JobStatus jobStatus, boolean writeBack) {
|
||||
boolean removed;
|
||||
boolean rocking;
|
||||
synchronized (mLock) {
|
||||
// Remove from store as well as controllers.
|
||||
removed = mJobs.remove(jobStatus, writeBack);
|
||||
rocking = mReadyToRock;
|
||||
}
|
||||
if (removed && rocking) {
|
||||
for (int i=0; i<mControllers.size(); i++) {
|
||||
StateController controller = mControllers.get(i);
|
||||
controller.maybeStopTrackingJob(jobStatus, false);
|
||||
final boolean removed = mJobs.remove(jobStatus, writeBack);
|
||||
if (removed && mReadyToRock) {
|
||||
for (int i=0; i<mControllers.size(); i++) {
|
||||
StateController controller = mControllers.get(i);
|
||||
controller.maybeStopTrackingJobLocked(jobStatus, false);
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
|
||||
@@ -759,7 +753,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
Slog.d(TAG, " queued " + job.toShortString());
|
||||
}
|
||||
mPendingJobs.add(job);
|
||||
} else if (areJobConstraintsNotSatisfied(job)) {
|
||||
} else if (areJobConstraintsNotSatisfiedLocked(job)) {
|
||||
stopJobOnServiceContextLocked(job,
|
||||
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
|
||||
}
|
||||
@@ -826,7 +820,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
runnableJobs = new ArrayList<>();
|
||||
}
|
||||
runnableJobs.add(job);
|
||||
} else if (areJobConstraintsNotSatisfied(job)) {
|
||||
} else if (areJobConstraintsNotSatisfiedLocked(job)) {
|
||||
stopJobOnServiceContextLocked(job,
|
||||
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
|
||||
}
|
||||
@@ -875,7 +869,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
* - It's not ready
|
||||
* - It's running on a JSC.
|
||||
*/
|
||||
private boolean areJobConstraintsNotSatisfied(JobStatus job) {
|
||||
private boolean areJobConstraintsNotSatisfiedLocked(JobStatus job) {
|
||||
return !job.isReady() && isCurrentlyActiveLocked(job);
|
||||
}
|
||||
|
||||
@@ -893,7 +887,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
|
||||
}
|
||||
assignJobsToContextsH();
|
||||
assignJobsToContextsLocked();
|
||||
reportActive();
|
||||
}
|
||||
}
|
||||
@@ -905,7 +899,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
* run higher priority ones.
|
||||
* Lock on mJobs before calling this function.
|
||||
*/
|
||||
private void assignJobsToContextsH() {
|
||||
private void assignJobsToContextsLocked() {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, printPendingQueue());
|
||||
}
|
||||
@@ -990,7 +984,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
for (int ic=0; ic<mControllers.size(); ic++) {
|
||||
StateController controller = mControllers.get(ic);
|
||||
controller.prepareForExecution(contextIdToJobMap[i]);
|
||||
controller.prepareForExecutionLocked(contextIdToJobMap[i]);
|
||||
}
|
||||
if (!mActiveServices.get(i).executeRunnableJob(contextIdToJobMap[i])) {
|
||||
Slog.d(TAG, "Error executing " + contextIdToJobMap[i]);
|
||||
@@ -1222,7 +1216,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
for (int i=0; i<mControllers.size(); i++) {
|
||||
pw.println();
|
||||
mControllers.get(i).dumpControllerState(pw);
|
||||
mControllers.get(i).dumpControllerStateLocked(pw);
|
||||
}
|
||||
pw.println();
|
||||
pw.println(printPendingQueue());
|
||||
|
||||
@@ -44,7 +44,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -680,7 +679,7 @@ public class JobStore {
|
||||
parser.nextTag(); // Consume </extras>
|
||||
|
||||
JobStatus js = new JobStatus(
|
||||
mLock, jobBuilder.build(), uid, sourcePackageName, sourceUserId,
|
||||
jobBuilder.build(), uid, sourcePackageName, sourceUserId,
|
||||
elapsedRuntimes.first, elapsedRuntimes.second);
|
||||
return js;
|
||||
}
|
||||
|
||||
@@ -64,39 +64,34 @@ public class AppIdleController extends StateController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
|
||||
synchronized (mLock) {
|
||||
mTrackedTasks.add(jobStatus);
|
||||
String packageName = jobStatus.getSourcePackageName();
|
||||
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
|
||||
jobStatus.getSourceUid(), jobStatus.getSourceUserId());
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
|
||||
+ packageName + " to " + appIdle);
|
||||
}
|
||||
jobStatus.appNotIdleConstraintSatisfied.set(!appIdle);
|
||||
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
|
||||
mTrackedTasks.add(jobStatus);
|
||||
String packageName = jobStatus.getSourcePackageName();
|
||||
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
|
||||
jobStatus.getSourceUid(), jobStatus.getSourceUserId());
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
|
||||
+ packageName + " to " + appIdle);
|
||||
}
|
||||
jobStatus.setAppNotIdleConstraintSatisfied(!appIdle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
|
||||
synchronized (mLock) {
|
||||
mTrackedTasks.remove(jobStatus);
|
||||
}
|
||||
public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
|
||||
mTrackedTasks.remove(jobStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpControllerState(PrintWriter pw) {
|
||||
public void dumpControllerStateLocked(PrintWriter pw) {
|
||||
pw.println("AppIdle");
|
||||
pw.println("Parole On: " + mAppIdleParoleOn);
|
||||
synchronized (mLock) {
|
||||
for (JobStatus task : mTrackedTasks) {
|
||||
pw.print(task.getSourcePackageName());
|
||||
pw.print(":idle=" + !task.appNotIdleConstraintSatisfied.get());
|
||||
pw.print(", ");
|
||||
}
|
||||
pw.println();
|
||||
for (JobStatus task : mTrackedTasks) {
|
||||
pw.print(task.getSourcePackageName());
|
||||
pw.print(":idle="
|
||||
+ ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
|
||||
pw.print(", ");
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
|
||||
void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
|
||||
@@ -114,8 +109,7 @@ public class AppIdleController extends StateController {
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
|
||||
}
|
||||
if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
|
||||
task.appNotIdleConstraintSatisfied.set(!appIdle);
|
||||
if (task.setAppNotIdleConstraintSatisfied(!appIdle)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -137,12 +131,11 @@ public class AppIdleController extends StateController {
|
||||
for (JobStatus task : mTrackedTasks) {
|
||||
if (task.getSourcePackageName().equals(packageName)
|
||||
&& task.getSourceUserId() == userId) {
|
||||
if (task.appNotIdleConstraintSatisfied.get() != !idle) {
|
||||
if (task.setAppNotIdleConstraintSatisfied(!idle)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
|
||||
+ packageName + " to " + idle);
|
||||
}
|
||||
task.appNotIdleConstraintSatisfied.set(!idle);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,22 +78,18 @@ public class BatteryController extends StateController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
|
||||
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
|
||||
final boolean isOnStablePower = mChargeTracker.isOnStablePower();
|
||||
if (taskStatus.hasChargingConstraint()) {
|
||||
synchronized (mLock) {
|
||||
mTrackedTasks.add(taskStatus);
|
||||
taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
|
||||
}
|
||||
mTrackedTasks.add(taskStatus);
|
||||
taskStatus.setChargingConstraintSatisfied(isOnStablePower);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
|
||||
public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
|
||||
if (taskStatus.hasChargingConstraint()) {
|
||||
synchronized (mLock) {
|
||||
mTrackedTasks.remove(taskStatus);
|
||||
}
|
||||
mTrackedTasks.remove(taskStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +101,7 @@ public class BatteryController extends StateController {
|
||||
boolean reportChange = false;
|
||||
synchronized (mLock) {
|
||||
for (JobStatus ts : mTrackedTasks) {
|
||||
boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
|
||||
boolean previous = ts.setChargingConstraintSatisfied(stablePower);
|
||||
if (previous != stablePower) {
|
||||
reportChange = true;
|
||||
}
|
||||
@@ -198,18 +194,16 @@ public class BatteryController extends StateController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpControllerState(PrintWriter pw) {
|
||||
public void dumpControllerStateLocked(PrintWriter pw) {
|
||||
pw.println("Batt.");
|
||||
pw.println("Stable power: " + mChargeTracker.isOnStablePower());
|
||||
synchronized (mLock) {
|
||||
Iterator<JobStatus> it = mTrackedTasks.iterator();
|
||||
if (it.hasNext()) {
|
||||
pw.print(String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
pw.print("," + String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
pw.println();
|
||||
Iterator<JobStatus> it = mTrackedTasks.iterator();
|
||||
if (it.hasNext()) {
|
||||
pw.print(String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
pw.print("," + String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,22 +83,18 @@ public class ConnectivityController extends StateController implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
|
||||
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
|
||||
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
|
||||
synchronized (mLock) {
|
||||
jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
|
||||
jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
|
||||
mTrackedJobs.add(jobStatus);
|
||||
}
|
||||
jobStatus.setConnectivityConstraintSatisfied(mNetworkConnected);
|
||||
jobStatus.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
|
||||
mTrackedJobs.add(jobStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
|
||||
public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
|
||||
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
|
||||
synchronized (mLock) {
|
||||
mTrackedJobs.remove(jobStatus);
|
||||
}
|
||||
mTrackedJobs.remove(jobStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,12 +108,8 @@ public class ConnectivityController extends StateController implements
|
||||
if (js.getUserId() != userId) {
|
||||
continue;
|
||||
}
|
||||
boolean prevIsConnected =
|
||||
js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
|
||||
boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
|
||||
if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
|
||||
changed = true;
|
||||
}
|
||||
changed |= js.setConnectivityConstraintSatisfied(mNetworkConnected);
|
||||
changed |= js.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
|
||||
}
|
||||
if (changed) {
|
||||
mStateChangedListener.onControllerStateChanged();
|
||||
@@ -189,7 +181,7 @@ public class ConnectivityController extends StateController implements
|
||||
};
|
||||
|
||||
@Override
|
||||
public void dumpControllerState(PrintWriter pw) {
|
||||
public void dumpControllerStateLocked(PrintWriter pw) {
|
||||
pw.println("Conn.");
|
||||
pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
|
||||
for (JobStatus js: mTrackedJobs) {
|
||||
|
||||
@@ -75,87 +75,81 @@ public class ContentObserverController extends StateController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
|
||||
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
|
||||
if (taskStatus.hasContentTriggerConstraint()) {
|
||||
synchronized (mLock) {
|
||||
if (taskStatus.contentObserverJobInstance == null) {
|
||||
taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
|
||||
}
|
||||
mTrackedTasks.add(taskStatus);
|
||||
boolean havePendingUris = false;
|
||||
// If there is a previous job associated with the new job, propagate over
|
||||
// any pending content URI trigger reports.
|
||||
if (lastJob != null && lastJob.contentObserverJobInstance != null
|
||||
&& lastJob.contentObserverJobInstance
|
||||
!= taskStatus.contentObserverJobInstance
|
||||
&& lastJob.contentObserverJobInstance.mChangedAuthorities != null) {
|
||||
havePendingUris = true;
|
||||
if (taskStatus.contentObserverJobInstance == null) {
|
||||
taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
|
||||
}
|
||||
mTrackedTasks.add(taskStatus);
|
||||
boolean havePendingUris = false;
|
||||
// If there is a previous job associated with the new job, propagate over
|
||||
// any pending content URI trigger reports.
|
||||
if (lastJob != null && lastJob.contentObserverJobInstance != null
|
||||
&& lastJob.contentObserverJobInstance
|
||||
!= taskStatus.contentObserverJobInstance
|
||||
&& lastJob.contentObserverJobInstance.mChangedAuthorities != null) {
|
||||
havePendingUris = true;
|
||||
taskStatus.contentObserverJobInstance.mChangedAuthorities
|
||||
= lastJob.contentObserverJobInstance.mChangedAuthorities;
|
||||
taskStatus.contentObserverJobInstance.mChangedUris
|
||||
= lastJob.contentObserverJobInstance.mChangedUris;
|
||||
lastJob.contentObserverJobInstance.mChangedAuthorities = null;
|
||||
lastJob.contentObserverJobInstance.mChangedUris = null;
|
||||
}
|
||||
// If we have previously reported changed authorities/uris, then we failed
|
||||
// to complete the job with them so will re-record them to report again.
|
||||
if (taskStatus.changedAuthorities != null) {
|
||||
havePendingUris = true;
|
||||
if (taskStatus.contentObserverJobInstance.mChangedAuthorities == null) {
|
||||
taskStatus.contentObserverJobInstance.mChangedAuthorities
|
||||
= lastJob.contentObserverJobInstance.mChangedAuthorities;
|
||||
taskStatus.contentObserverJobInstance.mChangedUris
|
||||
= lastJob.contentObserverJobInstance.mChangedUris;
|
||||
lastJob.contentObserverJobInstance.mChangedAuthorities = null;
|
||||
lastJob.contentObserverJobInstance.mChangedUris = null;
|
||||
= new ArraySet<>();
|
||||
}
|
||||
// If we have previously reported changed authorities/uris, then we failed
|
||||
// to complete the job with them so will re-record them to report again.
|
||||
if (taskStatus.changedAuthorities != null) {
|
||||
havePendingUris = true;
|
||||
if (taskStatus.contentObserverJobInstance.mChangedAuthorities == null) {
|
||||
taskStatus.contentObserverJobInstance.mChangedAuthorities
|
||||
= new ArraySet<>();
|
||||
for (String auth : taskStatus.changedAuthorities) {
|
||||
taskStatus.contentObserverJobInstance.mChangedAuthorities.add(auth);
|
||||
}
|
||||
if (taskStatus.changedUris != null) {
|
||||
if (taskStatus.contentObserverJobInstance.mChangedUris == null) {
|
||||
taskStatus.contentObserverJobInstance.mChangedUris = new ArraySet<>();
|
||||
}
|
||||
for (String auth : taskStatus.changedAuthorities) {
|
||||
taskStatus.contentObserverJobInstance.mChangedAuthorities.add(auth);
|
||||
for (Uri uri : taskStatus.changedUris) {
|
||||
taskStatus.contentObserverJobInstance.mChangedUris.add(uri);
|
||||
}
|
||||
if (taskStatus.changedUris != null) {
|
||||
if (taskStatus.contentObserverJobInstance.mChangedUris == null) {
|
||||
taskStatus.contentObserverJobInstance.mChangedUris = new ArraySet<>();
|
||||
}
|
||||
for (Uri uri : taskStatus.changedUris) {
|
||||
taskStatus.contentObserverJobInstance.mChangedUris.add(uri);
|
||||
}
|
||||
}
|
||||
taskStatus.changedAuthorities = null;
|
||||
taskStatus.changedUris = null;
|
||||
}
|
||||
taskStatus.changedAuthorities = null;
|
||||
taskStatus.changedUris = null;
|
||||
taskStatus.contentTriggerConstraintSatisfied.set(havePendingUris);
|
||||
}
|
||||
taskStatus.changedAuthorities = null;
|
||||
taskStatus.changedUris = null;
|
||||
taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareForExecutionLocked(JobStatus taskStatus) {
|
||||
if (taskStatus.hasContentTriggerConstraint()) {
|
||||
if (taskStatus.contentObserverJobInstance != null) {
|
||||
taskStatus.changedUris = taskStatus.contentObserverJobInstance.mChangedUris;
|
||||
taskStatus.changedAuthorities
|
||||
= taskStatus.contentObserverJobInstance.mChangedAuthorities;
|
||||
taskStatus.contentObserverJobInstance.mChangedUris = null;
|
||||
taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareForExecution(JobStatus taskStatus) {
|
||||
public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
|
||||
if (taskStatus.hasContentTriggerConstraint()) {
|
||||
synchronized (mLock) {
|
||||
if (!forUpdate) {
|
||||
// We won't do this reset if being called for an update, because
|
||||
// we know it will be immediately followed by maybeStartTrackingJobLocked...
|
||||
// and we don't want to lose any content changes in-between.
|
||||
if (taskStatus.contentObserverJobInstance != null) {
|
||||
taskStatus.changedUris = taskStatus.contentObserverJobInstance.mChangedUris;
|
||||
taskStatus.changedAuthorities
|
||||
= taskStatus.contentObserverJobInstance.mChangedAuthorities;
|
||||
taskStatus.contentObserverJobInstance.mChangedUris = null;
|
||||
taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
|
||||
taskStatus.contentObserverJobInstance.detach();
|
||||
taskStatus.contentObserverJobInstance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
|
||||
if (taskStatus.hasContentTriggerConstraint()) {
|
||||
synchronized (mLock) {
|
||||
if (!forUpdate) {
|
||||
// We won't do this reset if being called for an update, because
|
||||
// we know it will be immediately followed by maybeStartTrackingJob...
|
||||
// and we don't want to lose any content changes in-between.
|
||||
if (taskStatus.contentObserverJobInstance != null) {
|
||||
taskStatus.contentObserverJobInstance.detach();
|
||||
taskStatus.contentObserverJobInstance = null;
|
||||
}
|
||||
}
|
||||
mTrackedTasks.remove(taskStatus);
|
||||
}
|
||||
mTrackedTasks.remove(taskStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,9 +193,7 @@ public class ContentObserverController extends StateController {
|
||||
inst.mChangedAuthorities = new ArraySet<>();
|
||||
}
|
||||
inst.mChangedAuthorities.add(uri.getAuthority());
|
||||
boolean previous
|
||||
= inst.mJobStatus.contentTriggerConstraintSatisfied.getAndSet(true);
|
||||
if (!previous) {
|
||||
if (inst.mJobStatus.setContentTriggerConstraintSatisfied(true)) {
|
||||
reportChange = true;
|
||||
}
|
||||
}
|
||||
@@ -255,50 +247,48 @@ public class ContentObserverController extends StateController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpControllerState(PrintWriter pw) {
|
||||
public void dumpControllerStateLocked(PrintWriter pw) {
|
||||
pw.println("Content.");
|
||||
synchronized (mLock) {
|
||||
Iterator<JobStatus> it = mTrackedTasks.iterator();
|
||||
if (it.hasNext()) {
|
||||
pw.print(String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
pw.print("," + String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
pw.println();
|
||||
int N = mObservers.size();
|
||||
if (N > 0) {
|
||||
pw.println("URIs:");
|
||||
for (int i = 0; i < N; i++) {
|
||||
ObserverInstance obs = mObservers.valueAt(i);
|
||||
pw.print(" ");
|
||||
pw.print(mObservers.keyAt(i));
|
||||
pw.println(":");
|
||||
pw.print(" ");
|
||||
pw.println(obs);
|
||||
pw.println(" Jobs:");
|
||||
int M = obs.mJobs.size();
|
||||
for (int j=0; j<M; j++) {
|
||||
JobInstance inst = obs.mJobs.get(j);
|
||||
pw.print(" ");
|
||||
pw.print(inst.hashCode());
|
||||
if (inst.mChangedAuthorities != null) {
|
||||
pw.println(":");
|
||||
pw.println(" Changed Authorities:");
|
||||
for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
|
||||
pw.print(" ");
|
||||
pw.println(inst.mChangedAuthorities.valueAt(k));
|
||||
}
|
||||
if (inst.mChangedUris != null) {
|
||||
pw.println(" Changed URIs:");
|
||||
for (int k = 0; k<inst.mChangedUris.size(); k++) {
|
||||
pw.print(" ");
|
||||
pw.println(inst.mChangedUris.valueAt(k));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pw.println();
|
||||
Iterator<JobStatus> it = mTrackedTasks.iterator();
|
||||
if (it.hasNext()) {
|
||||
pw.print(String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
pw.print("," + String.valueOf(it.next().hashCode()));
|
||||
}
|
||||
pw.println();
|
||||
int N = mObservers.size();
|
||||
if (N > 0) {
|
||||
pw.println("URIs:");
|
||||
for (int i = 0; i < N; i++) {
|
||||
ObserverInstance obs = mObservers.valueAt(i);
|
||||
pw.print(" ");
|
||||
pw.print(mObservers.keyAt(i));
|
||||
pw.println(":");
|
||||
pw.print(" ");
|
||||
pw.println(obs);
|
||||
pw.println(" Jobs:");
|
||||
int M = obs.mJobs.size();
|
||||
for (int j=0; j<M; j++) {
|
||||
JobInstance inst = obs.mJobs.get(j);
|
||||
pw.print(" ");
|
||||
pw.print(inst.hashCode());
|
||||
if (inst.mChangedAuthorities != null) {
|
||||
pw.println(":");
|
||||
pw.println(" Changed Authorities:");
|
||||
for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
|
||||
pw.print(" ");
|
||||
pw.println(inst.mChangedAuthorities.valueAt(k));
|
||||
}
|
||||
if (inst.mChangedUris != null) {
|
||||
pw.println(" Changed URIs:");
|
||||
for (int k = 0; k<inst.mChangedUris.size(); k++) {
|
||||
pw.print(" ");
|
||||
pw.println(inst.mChangedUris.valueAt(k));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,20 +67,16 @@ public class IdleController extends StateController {
|
||||
* StateController interface
|
||||
*/
|
||||
@Override
|
||||
public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
|
||||
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
|
||||
if (taskStatus.hasIdleConstraint()) {
|
||||
synchronized (mLock) {
|
||||
mTrackedTasks.add(taskStatus);
|
||||
taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
|
||||
}
|
||||
mTrackedTasks.add(taskStatus);
|
||||
taskStatus.setIdleConstraintSatisfied(mIdleTracker.isIdle());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
|
||||
synchronized (mLock) {
|
||||
mTrackedTasks.remove(taskStatus);
|
||||
}
|
||||
public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
|
||||
mTrackedTasks.remove(taskStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +85,7 @@ public class IdleController extends StateController {
|
||||
void reportNewIdleState(boolean isIdle) {
|
||||
synchronized (mLock) {
|
||||
for (JobStatus task : mTrackedTasks) {
|
||||
task.idleConstraintSatisfied.set(isIdle);
|
||||
task.setIdleConstraintSatisfied(isIdle);
|
||||
}
|
||||
}
|
||||
mStateChangedListener.onControllerStateChanged();
|
||||
@@ -194,17 +190,15 @@ public class IdleController extends StateController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpControllerState(PrintWriter pw) {
|
||||
synchronized (mLock) {
|
||||
pw.print("Idle: ");
|
||||
pw.println(mIdleTracker.isIdle() ? "true" : "false");
|
||||
pw.println(mTrackedTasks.size());
|
||||
for (int i = 0; i < mTrackedTasks.size(); i++) {
|
||||
final JobStatus js = mTrackedTasks.get(i);
|
||||
pw.print(" ");
|
||||
pw.print(String.valueOf(js.hashCode()).substring(0, 3));
|
||||
pw.println("..");
|
||||
}
|
||||
public void dumpControllerStateLocked(PrintWriter pw) {
|
||||
pw.print("Idle: ");
|
||||
pw.println(mIdleTracker.isIdle() ? "true" : "false");
|
||||
pw.println(mTrackedTasks.size());
|
||||
for (int i = 0; i < mTrackedTasks.size(); i++) {
|
||||
final JobStatus js = mTrackedTasks.get(i);
|
||||
pw.print(" ");
|
||||
pw.print(String.valueOf(js.hashCode()).substring(0, 3));
|
||||
pw.println("..");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,15 +42,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* but we don't enforce that so this is safer.
|
||||
* @hide
|
||||
*/
|
||||
public class JobStatus {
|
||||
public final class JobStatus {
|
||||
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
|
||||
public static final long NO_EARLIEST_RUNTIME = 0L;
|
||||
|
||||
/**
|
||||
* Service global lock. NOTE: this should be removed, having this class just rely on
|
||||
* its callers doing the appropriate locking.
|
||||
*/
|
||||
final Object lock;
|
||||
static final int CONSTRAINT_CHARGING = 1<<0;
|
||||
static final int CONSTRAINT_TIMING_DELAY = 1<<1;
|
||||
static final int CONSTRAINT_DEADLINE = 1<<2;
|
||||
static final int CONSTRAINT_IDLE = 1<<3;
|
||||
static final int CONSTRAINT_UNMETERED = 1<<4;
|
||||
static final int CONSTRAINT_CONNECTIVITY = 1<<5;
|
||||
static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
|
||||
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
|
||||
|
||||
final JobInfo job;
|
||||
/** Uid of the package requesting this job. */
|
||||
final int callingUid;
|
||||
@@ -61,15 +65,23 @@ public class JobStatus {
|
||||
final int sourceUserId;
|
||||
final int sourceUid;
|
||||
|
||||
/**
|
||||
* Earliest point in the future at which this job will be eligible to run. A value of 0
|
||||
* indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
|
||||
*/
|
||||
private final long earliestRunTimeElapsedMillis;
|
||||
/**
|
||||
* Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
|
||||
* indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
|
||||
*/
|
||||
private final long latestRunTimeElapsedMillis;
|
||||
|
||||
/** How many times this job has failed, used to compute back-off. */
|
||||
private final int numFailures;
|
||||
|
||||
// Constraints.
|
||||
final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
|
||||
final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
|
||||
final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
|
||||
final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
|
||||
final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
|
||||
final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
|
||||
final AtomicBoolean appNotIdleConstraintSatisfied = new AtomicBoolean();
|
||||
final AtomicBoolean contentTriggerConstraintSatisfied = new AtomicBoolean();
|
||||
final int requiredConstraints;
|
||||
int satisfiedConstraints = 0;
|
||||
|
||||
// These are filled in by controllers when preparing for execution.
|
||||
public ArraySet<Uri> changedUris;
|
||||
@@ -81,32 +93,18 @@ public class JobStatus {
|
||||
*/
|
||||
ContentObserverController.JobInstance contentObserverJobInstance;
|
||||
|
||||
/**
|
||||
* Earliest point in the future at which this job will be eligible to run. A value of 0
|
||||
* indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
|
||||
*/
|
||||
private long earliestRunTimeElapsedMillis;
|
||||
/**
|
||||
* Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
|
||||
* indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
|
||||
*/
|
||||
private long latestRunTimeElapsedMillis;
|
||||
/** How many times this job has failed, used to compute back-off. */
|
||||
private final int numFailures;
|
||||
|
||||
/** Provide a handle to the service that this job will be run on. */
|
||||
public int getServiceToken() {
|
||||
return callingUid;
|
||||
}
|
||||
|
||||
private JobStatus(Object lock, JobInfo job, int callingUid, String sourcePackageName,
|
||||
int sourceUserId, int numFailures) {
|
||||
this.lock = lock;
|
||||
private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
|
||||
int sourceUserId, int numFailures, long earliestRunTimeElapsedMillis,
|
||||
long latestRunTimeElapsedMillis) {
|
||||
this.job = job;
|
||||
this.callingUid = callingUid;
|
||||
this.name = job.getService().flattenToShortString();
|
||||
this.tag = "*job*/" + this.name;
|
||||
this.numFailures = numFailures;
|
||||
|
||||
int tempSourceUid = -1;
|
||||
if (sourceUserId != -1 && sourcePackageName != null) {
|
||||
@@ -126,40 +124,42 @@ public class JobStatus {
|
||||
this.sourceUserId = sourceUserId;
|
||||
this.sourcePackageName = sourcePackageName;
|
||||
}
|
||||
|
||||
this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
|
||||
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
|
||||
this.numFailures = numFailures;
|
||||
|
||||
int requiredConstraints = 0;
|
||||
if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
|
||||
requiredConstraints |= CONSTRAINT_CONNECTIVITY;
|
||||
}
|
||||
if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
|
||||
requiredConstraints |= CONSTRAINT_UNMETERED;
|
||||
}
|
||||
if (job.isRequireCharging()) {
|
||||
requiredConstraints |= CONSTRAINT_CHARGING;
|
||||
}
|
||||
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
|
||||
requiredConstraints |= CONSTRAINT_TIMING_DELAY;
|
||||
}
|
||||
if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
|
||||
requiredConstraints |= CONSTRAINT_DEADLINE;
|
||||
}
|
||||
if (job.isRequireDeviceIdle()) {
|
||||
requiredConstraints |= CONSTRAINT_IDLE;
|
||||
}
|
||||
if (job.getTriggerContentUris() != null) {
|
||||
requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
|
||||
}
|
||||
this.requiredConstraints = requiredConstraints;
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
public JobStatus(JobStatus jobStatus) {
|
||||
this(jobStatus.lock, jobStatus.getJob(), jobStatus.getUid(),
|
||||
this(jobStatus.getJob(), jobStatus.getUid(),
|
||||
jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
|
||||
jobStatus.getNumFailures());
|
||||
this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
|
||||
this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Object lock, JobInfo job, int callingUid, String sourcePackageName,
|
||||
int sourceUserId) {
|
||||
this(lock, job, callingUid, sourcePackageName, sourceUserId, 0);
|
||||
|
||||
final long elapsedNow = SystemClock.elapsedRealtime();
|
||||
|
||||
if (job.isPeriodic()) {
|
||||
latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
|
||||
earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
|
||||
} else {
|
||||
earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
|
||||
elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
|
||||
latestRunTimeElapsedMillis = job.hasLateConstraint() ?
|
||||
elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
|
||||
}
|
||||
jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(),
|
||||
jobStatus.getLatestRunTimeElapsed());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,23 +169,43 @@ public class JobStatus {
|
||||
* wallclock runtime rather than resetting it on every boot.
|
||||
* We consider a freshly loaded job to no longer be in back-off.
|
||||
*/
|
||||
public JobStatus(Object lock, JobInfo job, int callingUid, String sourcePackageName,
|
||||
public JobStatus(JobInfo job, int callingUid, String sourcePackageName,
|
||||
int sourceUserId, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
|
||||
this(lock, job, callingUid, sourcePackageName, sourceUserId, 0);
|
||||
|
||||
this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
|
||||
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
|
||||
this(job, callingUid, sourcePackageName, sourceUserId, 0, earliestRunTimeElapsedMillis,
|
||||
latestRunTimeElapsedMillis);
|
||||
}
|
||||
|
||||
/** Create a new job to be rescheduled with the provided parameters. */
|
||||
public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
|
||||
long newLatestRuntimeElapsedMillis, int backoffAttempt) {
|
||||
this(rescheduling.lock, rescheduling.job, rescheduling.getUid(),
|
||||
this(rescheduling.job, rescheduling.getUid(),
|
||||
rescheduling.getSourcePackageName(),
|
||||
rescheduling.getSourceUserId(), backoffAttempt);
|
||||
rescheduling.getSourceUserId(), backoffAttempt, newEarliestRuntimeElapsedMillis,
|
||||
newLatestRuntimeElapsedMillis);
|
||||
}
|
||||
|
||||
earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
|
||||
latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
|
||||
int sourceUserId) {
|
||||
final long elapsedNow = SystemClock.elapsedRealtime();
|
||||
final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
|
||||
if (job.isPeriodic()) {
|
||||
latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
|
||||
earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
|
||||
} else {
|
||||
earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
|
||||
elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
|
||||
latestRunTimeElapsedMillis = job.hasLateConstraint() ?
|
||||
elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
|
||||
}
|
||||
return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, 0,
|
||||
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
|
||||
}
|
||||
|
||||
public JobInfo getJob() {
|
||||
@@ -241,31 +261,31 @@ public class JobStatus {
|
||||
}
|
||||
|
||||
public boolean hasConnectivityConstraint() {
|
||||
return job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY;
|
||||
return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
|
||||
}
|
||||
|
||||
public boolean hasUnmeteredConstraint() {
|
||||
return job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED;
|
||||
return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
|
||||
}
|
||||
|
||||
public boolean hasChargingConstraint() {
|
||||
return job.isRequireCharging();
|
||||
return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
|
||||
}
|
||||
|
||||
public boolean hasTimingDelayConstraint() {
|
||||
return earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME;
|
||||
return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
|
||||
}
|
||||
|
||||
public boolean hasDeadlineConstraint() {
|
||||
return latestRunTimeElapsedMillis != NO_LATEST_RUNTIME;
|
||||
return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
|
||||
}
|
||||
|
||||
public boolean hasIdleConstraint() {
|
||||
return job.isRequireDeviceIdle();
|
||||
return (requiredConstraints&CONSTRAINT_IDLE) != 0;
|
||||
}
|
||||
|
||||
public boolean hasContentTriggerConstraint() {
|
||||
return job.getTriggerContentUris() != null;
|
||||
return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
|
||||
}
|
||||
|
||||
public boolean isPersisted() {
|
||||
@@ -280,35 +300,74 @@ public class JobStatus {
|
||||
return latestRunTimeElapsedMillis;
|
||||
}
|
||||
|
||||
boolean setChargingConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
|
||||
}
|
||||
|
||||
boolean setTimingDelayConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
|
||||
}
|
||||
|
||||
boolean setDeadlineConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
|
||||
}
|
||||
|
||||
boolean setIdleConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_IDLE, state);
|
||||
}
|
||||
|
||||
boolean setUnmeteredConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
|
||||
}
|
||||
|
||||
boolean setConnectivityConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
|
||||
}
|
||||
|
||||
boolean setAppNotIdleConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
|
||||
}
|
||||
|
||||
boolean setContentTriggerConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
|
||||
}
|
||||
|
||||
boolean setConstraintSatisfied(int constraint, boolean state) {
|
||||
boolean old = (satisfiedConstraints&constraint) != 0;
|
||||
if (old == state) {
|
||||
return false;
|
||||
}
|
||||
satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether or not this job is ready to run, based on its requirements. This is true if
|
||||
* the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
|
||||
*/
|
||||
public boolean isReady() {
|
||||
synchronized (lock) {
|
||||
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
|
||||
// (is an implementation detail. A periodic job should only run if it's constraints are
|
||||
// satisfied).
|
||||
// AppNotIdle implicit constraint trumps all!
|
||||
return (isConstraintsSatisfied()
|
||||
|| (!job.isPeriodic()
|
||||
&& hasDeadlineConstraint() && deadlineConstraintSatisfied.get()))
|
||||
&& appNotIdleConstraintSatisfied.get();
|
||||
}
|
||||
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
|
||||
// (is an implementation detail. A periodic job should only run if it's constraints are
|
||||
// satisfied).
|
||||
// AppNotIdle implicit constraint trumps all!
|
||||
return (isConstraintsSatisfied()
|
||||
|| (!job.isPeriodic()
|
||||
&& hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0))
|
||||
&& (satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0;
|
||||
}
|
||||
|
||||
static final int CONSTRAINTS_OF_INTEREST =
|
||||
CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
|
||||
CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
|
||||
CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
|
||||
|
||||
/**
|
||||
* @return Whether the constraints set on this job are satisfied.
|
||||
*/
|
||||
public boolean isConstraintsSatisfied() {
|
||||
synchronized (lock) {
|
||||
return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
|
||||
&& (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
|
||||
&& (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
|
||||
&& (!hasUnmeteredConstraint() || unmeteredConstraintSatisfied.get())
|
||||
&& (!hasIdleConstraint() || idleConstraintSatisfied.get())
|
||||
&& (!hasContentTriggerConstraint() || contentTriggerConstraintSatisfied.get());
|
||||
}
|
||||
final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
|
||||
final int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
|
||||
return (sat & req) == req;
|
||||
}
|
||||
|
||||
public boolean matches(int uid, int jobId) {
|
||||
@@ -327,7 +386,7 @@ public class JobStatus {
|
||||
+ ",I=" + job.isRequireDeviceIdle()
|
||||
+ ",U=" + (job.getTriggerContentUris() != null)
|
||||
+ ",F=" + numFailures + ",P=" + job.isPersisted()
|
||||
+ ",ANI=" + appNotIdleConstraintSatisfied.get()
|
||||
+ ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
|
||||
+ (isReady() ? "(READY)" : "")
|
||||
+ "]";
|
||||
}
|
||||
@@ -362,6 +421,33 @@ public class JobStatus {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
void dumpConstraints(PrintWriter pw, int constraints) {
|
||||
if ((constraints&CONSTRAINT_CHARGING) != 0) {
|
||||
pw.print(" CHARGING");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
|
||||
pw.print(" TIMING_DELAY");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_DEADLINE) != 0) {
|
||||
pw.print(" DEADLINE");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_IDLE) != 0) {
|
||||
pw.print(" IDLE");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_UNMETERED) != 0) {
|
||||
pw.print(" UNMETERED");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
|
||||
pw.print(" CONNECTIVITY");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
|
||||
pw.print(" APP_NOT_IDLE");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
|
||||
pw.print(" CONTENT_TRIGGER");
|
||||
}
|
||||
}
|
||||
|
||||
// Dumpsys infrastructure
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.print(prefix); UserHandle.formatUid(pw, callingUid);
|
||||
@@ -426,39 +512,12 @@ public class JobStatus {
|
||||
if (job.hasLateConstraint()) {
|
||||
pw.print(prefix); pw.println(" Has late constraint");
|
||||
}
|
||||
pw.print(prefix); pw.println("Constraints:");
|
||||
if (hasChargingConstraint()) {
|
||||
pw.print(prefix); pw.print(" Charging: ");
|
||||
pw.println(chargingConstraintSatisfied.get());
|
||||
}
|
||||
if (hasTimingDelayConstraint()) {
|
||||
pw.print(prefix); pw.print(" Time delay: ");
|
||||
pw.println(timeDelayConstraintSatisfied.get());
|
||||
}
|
||||
if (hasDeadlineConstraint()) {
|
||||
pw.print(prefix); pw.print(" Deadline: ");
|
||||
pw.println(deadlineConstraintSatisfied.get());
|
||||
}
|
||||
if (hasIdleConstraint()) {
|
||||
pw.print(prefix); pw.print(" System idle: ");
|
||||
pw.println(idleConstraintSatisfied.get());
|
||||
}
|
||||
if (hasUnmeteredConstraint()) {
|
||||
pw.print(prefix); pw.print(" Unmetered: ");
|
||||
pw.println(unmeteredConstraintSatisfied.get());
|
||||
}
|
||||
if (hasConnectivityConstraint()) {
|
||||
pw.print(prefix); pw.print(" Connectivity: ");
|
||||
pw.println(connectivityConstraintSatisfied.get());
|
||||
}
|
||||
if (hasIdleConstraint()) {
|
||||
pw.print(prefix); pw.print(" App not idle: ");
|
||||
pw.println(appNotIdleConstraintSatisfied.get());
|
||||
}
|
||||
if (hasContentTriggerConstraint()) {
|
||||
pw.print(prefix); pw.print(" Content trigger: ");
|
||||
pw.println(contentTriggerConstraintSatisfied.get());
|
||||
}
|
||||
pw.print(prefix); pw.print("Required constraints:");
|
||||
dumpConstraints(pw, requiredConstraints);
|
||||
pw.println();
|
||||
pw.print(prefix); pw.print("Satisfied constraints:");
|
||||
dumpConstraints(pw, satisfiedConstraints);
|
||||
pw.println();
|
||||
if (changedAuthorities != null) {
|
||||
pw.print(prefix); pw.println("Changed authorities:");
|
||||
for (int i=0; i<changedAuthorities.size(); i++) {
|
||||
|
||||
@@ -52,21 +52,21 @@ public abstract class StateController {
|
||||
* Also called when updating a task, so implementing controllers have to be aware of
|
||||
* preexisting tasks.
|
||||
*/
|
||||
public abstract void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob);
|
||||
public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob);
|
||||
/**
|
||||
* Optionally implement logic here to prepare the job to be executed.
|
||||
*/
|
||||
public void prepareForExecution(JobStatus jobStatus) {
|
||||
public void prepareForExecutionLocked(JobStatus jobStatus) {
|
||||
}
|
||||
/**
|
||||
* Remove task - this will happen if the task is cancelled, completed, etc.
|
||||
*/
|
||||
public abstract void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate);
|
||||
public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate);
|
||||
/**
|
||||
* Called when a new job is being created to reschedule an old failed job.
|
||||
*/
|
||||
public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
|
||||
}
|
||||
|
||||
public abstract void dumpControllerState(PrintWriter pw);
|
||||
public abstract void dumpControllerStateLocked(PrintWriter pw);
|
||||
}
|
||||
|
||||
@@ -72,28 +72,26 @@ public class TimeController extends StateController {
|
||||
* list.
|
||||
*/
|
||||
@Override
|
||||
public void maybeStartTrackingJob(JobStatus job, JobStatus lastJob) {
|
||||
synchronized (mLock) {
|
||||
if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
|
||||
maybeStopTrackingJob(job, false);
|
||||
boolean isInsert = false;
|
||||
ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
|
||||
while (it.hasPrevious()) {
|
||||
JobStatus ts = it.previous();
|
||||
if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
|
||||
// Insert
|
||||
isInsert = true;
|
||||
break;
|
||||
}
|
||||
public void maybeStartTrackingJobLocked(JobStatus job, JobStatus lastJob) {
|
||||
if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
|
||||
maybeStopTrackingJobLocked(job, false);
|
||||
boolean isInsert = false;
|
||||
ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
|
||||
while (it.hasPrevious()) {
|
||||
JobStatus ts = it.previous();
|
||||
if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
|
||||
// Insert
|
||||
isInsert = true;
|
||||
break;
|
||||
}
|
||||
if (isInsert) {
|
||||
it.next();
|
||||
}
|
||||
it.add(job);
|
||||
maybeUpdateAlarms(
|
||||
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
|
||||
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
|
||||
}
|
||||
if (isInsert) {
|
||||
it.next();
|
||||
}
|
||||
it.add(job);
|
||||
maybeUpdateAlarmsLocked(
|
||||
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
|
||||
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,12 +101,10 @@ public class TimeController extends StateController {
|
||||
* Really an == comparison should be enough, but why play with fate? We'll do <=.
|
||||
*/
|
||||
@Override
|
||||
public void maybeStopTrackingJob(JobStatus job, boolean forUpdate) {
|
||||
synchronized (mLock) {
|
||||
if (mTrackedJobs.remove(job)) {
|
||||
checkExpiredDelaysAndResetAlarm();
|
||||
checkExpiredDeadlinesAndResetAlarm();
|
||||
}
|
||||
public void maybeStopTrackingJobLocked(JobStatus job, boolean forUpdate) {
|
||||
if (mTrackedJobs.remove(job)) {
|
||||
checkExpiredDelaysAndResetAlarm();
|
||||
checkExpiredDeadlinesAndResetAlarm();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,14 +114,14 @@ public class TimeController extends StateController {
|
||||
* the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
|
||||
* back and forth.
|
||||
*/
|
||||
private boolean canStopTrackingJob(JobStatus job) {
|
||||
private boolean canStopTrackingJobLocked(JobStatus job) {
|
||||
return (!job.hasTimingDelayConstraint() ||
|
||||
job.timeDelayConstraintSatisfied.get()) &&
|
||||
(job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
|
||||
(!job.hasDeadlineConstraint() ||
|
||||
job.deadlineConstraintSatisfied.get());
|
||||
(job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
|
||||
}
|
||||
|
||||
private void ensureAlarmService() {
|
||||
private void ensureAlarmServiceLocked() {
|
||||
if (mAlarmService == null) {
|
||||
mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
|
||||
}
|
||||
@@ -149,7 +145,7 @@ public class TimeController extends StateController {
|
||||
final long jobDeadline = job.getLatestRunTimeElapsed();
|
||||
|
||||
if (jobDeadline <= nowElapsedMillis) {
|
||||
job.deadlineConstraintSatisfied.set(true);
|
||||
job.setDeadlineConstraintSatisfied(true);
|
||||
mStateChangedListener.onRunJobNow(job);
|
||||
it.remove();
|
||||
} else { // Sorted by expiry time, so take the next one and stop.
|
||||
@@ -157,7 +153,7 @@ public class TimeController extends StateController {
|
||||
break;
|
||||
}
|
||||
}
|
||||
setDeadlineExpiredAlarm(nextExpiryTime);
|
||||
setDeadlineExpiredAlarmLocked(nextExpiryTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,8 +174,8 @@ public class TimeController extends StateController {
|
||||
}
|
||||
final long jobDelayTime = job.getEarliestRunTime();
|
||||
if (jobDelayTime <= nowElapsedMillis) {
|
||||
job.timeDelayConstraintSatisfied.set(true);
|
||||
if (canStopTrackingJob(job)) {
|
||||
job.setTimingDelayConstraintSatisfied(true);
|
||||
if (canStopTrackingJobLocked(job)) {
|
||||
it.remove();
|
||||
}
|
||||
if (job.isReady()) {
|
||||
@@ -194,16 +190,16 @@ public class TimeController extends StateController {
|
||||
if (ready) {
|
||||
mStateChangedListener.onControllerStateChanged();
|
||||
}
|
||||
setDelayExpiredAlarm(nextDelayTime);
|
||||
setDelayExpiredAlarmLocked(nextDelayTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
|
||||
private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed) {
|
||||
if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
|
||||
setDelayExpiredAlarm(delayExpiredElapsed);
|
||||
setDelayExpiredAlarmLocked(delayExpiredElapsed);
|
||||
}
|
||||
if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
|
||||
setDeadlineExpiredAlarm(deadlineExpiredElapsed);
|
||||
setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,10 +208,11 @@ public class TimeController extends StateController {
|
||||
* delay will expire.
|
||||
* This alarm <b>will</b> wake up the phone.
|
||||
*/
|
||||
private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
|
||||
private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis) {
|
||||
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
|
||||
mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
|
||||
updateAlarmWithListener(DELAY_TAG, mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis);
|
||||
updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
|
||||
mNextDelayExpiredElapsedMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,10 +220,11 @@ public class TimeController extends StateController {
|
||||
* deadline will expire.
|
||||
* This alarm <b>will</b> wake up the phone.
|
||||
*/
|
||||
private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
|
||||
private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis) {
|
||||
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
|
||||
mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
|
||||
updateAlarmWithListener(DEADLINE_TAG, mDeadlineExpiredListener, mNextJobExpiredElapsedMillis);
|
||||
updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
|
||||
mNextJobExpiredElapsedMillis);
|
||||
}
|
||||
|
||||
private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
|
||||
@@ -237,9 +235,9 @@ public class TimeController extends StateController {
|
||||
return proposedAlarmTimeElapsedMillis;
|
||||
}
|
||||
|
||||
private void updateAlarmWithListener(String tag, OnAlarmListener listener,
|
||||
private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
|
||||
long alarmTimeElapsed) {
|
||||
ensureAlarmService();
|
||||
ensureAlarmServiceLocked();
|
||||
if (alarmTimeElapsed == Long.MAX_VALUE) {
|
||||
mAlarmService.cancel(listener);
|
||||
} else {
|
||||
@@ -274,7 +272,7 @@ public class TimeController extends StateController {
|
||||
};
|
||||
|
||||
@Override
|
||||
public void dumpControllerState(PrintWriter pw) {
|
||||
public void dumpControllerStateLocked(PrintWriter pw) {
|
||||
final long nowElapsed = SystemClock.elapsedRealtime();
|
||||
pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")");
|
||||
pw.println(
|
||||
|
||||
@@ -58,7 +58,7 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
.setMinimumLatency(runFromMillis)
|
||||
.setPersisted(true)
|
||||
.build();
|
||||
final JobStatus ts = new JobStatus(this, task, SOME_UID, null, -1);
|
||||
final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
|
||||
mTaskStoreUnderTest.add(ts);
|
||||
Thread.sleep(IO_WAIT);
|
||||
// Manually load tasks from xml file.
|
||||
@@ -91,8 +91,8 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
|
||||
.setPersisted(true)
|
||||
.build();
|
||||
final JobStatus taskStatus1 = new JobStatus(this, task1, SOME_UID, null, -1);
|
||||
final JobStatus taskStatus2 = new JobStatus(this, task2, SOME_UID, null, -1);
|
||||
final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1);
|
||||
final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1);
|
||||
mTaskStoreUnderTest.add(taskStatus1);
|
||||
mTaskStoreUnderTest.add(taskStatus2);
|
||||
Thread.sleep(IO_WAIT);
|
||||
@@ -140,7 +140,7 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
extras.putInt("into", 3);
|
||||
b.setExtras(extras);
|
||||
final JobInfo task = b.build();
|
||||
JobStatus taskStatus = new JobStatus(this, task, SOME_UID, null, -1);
|
||||
JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
|
||||
|
||||
mTaskStoreUnderTest.add(taskStatus);
|
||||
Thread.sleep(IO_WAIT);
|
||||
@@ -157,7 +157,7 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
.setPeriodic(10000L)
|
||||
.setRequiresCharging(true)
|
||||
.setPersisted(true);
|
||||
JobStatus taskStatus = new JobStatus(this, b.build(), SOME_UID,
|
||||
JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID,
|
||||
"com.google.android.gms", 0);
|
||||
|
||||
mTaskStoreUnderTest.add(taskStatus);
|
||||
@@ -179,7 +179,7 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
.setPeriodic(5*60*60*1000, 1*60*60*1000)
|
||||
.setRequiresCharging(true)
|
||||
.setPersisted(true);
|
||||
JobStatus taskStatus = new JobStatus(this, b.build(), SOME_UID, null, -1);
|
||||
JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
|
||||
|
||||
mTaskStoreUnderTest.add(taskStatus);
|
||||
Thread.sleep(IO_WAIT);
|
||||
@@ -204,7 +204,7 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS; // > period+flex
|
||||
final long invalidEarlyRuntimeElapsedMillis =
|
||||
invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period).
|
||||
final JobStatus js = new JobStatus(this, b.build(), SOME_UID, "somePackage",
|
||||
final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
|
||||
0 /* sourceUserId */,
|
||||
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
|
||||
|
||||
@@ -231,7 +231,7 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
.setOverrideDeadline(5000)
|
||||
.setPriority(42)
|
||||
.setPersisted(true);
|
||||
final JobStatus js = new JobStatus(this, b.build(), SOME_UID, null, -1);
|
||||
final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
|
||||
mTaskStoreUnderTest.add(js);
|
||||
Thread.sleep(IO_WAIT);
|
||||
final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
|
||||
@@ -247,12 +247,12 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
JobInfo.Builder b = new Builder(42, mComponent)
|
||||
.setOverrideDeadline(10000)
|
||||
.setPersisted(false);
|
||||
JobStatus jsNonPersisted = new JobStatus(this, b.build(), SOME_UID, null, -1);
|
||||
JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
|
||||
mTaskStoreUnderTest.add(jsNonPersisted);
|
||||
b = new Builder(43, mComponent)
|
||||
.setOverrideDeadline(10000)
|
||||
.setPersisted(true);
|
||||
JobStatus jsPersisted = new JobStatus(this, b.build(), SOME_UID, null, -1);
|
||||
JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
|
||||
mTaskStoreUnderTest.add(jsPersisted);
|
||||
Thread.sleep(IO_WAIT);
|
||||
final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
|
||||
|
||||
Reference in New Issue
Block a user