blob: 072787b19dc5f9e3ac1228c17b7c39e69765bbb0 [file] [log] [blame]
Christopher Tate7060b042014-06-09 19:50:00 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.job.controllers;
18
Shreyas Basarge968ac752016-01-11 23:09:26 +000019import android.app.AppGlobals;
Christopher Tate7060b042014-06-09 19:50:00 -070020import android.app.job.JobInfo;
21import android.content.ComponentName;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080022import android.net.Uri;
Christopher Tate7060b042014-06-09 19:50:00 -070023import android.os.PersistableBundle;
Shreyas Basarge968ac752016-01-11 23:09:26 +000024import android.os.RemoteException;
Christopher Tate7060b042014-06-09 19:50:00 -070025import android.os.SystemClock;
26import android.os.UserHandle;
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070027import android.text.format.DateUtils;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080028import android.util.ArraySet;
29import android.util.TimeUtils;
Christopher Tate7060b042014-06-09 19:50:00 -070030
31import java.io.PrintWriter;
Christopher Tate7060b042014-06-09 19:50:00 -070032
33/**
34 * Uniquely identifies a job internally.
35 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
36 * Contains current state of the requirements of the job, as well as a function to evaluate
37 * whether it's ready to run.
38 * This object is shared among the various controllers - hence why the different fields are atomic.
39 * This isn't strictly necessary because each controller is only interested in a specific field,
40 * and the receivers that are listening for global state change will all run on the main looper,
41 * but we don't enforce that so this is safer.
42 * @hide
43 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -080044public final class JobStatus {
Christopher Tate7060b042014-06-09 19:50:00 -070045 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
46 public static final long NO_EARLIEST_RUNTIME = 0L;
47
Dianne Hackbornb0001f62016-02-16 10:30:33 -080048 static final int CONSTRAINT_CHARGING = 1<<0;
49 static final int CONSTRAINT_TIMING_DELAY = 1<<1;
50 static final int CONSTRAINT_DEADLINE = 1<<2;
51 static final int CONSTRAINT_IDLE = 1<<3;
52 static final int CONSTRAINT_UNMETERED = 1<<4;
53 static final int CONSTRAINT_CONNECTIVITY = 1<<5;
54 static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
55 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
Amith Yamasanicb926fc2016-03-14 17:15:20 -070056 static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<8;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060057 static final int CONSTRAINT_NOT_ROAMING = 1<<9;
Dianne Hackbornb0001f62016-02-16 10:30:33 -080058
Christopher Tate5d346052016-03-08 12:56:08 -080059 // Soft override: ignore constraints like time that don't affect API availability
60 public static final int OVERRIDE_SOFT = 1;
61 // Full override: ignore all constraints including API-affecting like connectivity
62 public static final int OVERRIDE_FULL = 2;
63
Dianne Hackborn8db0fc12016-04-12 13:48:25 -070064 /** If not specified, trigger update delay is 10 seconds. */
65 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
66
67 /** The minimum possible update delay is 1/2 second. */
68 public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
69
70 /** If not specified, trigger maxumum delay is 2 minutes. */
71 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
72
73 /** The minimum possible update delay is 1 second. */
74 public static final long MIN_TRIGGER_MAX_DELAY = 1000;
75
Christopher Tate7060b042014-06-09 19:50:00 -070076 final JobInfo job;
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070077 /** Uid of the package requesting this job. */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000078 final int callingUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080079 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -070080
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000081 final String sourcePackageName;
82 final int sourceUserId;
83 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080084 final String sourceTag;
85
86 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +000087
Dianne Hackbornb0001f62016-02-16 10:30:33 -080088 /**
89 * Earliest point in the future at which this job will be eligible to run. A value of 0
90 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
91 */
92 private final long earliestRunTimeElapsedMillis;
93 /**
94 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
95 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
96 */
97 private final long latestRunTimeElapsedMillis;
98
99 /** How many times this job has failed, used to compute back-off. */
100 private final int numFailures;
101
Christopher Tate7060b042014-06-09 19:50:00 -0700102 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800103 final int requiredConstraints;
104 int satisfiedConstraints = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800105
106 // These are filled in by controllers when preparing for execution.
107 public ArraySet<Uri> changedUris;
108 public ArraySet<String> changedAuthorities;
109
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800110 public int lastEvaluatedPriority;
111
Christopher Tate5d346052016-03-08 12:56:08 -0800112 // Used by shell commands
113 public int overrideState = 0;
114
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800115 /**
116 * For use only by ContentObserverController: state it is maintaining about content URIs
117 * being observed.
118 */
119 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -0700120
Christopher Tate7060b042014-06-09 19:50:00 -0700121 /** Provide a handle to the service that this job will be run on. */
122 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000123 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700124 }
125
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800126 private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800127 int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800128 long latestRunTimeElapsedMillis) {
Christopher Tate7060b042014-06-09 19:50:00 -0700129 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000130 this.callingUid = callingUid;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000131
132 int tempSourceUid = -1;
133 if (sourceUserId != -1 && sourcePackageName != null) {
134 try {
135 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
136 sourceUserId);
137 } catch (RemoteException ex) {
138 // Can't happen, PackageManager runs in the same process.
139 }
140 }
141 if (tempSourceUid == -1) {
142 this.sourceUid = callingUid;
143 this.sourceUserId = UserHandle.getUserId(callingUid);
144 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800145 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000146 } else {
147 this.sourceUid = tempSourceUid;
148 this.sourceUserId = sourceUserId;
149 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800150 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000151 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800152
Shreyas Basargeeda34e42016-04-26 00:14:02 +0100153 this.batteryName = this.sourceTag != null
154 ? this.sourceTag + ":" + job.getService().getPackageName()
155 : job.getService().flattenToShortString();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800156 this.tag = "*job*/" + this.batteryName;
157
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800158 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
159 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
160 this.numFailures = numFailures;
161
162 int requiredConstraints = 0;
163 if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
164 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
165 }
166 if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
167 requiredConstraints |= CONSTRAINT_UNMETERED;
168 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600169 if (job.getNetworkType() == JobInfo.NETWORK_TYPE_NOT_ROAMING) {
170 requiredConstraints |= CONSTRAINT_NOT_ROAMING;
171 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800172 if (job.isRequireCharging()) {
173 requiredConstraints |= CONSTRAINT_CHARGING;
174 }
175 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
176 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
177 }
178 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
179 requiredConstraints |= CONSTRAINT_DEADLINE;
180 }
181 if (job.isRequireDeviceIdle()) {
182 requiredConstraints |= CONSTRAINT_IDLE;
183 }
184 if (job.getTriggerContentUris() != null) {
185 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
186 }
187 this.requiredConstraints = requiredConstraints;
Christopher Tate7060b042014-06-09 19:50:00 -0700188 }
189
Matthew Williams0cc76542015-10-16 21:04:51 -0700190 /** Copy constructor. */
191 public JobStatus(JobStatus jobStatus) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800192 this(jobStatus.getJob(), jobStatus.getUid(),
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800193 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800194 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
195 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
Christopher Tate7060b042014-06-09 19:50:00 -0700196 }
197
198 /**
199 * Create a new JobStatus that was loaded from disk. We ignore the provided
200 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
201 * from the {@link com.android.server.job.JobStore} and still want to respect its
202 * wallclock runtime rather than resetting it on every boot.
203 * We consider a freshly loaded job to no longer be in back-off.
204 */
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800205 public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
206 String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
207 this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
208 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700209 }
210
211 /** Create a new job to be rescheduled with the provided parameters. */
212 public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
213 long newLatestRuntimeElapsedMillis, int backoffAttempt) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800214 this(rescheduling.job, rescheduling.getUid(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800215 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
216 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800217 newLatestRuntimeElapsedMillis);
218 }
Christopher Tate7060b042014-06-09 19:50:00 -0700219
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800220 /**
221 * Create a newly scheduled job.
222 * @param callingUid Uid of the package that scheduled this job.
223 * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
224 * the calling package is the source.
225 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
226 */
227 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800228 int sourceUserId, String tag) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800229 final long elapsedNow = SystemClock.elapsedRealtime();
230 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
231 if (job.isPeriodic()) {
232 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
233 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
234 } else {
235 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
236 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
237 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
238 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
239 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800240 return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800241 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700242 }
243
244 public JobInfo getJob() {
245 return job;
246 }
247
248 public int getJobId() {
249 return job.getId();
250 }
251
252 public int getNumFailures() {
253 return numFailures;
254 }
255
256 public ComponentName getServiceComponent() {
257 return job.getService();
258 }
259
Shreyas Basarge968ac752016-01-11 23:09:26 +0000260 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000261 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000262 }
263
264 public int getSourceUid() {
265 return sourceUid;
266 }
267
268 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000269 return sourceUserId;
270 }
271
Christopher Tate7060b042014-06-09 19:50:00 -0700272 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000273 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700274 }
275
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800276 public String getSourceTag() {
277 return sourceTag;
278 }
279
Christopher Tate7060b042014-06-09 19:50:00 -0700280 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000281 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700282 }
283
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800284 public String getBatteryName() {
285 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700286 }
287
288 public String getTag() {
289 return tag;
290 }
291
Christopher Tate7060b042014-06-09 19:50:00 -0700292 public PersistableBundle getExtras() {
293 return job.getExtras();
294 }
Shreyas Basarge968ac752016-01-11 23:09:26 +0000295
Shreyas Basarge5db09082016-01-07 13:38:29 +0000296 public int getPriority() {
297 return job.getPriority();
298 }
Christopher Tate7060b042014-06-09 19:50:00 -0700299
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600300 public int getFlags() {
301 return job.getFlags();
302 }
303
Christopher Tate7060b042014-06-09 19:50:00 -0700304 public boolean hasConnectivityConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800305 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700306 }
307
308 public boolean hasUnmeteredConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800309 return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700310 }
311
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600312 public boolean hasNotRoamingConstraint() {
313 return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0;
314 }
315
Christopher Tate7060b042014-06-09 19:50:00 -0700316 public boolean hasChargingConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800317 return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700318 }
319
320 public boolean hasTimingDelayConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800321 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700322 }
323
324 public boolean hasDeadlineConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800325 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700326 }
327
328 public boolean hasIdleConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800329 return (requiredConstraints&CONSTRAINT_IDLE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700330 }
331
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800332 public boolean hasContentTriggerConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800333 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800334 }
335
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700336 public long getTriggerContentUpdateDelay() {
337 long time = job.getTriggerContentUpdateDelay();
338 if (time < 0) {
339 return DEFAULT_TRIGGER_UPDATE_DELAY;
340 }
341 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
342 }
343
344 public long getTriggerContentMaxDelay() {
345 long time = job.getTriggerContentMaxDelay();
346 if (time < 0) {
347 return DEFAULT_TRIGGER_MAX_DELAY;
348 }
349 return Math.max(time, MIN_TRIGGER_MAX_DELAY);
350 }
351
Matthew Williams900c67f2014-07-09 12:46:53 -0700352 public boolean isPersisted() {
353 return job.isPersisted();
354 }
355
Christopher Tate7060b042014-06-09 19:50:00 -0700356 public long getEarliestRunTime() {
357 return earliestRunTimeElapsedMillis;
358 }
359
360 public long getLatestRunTimeElapsed() {
361 return latestRunTimeElapsedMillis;
362 }
363
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800364 boolean setChargingConstraintSatisfied(boolean state) {
365 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
366 }
367
368 boolean setTimingDelayConstraintSatisfied(boolean state) {
369 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
370 }
371
372 boolean setDeadlineConstraintSatisfied(boolean state) {
373 return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
374 }
375
376 boolean setIdleConstraintSatisfied(boolean state) {
377 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
378 }
379
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600380 boolean setConnectivityConstraintSatisfied(boolean state) {
381 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
382 }
383
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800384 boolean setUnmeteredConstraintSatisfied(boolean state) {
385 return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
386 }
387
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600388 boolean setNotRoamingConstraintSatisfied(boolean state) {
389 return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800390 }
391
392 boolean setAppNotIdleConstraintSatisfied(boolean state) {
393 return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
394 }
395
396 boolean setContentTriggerConstraintSatisfied(boolean state) {
397 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
398 }
399
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700400 boolean setDeviceNotDozingConstraintSatisfied(boolean state) {
401 return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
402 }
403
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800404 boolean setConstraintSatisfied(int constraint, boolean state) {
405 boolean old = (satisfiedConstraints&constraint) != 0;
406 if (old == state) {
407 return false;
408 }
409 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
410 return true;
411 }
412
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700413 public boolean shouldDump(int filterUid) {
414 return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
415 || UserHandle.getAppId(getSourceUid()) == filterUid;
416 }
417
Christopher Tate7060b042014-06-09 19:50:00 -0700418 /**
Matthew Williams03a4da62014-09-10 17:32:18 -0700419 * @return Whether or not this job is ready to run, based on its requirements. This is true if
420 * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
Christopher Tate7060b042014-06-09 19:50:00 -0700421 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800422 public boolean isReady() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800423 // Deadline constraint trumps other constraints (except for periodic jobs where deadline
Christopher Tate5d346052016-03-08 12:56:08 -0800424 // is an implementation detail. A periodic job should only run if its constraints are
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800425 // satisfied).
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700426 // AppNotIdle implicit constraint must be satisfied
427 // DeviceNotDozing implicit constraint must be satisfied
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600428 final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
429 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
430 final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
431 final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
432 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
433 return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing;
Matthew Williams03a4da62014-09-10 17:32:18 -0700434 }
435
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800436 static final int CONSTRAINTS_OF_INTEREST =
437 CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600438 CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING |
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800439 CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
440
Christopher Tate5d346052016-03-08 12:56:08 -0800441 // Soft override covers all non-"functional" constraints
442 static final int SOFT_OVERRIDE_CONSTRAINTS =
443 CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
444
Matthew Williams03a4da62014-09-10 17:32:18 -0700445 /**
446 * @return Whether the constraints set on this job are satisfied.
447 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800448 public boolean isConstraintsSatisfied() {
Christopher Tate5d346052016-03-08 12:56:08 -0800449 if (overrideState == OVERRIDE_FULL) {
450 // force override: the job is always runnable
451 return true;
452 }
453
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800454 final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
Christopher Tate5d346052016-03-08 12:56:08 -0800455
456 int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
457 if (overrideState == OVERRIDE_SOFT) {
458 // override: pretend all 'soft' requirements are satisfied
459 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
460 }
461
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800462 return (sat & req) == req;
Christopher Tate7060b042014-06-09 19:50:00 -0700463 }
464
465 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000466 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -0700467 }
468
469 @Override
470 public String toString() {
471 return String.valueOf(hashCode()).substring(0, 3) + ".."
Christopher Tate1b8b3aa2014-06-20 13:17:01 -0700472 + ":[" + job.getService()
473 + ",jId=" + job.getId()
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700474 + ",u" + getUserId()
475 + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
476 + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
Matthew Williamsd1c06752014-08-22 14:15:28 -0700477 + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800478 + ",I=" + job.isRequireDeviceIdle()
479 + ",U=" + (job.getTriggerContentUris() != null)
480 + ",F=" + numFailures + ",P=" + job.isPersisted()
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800481 + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700482 + ",DND=" + ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0)
Christopher Tate7060b042014-06-09 19:50:00 -0700483 + (isReady() ? "(READY)" : "")
484 + "]";
485 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700486
487 private String formatRunTime(long runtime, long defaultValue) {
488 if (runtime == defaultValue) {
489 return "none";
490 } else {
491 long elapsedNow = SystemClock.elapsedRealtime();
492 long nextRuntime = runtime - elapsedNow;
493 if (nextRuntime > 0) {
494 return DateUtils.formatElapsedTime(nextRuntime / 1000);
495 } else {
496 return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
497 }
498 }
499 }
500
501 /**
502 * Convenience function to identify a job uniquely without pulling all the data that
503 * {@link #toString()} returns.
504 */
505 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800506 StringBuilder sb = new StringBuilder();
507 sb.append(Integer.toHexString(System.identityHashCode(this)));
508 sb.append(" jId=");
509 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800510 sb.append(' ');
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000511 UserHandle.formatUid(sb, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800512 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -0800513 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800514 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700515 }
516
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800517 void dumpConstraints(PrintWriter pw, int constraints) {
518 if ((constraints&CONSTRAINT_CHARGING) != 0) {
519 pw.print(" CHARGING");
520 }
521 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
522 pw.print(" TIMING_DELAY");
523 }
524 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
525 pw.print(" DEADLINE");
526 }
527 if ((constraints&CONSTRAINT_IDLE) != 0) {
528 pw.print(" IDLE");
529 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600530 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
531 pw.print(" CONNECTIVITY");
532 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800533 if ((constraints&CONSTRAINT_UNMETERED) != 0) {
534 pw.print(" UNMETERED");
535 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600536 if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
537 pw.print(" NOT_ROAMING");
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800538 }
539 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
540 pw.print(" APP_NOT_IDLE");
541 }
542 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
543 pw.print(" CONTENT_TRIGGER");
544 }
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700545 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
546 pw.print(" DEVICE_NOT_DOZING");
547 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800548 }
549
Christopher Tate7060b042014-06-09 19:50:00 -0700550 // Dumpsys infrastructure
Dianne Hackborn970510b2016-02-24 16:56:42 -0800551 public void dump(PrintWriter pw, String prefix, boolean full) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000552 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800553 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -0700554 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000555 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
556 pw.print(" user="); pw.print(getSourceUserId());
557 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800558 if (full) {
559 pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix);
560 pw.print(" Service: "); pw.println(job.getService().flattenToShortString());
561 if (job.isPeriodic()) {
562 pw.print(prefix); pw.print(" PERIODIC: interval=");
563 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
564 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
565 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800566 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800567 if (job.isPersisted()) {
568 pw.print(prefix); pw.println(" PERSISTED");
569 }
570 if (job.getPriority() != 0) {
571 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
572 }
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600573 if (job.getFlags() != 0) {
574 pw.print(prefix); pw.print(" Flags: ");
575 pw.println(Integer.toHexString(job.getFlags()));
576 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800577 pw.print(prefix); pw.print(" Requires: charging=");
578 pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
579 pw.println(job.isRequireDeviceIdle());
580 if (job.getTriggerContentUris() != null) {
581 pw.print(prefix); pw.println(" Trigger content URIs:");
582 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
583 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
584 pw.print(prefix); pw.print(" ");
585 pw.print(Integer.toHexString(trig.getFlags()));
586 pw.print(' '); pw.println(trig.getUri());
587 }
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700588 if (job.getTriggerContentUpdateDelay() >= 0) {
589 pw.print(prefix); pw.print(" Trigger update delay: ");
590 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
591 pw.println();
592 }
593 if (job.getTriggerContentMaxDelay() >= 0) {
594 pw.print(prefix); pw.print(" Trigger max delay: ");
595 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
596 pw.println();
597 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800598 }
599 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
600 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
601 }
602 if (job.getMinLatencyMillis() != 0) {
603 pw.print(prefix); pw.print(" Minimum latency: ");
604 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
605 pw.println();
606 }
607 if (job.getMaxExecutionDelayMillis() != 0) {
608 pw.print(prefix); pw.print(" Max execution delay: ");
609 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
610 pw.println();
611 }
612 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
613 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800614 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -0800615 if (job.hasEarlyConstraint()) {
616 pw.print(prefix); pw.println(" Has early constraint");
617 }
618 if (job.hasLateConstraint()) {
619 pw.print(prefix); pw.println(" Has late constraint");
620 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800621 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800622 pw.print(prefix); pw.print("Required constraints:");
623 dumpConstraints(pw, requiredConstraints);
624 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -0800625 if (full) {
626 pw.print(prefix); pw.print("Satisfied constraints:");
627 dumpConstraints(pw, satisfiedConstraints);
628 pw.println();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600629 pw.print(prefix); pw.print("Unsatisfied constraints:");
630 dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
631 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -0800632 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800633 if (changedAuthorities != null) {
634 pw.print(prefix); pw.println("Changed authorities:");
635 for (int i=0; i<changedAuthorities.size(); i++) {
636 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
637 }
638 if (changedUris != null) {
639 pw.print(prefix); pw.println("Changed URIs:");
640 for (int i=0; i<changedUris.size(); i++) {
641 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i));
642 }
643 }
644 }
645 pw.print(prefix); pw.print("Earliest run time: ");
646 pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
647 pw.print(prefix); pw.print("Latest run time: ");
648 pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
649 if (numFailures != 0) {
650 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
651 }
Christopher Tate7060b042014-06-09 19:50:00 -0700652 }
653}