Add new job scheduler constraints for "battery not low".
Clean up the implementation of boolean constraints so that they are in a single flags value that gets propagated all of the way from JobInfo.Builder in to the JobStatus. Much simpler and easier to add new constraints! Also introduce some shell commands to make it easier to write tests against the job scheduler (and other things tied to power). One of the big things here is that there is a new sequence number that propagates with battery updates, which we can look for in the job scheduler to determine when a change the test has made to battery state has actually gotten applied, to allow it to safely and minimally wait until executing the condition being tested. Test: New BatteryConstraintTest suite added. Change-Id: I11076d90b80ec25ee604c29b6a6dc2337fd867ce
This commit is contained in:
@@ -6718,6 +6718,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
|
||||
method public boolean isPeriodic();
|
||||
method public boolean isPersisted();
|
||||
method public boolean isRequireBatteryNotLow();
|
||||
method public boolean isRequireCharging();
|
||||
method public boolean isRequireDeviceIdle();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
@@ -6744,6 +6745,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
|
||||
method public android.app.job.JobInfo.Builder setPersisted(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
|
||||
method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
|
||||
method public android.app.job.JobInfo.Builder setTransientExtras(android.os.Bundle);
|
||||
|
||||
@@ -7110,6 +7110,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
|
||||
method public boolean isPeriodic();
|
||||
method public boolean isPersisted();
|
||||
method public boolean isRequireBatteryNotLow();
|
||||
method public boolean isRequireCharging();
|
||||
method public boolean isRequireDeviceIdle();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
@@ -7136,6 +7137,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
|
||||
method public android.app.job.JobInfo.Builder setPersisted(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
|
||||
method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
|
||||
method public android.app.job.JobInfo.Builder setTransientExtras(android.os.Bundle);
|
||||
|
||||
@@ -6744,6 +6744,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
|
||||
method public boolean isPeriodic();
|
||||
method public boolean isPersisted();
|
||||
method public boolean isRequireBatteryNotLow();
|
||||
method public boolean isRequireCharging();
|
||||
method public boolean isRequireDeviceIdle();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
@@ -6770,6 +6771,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
|
||||
method public android.app.job.JobInfo.Builder setPersisted(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
|
||||
method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
|
||||
method public android.app.job.JobInfo.Builder setTransientExtras(android.os.Bundle);
|
||||
|
||||
@@ -174,12 +174,26 @@ public class JobInfo implements Parcelable {
|
||||
*/
|
||||
public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONSTRAINT_FLAG_BATTERY_NOT_LOW = 1 << 1;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONSTRAINT_FLAG_DEVICE_IDLE = 1 << 2;
|
||||
|
||||
private final int jobId;
|
||||
private final PersistableBundle extras;
|
||||
private final Bundle transientExtras;
|
||||
private final ComponentName service;
|
||||
private final boolean requireCharging;
|
||||
private final boolean requireDeviceIdle;
|
||||
private final int constraintFlags;
|
||||
private final TriggerContentUri[] triggerContentUris;
|
||||
private final long triggerContentUpdateDelay;
|
||||
private final long triggerContentMaxDelay;
|
||||
@@ -241,14 +255,28 @@ public class JobInfo implements Parcelable {
|
||||
* Whether this job needs the device to be plugged in.
|
||||
*/
|
||||
public boolean isRequireCharging() {
|
||||
return requireCharging;
|
||||
return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this job needs the device's battery level to not be at below the critical threshold.
|
||||
*/
|
||||
public boolean isRequireBatteryNotLow() {
|
||||
return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this job needs the device to be in an Idle maintenance window.
|
||||
*/
|
||||
public boolean isRequireDeviceIdle() {
|
||||
return requireDeviceIdle;
|
||||
return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int getConstraintFlags() {
|
||||
return constraintFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,8 +404,7 @@ public class JobInfo implements Parcelable {
|
||||
extras = in.readPersistableBundle();
|
||||
transientExtras = in.readBundle();
|
||||
service = in.readParcelable(null);
|
||||
requireCharging = in.readInt() == 1;
|
||||
requireDeviceIdle = in.readInt() == 1;
|
||||
constraintFlags = in.readInt();
|
||||
triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
|
||||
triggerContentUpdateDelay = in.readLong();
|
||||
triggerContentMaxDelay = in.readLong();
|
||||
@@ -401,8 +428,7 @@ public class JobInfo implements Parcelable {
|
||||
extras = b.mExtras.deepcopy();
|
||||
transientExtras = b.mTransientExtras.deepcopy();
|
||||
service = b.mJobService;
|
||||
requireCharging = b.mRequiresCharging;
|
||||
requireDeviceIdle = b.mRequiresDeviceIdle;
|
||||
constraintFlags = b.mConstraintFlags;
|
||||
triggerContentUris = b.mTriggerContentUris != null
|
||||
? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
|
||||
: null;
|
||||
@@ -434,8 +460,7 @@ public class JobInfo implements Parcelable {
|
||||
out.writePersistableBundle(extras);
|
||||
out.writeBundle(transientExtras);
|
||||
out.writeParcelable(service, flags);
|
||||
out.writeInt(requireCharging ? 1 : 0);
|
||||
out.writeInt(requireDeviceIdle ? 1 : 0);
|
||||
out.writeInt(constraintFlags);
|
||||
out.writeTypedArray(triggerContentUris, flags);
|
||||
out.writeLong(triggerContentUpdateDelay);
|
||||
out.writeLong(triggerContentMaxDelay);
|
||||
@@ -563,8 +588,7 @@ public class JobInfo implements Parcelable {
|
||||
private int mPriority = PRIORITY_DEFAULT;
|
||||
private int mFlags;
|
||||
// Requirements.
|
||||
private boolean mRequiresCharging;
|
||||
private boolean mRequiresDeviceIdle;
|
||||
private int mConstraintFlags;
|
||||
private int mNetworkType;
|
||||
private ArrayList<TriggerContentUri> mTriggerContentUris;
|
||||
private long mTriggerContentUpdateDelay = -1;
|
||||
@@ -651,7 +675,21 @@ public class JobInfo implements Parcelable {
|
||||
* @param requiresCharging Whether or not the device is plugged in.
|
||||
*/
|
||||
public Builder setRequiresCharging(boolean requiresCharging) {
|
||||
mRequiresCharging = requiresCharging;
|
||||
mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
|
||||
| (requiresCharging ? CONSTRAINT_FLAG_CHARGING : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that to run this job, the device's battery level must not be low.
|
||||
* This defaults to false. If true, the job will only run when the battery level
|
||||
* is not low, which is generally the point where the user is given a "low battery"
|
||||
* warning.
|
||||
* @param batteryNotLow Whether or not the device's battery level must not be low.
|
||||
*/
|
||||
public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
|
||||
mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
|
||||
| (batteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -666,7 +704,8 @@ public class JobInfo implements Parcelable {
|
||||
* window.
|
||||
*/
|
||||
public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
|
||||
mRequiresDeviceIdle = requiresDeviceIdle;
|
||||
mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
|
||||
| (requiresDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -816,8 +855,8 @@ public class JobInfo implements Parcelable {
|
||||
*/
|
||||
public JobInfo build() {
|
||||
// Allow jobs with no constraints - What am I, a database?
|
||||
if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
|
||||
!mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE &&
|
||||
if (!mHasEarlyConstraint && !mHasLateConstraint && mConstraintFlags == 0 &&
|
||||
mNetworkType == NETWORK_TYPE_NONE &&
|
||||
mTriggerContentUris == null) {
|
||||
throw new IllegalArgumentException("You're trying to build a job with no " +
|
||||
"constraints, this is not allowed.");
|
||||
@@ -843,7 +882,7 @@ public class JobInfo implements Parcelable {
|
||||
throw new IllegalArgumentException("Can't call setTransientExtras() on a " +
|
||||
"persisted job");
|
||||
}
|
||||
if (mBackoffPolicySet && mRequiresDeviceIdle) {
|
||||
if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {
|
||||
throw new IllegalArgumentException("An idle mode job will not respect any" +
|
||||
" back-off policy, so calling setBackoffCriteria with" +
|
||||
" setRequiresDeviceIdle is an error.");
|
||||
|
||||
@@ -118,6 +118,13 @@ public class BatteryManager {
|
||||
*/
|
||||
public static final String EXTRA_CHARGE_COUNTER = "charge_counter";
|
||||
|
||||
/**
|
||||
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
|
||||
* Current int sequence number of the update.
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String EXTRA_SEQUENCE = "seq";
|
||||
|
||||
// values for "status" field in the ACTION_BATTERY_CHANGED Intent
|
||||
public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;
|
||||
public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;
|
||||
|
||||
@@ -130,6 +130,8 @@ public final class BatteryService extends SystemService {
|
||||
private int mLastMaxChargingVoltage;
|
||||
private int mLastChargeCounter;
|
||||
|
||||
private int mSequence = 1;
|
||||
|
||||
private int mInvalidCharger;
|
||||
private int mLastInvalidCharger;
|
||||
|
||||
@@ -448,27 +450,29 @@ public final class BatteryService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
sendIntentLocked();
|
||||
mSequence++;
|
||||
|
||||
// Separate broadcast is sent for power connected / not connected
|
||||
// since the standard intent will not wake any applications and some
|
||||
// applications may want to have smart behavior based on this.
|
||||
if (mPlugType != 0 && mLastPlugType == 0) {
|
||||
final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (mPlugType == 0 && mLastPlugType != 0) {
|
||||
final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
|
||||
}
|
||||
});
|
||||
@@ -476,26 +480,33 @@ public final class BatteryService extends SystemService {
|
||||
|
||||
if (shouldSendBatteryLowLocked()) {
|
||||
mSentLowBatteryBroadcast = true;
|
||||
final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
|
||||
}
|
||||
});
|
||||
} else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
|
||||
mSentLowBatteryBroadcast = false;
|
||||
final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
|
||||
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// We are doing this after sending the above broadcasts, so anything processing
|
||||
// them will get the new sequence number at that point. (See for example how testing
|
||||
// of JobScheduler's BatteryController works.)
|
||||
sendIntentLocked();
|
||||
|
||||
// Update the battery LED
|
||||
mLed.updateLightsLocked();
|
||||
|
||||
@@ -527,6 +538,7 @@ public final class BatteryService extends SystemService {
|
||||
|
||||
int icon = getIconLocked(mBatteryProps.batteryLevel);
|
||||
|
||||
intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
|
||||
intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
|
||||
intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
|
||||
intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
|
||||
@@ -666,12 +678,28 @@ public final class BatteryService extends SystemService {
|
||||
pw.println("Battery service (battery) commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Print this help text.");
|
||||
pw.println(" set [ac|usb|wireless|status|level|invalid] <value>");
|
||||
pw.println(" set [-f] [ac|usb|wireless|status|level|invalid] <value>");
|
||||
pw.println(" Force a battery property value, freezing battery state.");
|
||||
pw.println(" unplug");
|
||||
pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
|
||||
pw.println(" unplug [-f]");
|
||||
pw.println(" Force battery unplugged, freezing battery state.");
|
||||
pw.println(" reset");
|
||||
pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
|
||||
pw.println(" reset [-f]");
|
||||
pw.println(" Unfreeze battery state, returning to current hardware values.");
|
||||
pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
|
||||
}
|
||||
|
||||
static final int OPTION_FORCE_UPDATE = 1<<0;
|
||||
|
||||
int parseOptions(Shell shell) {
|
||||
String opt;
|
||||
int opts = 0;
|
||||
while ((opt = shell.getNextOption()) != null) {
|
||||
if ("-f".equals(opt)) {
|
||||
opts |= OPTION_FORCE_UPDATE;
|
||||
}
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
int onShellCommand(Shell shell, String cmd) {
|
||||
@@ -681,6 +709,7 @@ public final class BatteryService extends SystemService {
|
||||
PrintWriter pw = shell.getOutPrintWriter();
|
||||
switch (cmd) {
|
||||
case "unplug": {
|
||||
int opts = parseOptions(shell);
|
||||
getContext().enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.DEVICE_POWER, null);
|
||||
if (!mUpdatesStopped) {
|
||||
@@ -692,12 +721,13 @@ public final class BatteryService extends SystemService {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mUpdatesStopped = true;
|
||||
processValuesLocked(false);
|
||||
processValuesFromShellLocked(pw, opts);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
} break;
|
||||
case "set": {
|
||||
int opts = parseOptions(shell);
|
||||
getContext().enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.DEVICE_POWER, null);
|
||||
final String key = shell.getNextArg();
|
||||
@@ -745,7 +775,7 @@ public final class BatteryService extends SystemService {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mUpdatesStopped = true;
|
||||
processValuesLocked(false);
|
||||
processValuesFromShellLocked(pw, opts);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -756,6 +786,7 @@ public final class BatteryService extends SystemService {
|
||||
}
|
||||
} break;
|
||||
case "reset": {
|
||||
int opts = parseOptions(shell);
|
||||
getContext().enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.DEVICE_POWER, null);
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
@@ -763,7 +794,7 @@ public final class BatteryService extends SystemService {
|
||||
if (mUpdatesStopped) {
|
||||
mUpdatesStopped = false;
|
||||
mBatteryProps.set(mLastBatteryProps);
|
||||
processValuesLocked(false);
|
||||
processValuesFromShellLocked(pw, opts);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
@@ -775,6 +806,13 @@ public final class BatteryService extends SystemService {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void processValuesFromShellLocked(PrintWriter pw, int opts) {
|
||||
processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
|
||||
if ((opts & OPTION_FORCE_UPDATE) != 0) {
|
||||
pw.println(mSequence);
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
synchronized (mLock) {
|
||||
if (args == null || args.length == 0 || "-a".equals(args[0])) {
|
||||
|
||||
@@ -437,7 +437,7 @@ public final class JobPackageTracker {
|
||||
for (int i=0; i<size; i++) {
|
||||
final int index = mEventIndices.indexOf(i);
|
||||
final int uid = mEventUids[index];
|
||||
if (filterUid != -1 && filterUid != UserHandle.getAppId(filterUid)) {
|
||||
if (filterUid != -1 && filterUid != UserHandle.getAppId(uid)) {
|
||||
continue;
|
||||
}
|
||||
final int cmd = mEventCmds[index];
|
||||
|
||||
@@ -131,6 +131,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
final List<JobServiceContext> mActiveServices = new ArrayList<>();
|
||||
/** List of controllers that will notify this service of updates to jobs. */
|
||||
List<StateController> mControllers;
|
||||
/** Need direct access to this for testing. */
|
||||
BatteryController mBatteryController;
|
||||
/**
|
||||
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
|
||||
* when ready to execute them.
|
||||
@@ -194,6 +196,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
// Key names stored in the settings value.
|
||||
private static final String KEY_MIN_IDLE_COUNT = "min_idle_count";
|
||||
private static final String KEY_MIN_CHARGING_COUNT = "min_charging_count";
|
||||
private static final String KEY_MIN_BATTERY_NOT_LOW_COUNT = "min_battery_not_low_count";
|
||||
private static final String KEY_MIN_CONNECTIVITY_COUNT = "min_connectivity_count";
|
||||
private static final String KEY_MIN_CONTENT_COUNT = "min_content_count";
|
||||
private static final String KEY_MIN_READY_JOBS_COUNT = "min_ready_jobs_count";
|
||||
@@ -207,6 +210,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
|
||||
private static final int DEFAULT_MIN_IDLE_COUNT = 1;
|
||||
private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
|
||||
private static final int DEFAULT_MIN_BATTERY_NOT_LOW_COUNT = 1;
|
||||
private static final int DEFAULT_MIN_CONNECTIVITY_COUNT = 1;
|
||||
private static final int DEFAULT_MIN_CONTENT_COUNT = 1;
|
||||
private static final int DEFAULT_MIN_READY_JOBS_COUNT = 1;
|
||||
@@ -228,6 +232,11 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
* things early.
|
||||
*/
|
||||
int MIN_CHARGING_COUNT = DEFAULT_MIN_CHARGING_COUNT;
|
||||
/**
|
||||
* Minimum # of "battery not low" jobs that must be ready in order to force the JMS to
|
||||
* schedule things early.
|
||||
*/
|
||||
int MIN_BATTERY_NOT_LOW_COUNT = DEFAULT_MIN_BATTERY_NOT_LOW_COUNT;
|
||||
/**
|
||||
* Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
|
||||
* things early. 1 == Run connectivity jobs as soon as ready.
|
||||
@@ -312,6 +321,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
DEFAULT_MIN_IDLE_COUNT);
|
||||
MIN_CHARGING_COUNT = mParser.getInt(KEY_MIN_CHARGING_COUNT,
|
||||
DEFAULT_MIN_CHARGING_COUNT);
|
||||
MIN_BATTERY_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_BATTERY_NOT_LOW_COUNT,
|
||||
DEFAULT_MIN_BATTERY_NOT_LOW_COUNT);
|
||||
MIN_CONNECTIVITY_COUNT = mParser.getInt(KEY_MIN_CONNECTIVITY_COUNT,
|
||||
DEFAULT_MIN_CONNECTIVITY_COUNT);
|
||||
MIN_CONTENT_COUNT = mParser.getInt(KEY_MIN_CONTENT_COUNT,
|
||||
@@ -356,6 +367,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
pw.print(" "); pw.print(KEY_MIN_CHARGING_COUNT); pw.print("=");
|
||||
pw.print(MIN_CHARGING_COUNT); pw.println();
|
||||
|
||||
pw.print(" "); pw.print(KEY_MIN_BATTERY_NOT_LOW_COUNT); pw.print("=");
|
||||
pw.print(MIN_BATTERY_NOT_LOW_COUNT); pw.println();
|
||||
|
||||
pw.print(" "); pw.print(KEY_MIN_CONNECTIVITY_COUNT); pw.print("=");
|
||||
pw.print(MIN_CONNECTIVITY_COUNT); pw.println();
|
||||
|
||||
@@ -785,7 +799,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
mControllers.add(ConnectivityController.get(this));
|
||||
mControllers.add(TimeController.get(this));
|
||||
mControllers.add(IdleController.get(this));
|
||||
mControllers.add(BatteryController.get(this));
|
||||
mBatteryController = BatteryController.get(this);
|
||||
mControllers.add(mBatteryController);
|
||||
mControllers.add(AppIdleController.get(this));
|
||||
mControllers.add(ContentObserverController.get(this));
|
||||
mControllers.add(DeviceIdleJobsController.get(this));
|
||||
@@ -1186,6 +1201,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
*/
|
||||
class MaybeReadyJobQueueFunctor implements JobStatusFunctor {
|
||||
int chargingCount;
|
||||
int batteryNotLowCount;
|
||||
int idleCount;
|
||||
int backoffCount;
|
||||
int connectivityCount;
|
||||
@@ -1223,6 +1239,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
if (job.hasChargingConstraint()) {
|
||||
chargingCount++;
|
||||
}
|
||||
if (job.hasBatteryNotLowConstraint()) {
|
||||
batteryNotLowCount++;
|
||||
}
|
||||
if (job.hasContentTriggerConstraint()) {
|
||||
contentCount++;
|
||||
}
|
||||
@@ -1241,6 +1260,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
idleCount >= mConstants.MIN_IDLE_COUNT ||
|
||||
connectivityCount >= mConstants.MIN_CONNECTIVITY_COUNT ||
|
||||
chargingCount >= mConstants.MIN_CHARGING_COUNT ||
|
||||
batteryNotLowCount >= mConstants.MIN_BATTERY_NOT_LOW_COUNT ||
|
||||
contentCount >= mConstants.MIN_CONTENT_COUNT ||
|
||||
(runnableJobs != null
|
||||
&& runnableJobs.size() >= mConstants.MIN_READY_JOBS_COUNT)) {
|
||||
@@ -1264,6 +1284,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
idleCount = 0;
|
||||
backoffCount = 0;
|
||||
connectivityCount = 0;
|
||||
batteryNotLowCount = 0;
|
||||
contentCount = 0;
|
||||
runnableJobs = null;
|
||||
}
|
||||
@@ -1764,6 +1785,34 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setMonitorBattery(boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
if (mBatteryController != null) {
|
||||
mBatteryController.getTracker().setMonitorBatteryLocked(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getBatterySeq() {
|
||||
synchronized (mLock) {
|
||||
return mBatteryController != null ? mBatteryController.getTracker().getSeq() : -1;
|
||||
}
|
||||
}
|
||||
|
||||
boolean getBatteryCharging() {
|
||||
synchronized (mLock) {
|
||||
return mBatteryController != null
|
||||
? mBatteryController.getTracker().isOnStablePower() : false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean getBatteryNotLow() {
|
||||
synchronized (mLock) {
|
||||
return mBatteryController != null
|
||||
? mBatteryController.getTracker().isBatteryNotLow() : false;
|
||||
}
|
||||
}
|
||||
|
||||
private String printContextIdToJobMap(JobStatus[] map, String initial) {
|
||||
StringBuilder s = new StringBuilder(initial + ": ");
|
||||
for (int i=0; i<map.length; i++) {
|
||||
|
||||
@@ -43,10 +43,19 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
public int onCommand(String cmd) {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
try {
|
||||
if ("run".equals(cmd)) {
|
||||
return runJob();
|
||||
} else {
|
||||
return handleDefaultCommands(cmd);
|
||||
switch (cmd != null ? cmd : "") {
|
||||
case "run":
|
||||
return runJob(pw);
|
||||
case "monitor-battery":
|
||||
return runMonitorBattery(pw);
|
||||
case "get-battery-seq":
|
||||
return runGetBatterySeq(pw);
|
||||
case "get-battery-charging":
|
||||
return runGetBatteryCharging(pw);
|
||||
case "get-battery-not-low":
|
||||
return runGetBatteryNotLow(pw);
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
pw.println("Exception: " + e);
|
||||
@@ -54,20 +63,23 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int runJob() {
|
||||
try {
|
||||
final int uid = Binder.getCallingUid();
|
||||
final int perm = mPM.checkUidPermission(
|
||||
"android.permission.CHANGE_APP_IDLE_STATE", uid);
|
||||
if (perm != PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Uid " + uid
|
||||
+ " not permitted to force scheduled jobs");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// Can't happen
|
||||
private void checkPermission(String operation) throws Exception {
|
||||
final int uid = Binder.getCallingUid();
|
||||
if (uid == 0) {
|
||||
// Root can do anything.
|
||||
return;
|
||||
}
|
||||
final int perm = mPM.checkUidPermission(
|
||||
"android.permission.CHANGE_APP_IDLE_STATE", uid);
|
||||
if (perm != PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Uid " + uid
|
||||
+ " not permitted to " + operation);
|
||||
}
|
||||
}
|
||||
|
||||
private int runJob(PrintWriter pw) throws Exception {
|
||||
checkPermission("force scheduled jobs");
|
||||
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
boolean force = false;
|
||||
int userId = UserHandle.USER_SYSTEM;
|
||||
|
||||
@@ -133,6 +145,42 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private int runMonitorBattery(PrintWriter pw) throws Exception {
|
||||
checkPermission("change battery monitoring");
|
||||
String opt = getNextArgRequired();
|
||||
boolean enabled;
|
||||
if ("on".equals(opt)) {
|
||||
enabled = true;
|
||||
} else if ("off".equals(opt)) {
|
||||
enabled = false;
|
||||
} else {
|
||||
getErrPrintWriter().println("Error: unknown option " + opt);
|
||||
return 1;
|
||||
}
|
||||
mInternal.setMonitorBattery(enabled);
|
||||
if (enabled) pw.println("Battery monitoring enabled");
|
||||
else pw.println("Battery monitoring disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runGetBatterySeq(PrintWriter pw) {
|
||||
int seq = mInternal.getBatterySeq();
|
||||
pw.println(seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runGetBatteryCharging(PrintWriter pw) {
|
||||
boolean val = mInternal.getBatteryCharging();
|
||||
pw.println(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runGetBatteryNotLow(PrintWriter pw) {
|
||||
boolean val = mInternal.getBatteryNotLow();
|
||||
pw.println(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
@@ -140,7 +188,6 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
pw.println("Job scheduler (jobscheduler) commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Print this help text.");
|
||||
pw.println();
|
||||
pw.println(" run [-f | --force] [-u | --user USER_ID] PACKAGE JOB_ID");
|
||||
pw.println(" Trigger immediate execution of a specific scheduled job.");
|
||||
pw.println(" Options:");
|
||||
@@ -148,6 +195,15 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
pw.println(" connectivity are not currently met");
|
||||
pw.println(" -u or --user: specify which user's job is to be run; the default is");
|
||||
pw.println(" the primary or system user");
|
||||
pw.println(" monitor-battery [on|off]");
|
||||
pw.println(" Control monitoring of all battery changes. Off by default. Turning");
|
||||
pw.println(" on makes get-battery-seq useful.");
|
||||
pw.println(" get-battery-seq");
|
||||
pw.println(" Return the last battery update sequence number that was received.");
|
||||
pw.println(" get-battery-charging");
|
||||
pw.println(" Return whether the battery is currently considered to be charging.");
|
||||
pw.println(" get-battery-not-low");
|
||||
pw.println(" Return whether the battery is currently considered to not be low.");
|
||||
pw.println();
|
||||
}
|
||||
|
||||
|
||||
@@ -381,6 +381,9 @@ public class JobStore {
|
||||
if (jobStatus.hasChargingConstraint()) {
|
||||
out.attribute(null, "charging", Boolean.toString(true));
|
||||
}
|
||||
if (jobStatus.hasBatteryNotLowConstraint()) {
|
||||
out.attribute(null, "battery-not-low", Boolean.toString(true));
|
||||
}
|
||||
out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,32 +80,38 @@ public class BatteryController extends StateController {
|
||||
|
||||
@Override
|
||||
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
|
||||
final boolean isOnStablePower = mChargeTracker.isOnStablePower();
|
||||
if (taskStatus.hasChargingConstraint()) {
|
||||
if (taskStatus.hasPowerConstraint()) {
|
||||
mTrackedTasks.add(taskStatus);
|
||||
taskStatus.setChargingConstraintSatisfied(isOnStablePower);
|
||||
taskStatus.setChargingConstraintSatisfied(mChargeTracker.isOnStablePower());
|
||||
taskStatus.setBatteryNotLowConstraintSatisfied(mChargeTracker.isBatteryNotLow());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob, boolean forUpdate) {
|
||||
if (taskStatus.hasChargingConstraint()) {
|
||||
if (taskStatus.hasPowerConstraint()) {
|
||||
mTrackedTasks.remove(taskStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeReportNewChargingState() {
|
||||
final boolean stablePower = mChargeTracker.isOnStablePower();
|
||||
final boolean batteryNotLow = mChargeTracker.isBatteryNotLow();
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
|
||||
}
|
||||
boolean reportChange = false;
|
||||
synchronized (mLock) {
|
||||
for (JobStatus ts : mTrackedTasks) {
|
||||
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
|
||||
final JobStatus ts = mTrackedTasks.get(i);
|
||||
boolean previous = ts.setChargingConstraintSatisfied(stablePower);
|
||||
if (previous != stablePower) {
|
||||
reportChange = true;
|
||||
}
|
||||
previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow);
|
||||
if (previous != batteryNotLow) {
|
||||
reportChange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Let the scheduler know that state has changed. This may or may not result in an
|
||||
@@ -127,6 +133,10 @@ public class BatteryController extends StateController {
|
||||
private boolean mCharging;
|
||||
/** Keep track of whether the battery is charged enough that we want to do work. */
|
||||
private boolean mBatteryHealthy;
|
||||
/** Sequence number of last broadcast. */
|
||||
private int mLastBatterySeq = -1;
|
||||
|
||||
private BroadcastReceiver mMonitor;
|
||||
|
||||
public ChargingTracker() {
|
||||
}
|
||||
@@ -149,10 +159,42 @@ public class BatteryController extends StateController {
|
||||
mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
|
||||
}
|
||||
|
||||
boolean isOnStablePower() {
|
||||
public void setMonitorBatteryLocked(boolean enabled) {
|
||||
if (enabled) {
|
||||
if (mMonitor == null) {
|
||||
mMonitor = new BroadcastReceiver() {
|
||||
@Override public void onReceive(Context context, Intent intent) {
|
||||
ChargingTracker.this.onReceive(context, intent);
|
||||
}
|
||||
};
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
mContext.registerReceiver(mMonitor, filter);
|
||||
}
|
||||
} else {
|
||||
if (mMonitor != null) {
|
||||
mContext.unregisterReceiver(mMonitor);
|
||||
mMonitor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOnStablePower() {
|
||||
return mCharging && mBatteryHealthy;
|
||||
}
|
||||
|
||||
public boolean isBatteryNotLow() {
|
||||
return mBatteryHealthy;
|
||||
}
|
||||
|
||||
public boolean isMonitoring() {
|
||||
return mMonitor != null;
|
||||
}
|
||||
|
||||
public int getSeq() {
|
||||
return mLastBatterySeq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
onReceiveInternal(intent);
|
||||
@@ -191,13 +233,20 @@ public class BatteryController extends StateController {
|
||||
mCharging = false;
|
||||
maybeReportNewChargingState();
|
||||
}
|
||||
mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE, mLastBatterySeq);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
|
||||
pw.print("Battery: stable power = ");
|
||||
pw.println(mChargeTracker.isOnStablePower());
|
||||
pw.print(mChargeTracker.isOnStablePower());
|
||||
pw.print(", not low = ");
|
||||
pw.println(mChargeTracker.isBatteryNotLow());
|
||||
if (mChargeTracker.isMonitoring()) {
|
||||
pw.print("MONITORING: seq=");
|
||||
pw.println(mChargeTracker.getSeq());
|
||||
}
|
||||
pw.print("Tracking ");
|
||||
pw.print(mTrackedTasks.size());
|
||||
pw.println(":");
|
||||
|
||||
@@ -46,16 +46,17 @@ public final class JobStatus {
|
||||
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
|
||||
public static final long NO_EARLIEST_RUNTIME = 0L;
|
||||
|
||||
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;
|
||||
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<8;
|
||||
static final int CONSTRAINT_NOT_ROAMING = 1<<9;
|
||||
static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING;
|
||||
static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;
|
||||
static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW;
|
||||
static final int CONSTRAINT_TIMING_DELAY = 1<<31;
|
||||
static final int CONSTRAINT_DEADLINE = 1<<30;
|
||||
static final int CONSTRAINT_UNMETERED = 1<<29;
|
||||
static final int CONSTRAINT_CONNECTIVITY = 1<<28;
|
||||
static final int CONSTRAINT_APP_NOT_IDLE = 1<<27;
|
||||
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
|
||||
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
|
||||
static final int CONSTRAINT_NOT_ROAMING = 1<<24;
|
||||
|
||||
// Soft override: ignore constraints like time that don't affect API availability
|
||||
public static final int OVERRIDE_SOFT = 1;
|
||||
@@ -163,7 +164,7 @@ public final class JobStatus {
|
||||
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
|
||||
this.numFailures = numFailures;
|
||||
|
||||
int requiredConstraints = 0;
|
||||
int requiredConstraints = job.getConstraintFlags();
|
||||
if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
|
||||
requiredConstraints |= CONSTRAINT_CONNECTIVITY;
|
||||
}
|
||||
@@ -173,18 +174,12 @@ public final class JobStatus {
|
||||
if (job.getNetworkType() == JobInfo.NETWORK_TYPE_NOT_ROAMING) {
|
||||
requiredConstraints |= CONSTRAINT_NOT_ROAMING;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -331,6 +326,14 @@ public final class JobStatus {
|
||||
return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
|
||||
}
|
||||
|
||||
public boolean hasBatteryNotLowConstraint() {
|
||||
return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0;
|
||||
}
|
||||
|
||||
public boolean hasPowerConstraint() {
|
||||
return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0;
|
||||
}
|
||||
|
||||
public boolean hasTimingDelayConstraint() {
|
||||
return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
|
||||
}
|
||||
@@ -379,6 +382,10 @@ public final class JobStatus {
|
||||
return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
|
||||
}
|
||||
|
||||
boolean setBatteryNotLowConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
|
||||
}
|
||||
|
||||
boolean setTimingDelayConstraintSatisfied(boolean state) {
|
||||
return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
|
||||
}
|
||||
@@ -453,13 +460,14 @@ public final class JobStatus {
|
||||
}
|
||||
|
||||
static final int CONSTRAINTS_OF_INTEREST =
|
||||
CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
|
||||
CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_TIMING_DELAY |
|
||||
CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING |
|
||||
CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
|
||||
|
||||
// Soft override covers all non-"functional" constraints
|
||||
static final int SOFT_OVERRIDE_CONSTRAINTS =
|
||||
CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
|
||||
CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
|
||||
| CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
|
||||
|
||||
/**
|
||||
* @return Whether the constraints set on this job are satisfied.
|
||||
@@ -495,6 +503,7 @@ public final class JobStatus {
|
||||
+ ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
|
||||
+ "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
|
||||
+ ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
|
||||
+ ",BL=" + job.isRequireBatteryNotLow()
|
||||
+ ",I=" + job.isRequireDeviceIdle()
|
||||
+ ",U=" + (job.getTriggerContentUris() != null)
|
||||
+ ",F=" + numFailures + ",P=" + job.isPersisted()
|
||||
@@ -550,6 +559,9 @@ public final class JobStatus {
|
||||
if ((constraints&CONSTRAINT_CHARGING) != 0) {
|
||||
pw.print(" CHARGING");
|
||||
}
|
||||
if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
|
||||
pw.print(" BATTERY_NOT_LOW");
|
||||
}
|
||||
if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
|
||||
pw.print(" TIMING_DELAY");
|
||||
}
|
||||
@@ -607,7 +619,8 @@ public final class JobStatus {
|
||||
pw.println(Integer.toHexString(job.getFlags()));
|
||||
}
|
||||
pw.print(prefix); pw.print(" Requires: charging=");
|
||||
pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
|
||||
pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
|
||||
pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
|
||||
pw.println(job.isRequireDeviceIdle());
|
||||
if (job.getTriggerContentUris() != null) {
|
||||
pw.print(prefix); pw.println(" Trigger content URIs:");
|
||||
|
||||
@@ -10,7 +10,6 @@ import android.os.SystemClock;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.RenamingDelegatingContext;
|
||||
import android.util.Log;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.server.job.JobStore.JobSet;
|
||||
import com.android.server.job.controllers.JobStatus;
|
||||
@@ -278,6 +277,8 @@ public class JobStoreTest extends AndroidTestCase {
|
||||
|
||||
assertEquals("Invalid charging constraint.", first.isRequireCharging(),
|
||||
second.isRequireCharging());
|
||||
assertEquals("Invalid battery not low constraint.", first.isRequireBatteryNotLow(),
|
||||
second.isRequireBatteryNotLow());
|
||||
assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
|
||||
second.isRequireDeviceIdle());
|
||||
assertEquals("Invalid unmetered constraint.",
|
||||
|
||||
Reference in New Issue
Block a user