Merge "Remove internal locking from JobStatus." into nyc-dev

am: 044a802b26

* commit '044a802b26557aef84da074801ee818ba24f86b6':
  Remove internal locking from JobStatus.
This commit is contained in:
Dianne Hackborn
2016-02-20 02:55:36 +00:00
committed by android-build-merger
11 changed files with 426 additions and 413 deletions

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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) {

View File

@@ -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();
}
}
}

View File

@@ -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("..");
}
}
}

View File

@@ -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++) {

View File

@@ -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);
}

View File

@@ -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(

View File

@@ -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>();