blob: 4a2c88c2f733e93bd003849e1908d9ebc708d09d [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;
32import java.util.concurrent.atomic.AtomicBoolean;
33
34/**
35 * Uniquely identifies a job internally.
36 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
37 * Contains current state of the requirements of the job, as well as a function to evaluate
38 * whether it's ready to run.
39 * This object is shared among the various controllers - hence why the different fields are atomic.
40 * This isn't strictly necessary because each controller is only interested in a specific field,
41 * and the receivers that are listening for global state change will all run on the main looper,
42 * but we don't enforce that so this is safer.
43 * @hide
44 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -080045public final class JobStatus {
Christopher Tate7060b042014-06-09 19:50:00 -070046 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
47 public static final long NO_EARLIEST_RUNTIME = 0L;
48
Dianne Hackbornb0001f62016-02-16 10:30:33 -080049 static final int CONSTRAINT_CHARGING = 1<<0;
50 static final int CONSTRAINT_TIMING_DELAY = 1<<1;
51 static final int CONSTRAINT_DEADLINE = 1<<2;
52 static final int CONSTRAINT_IDLE = 1<<3;
53 static final int CONSTRAINT_UNMETERED = 1<<4;
54 static final int CONSTRAINT_CONNECTIVITY = 1<<5;
55 static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
56 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
57
Christopher Tate5d346052016-03-08 12:56:08 -080058 // Soft override: ignore constraints like time that don't affect API availability
59 public static final int OVERRIDE_SOFT = 1;
60 // Full override: ignore all constraints including API-affecting like connectivity
61 public static final int OVERRIDE_FULL = 2;
62
Christopher Tate7060b042014-06-09 19:50:00 -070063 final JobInfo job;
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070064 /** Uid of the package requesting this job. */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000065 final int callingUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080066 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -070067
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000068 final String sourcePackageName;
69 final int sourceUserId;
70 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080071 final String sourceTag;
72
73 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +000074
Dianne Hackbornb0001f62016-02-16 10:30:33 -080075 /**
76 * Earliest point in the future at which this job will be eligible to run. A value of 0
77 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
78 */
79 private final long earliestRunTimeElapsedMillis;
80 /**
81 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
82 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
83 */
84 private final long latestRunTimeElapsedMillis;
85
86 /** How many times this job has failed, used to compute back-off. */
87 private final int numFailures;
88
Christopher Tate7060b042014-06-09 19:50:00 -070089 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -080090 final int requiredConstraints;
91 int satisfiedConstraints = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080092
93 // These are filled in by controllers when preparing for execution.
94 public ArraySet<Uri> changedUris;
95 public ArraySet<String> changedAuthorities;
96
Dianne Hackborn1085ff62016-02-23 17:04:58 -080097 public int lastEvaluatedPriority;
98
Christopher Tate5d346052016-03-08 12:56:08 -080099 // Used by shell commands
100 public int overrideState = 0;
101
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800102 /**
103 * For use only by ContentObserverController: state it is maintaining about content URIs
104 * being observed.
105 */
106 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -0700107
Christopher Tate7060b042014-06-09 19:50:00 -0700108 /** Provide a handle to the service that this job will be run on. */
109 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000110 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700111 }
112
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800113 private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800114 int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800115 long latestRunTimeElapsedMillis) {
Christopher Tate7060b042014-06-09 19:50:00 -0700116 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000117 this.callingUid = callingUid;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000118
119 int tempSourceUid = -1;
120 if (sourceUserId != -1 && sourcePackageName != null) {
121 try {
122 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
123 sourceUserId);
124 } catch (RemoteException ex) {
125 // Can't happen, PackageManager runs in the same process.
126 }
127 }
128 if (tempSourceUid == -1) {
129 this.sourceUid = callingUid;
130 this.sourceUserId = UserHandle.getUserId(callingUid);
131 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800132 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000133 } else {
134 this.sourceUid = tempSourceUid;
135 this.sourceUserId = sourceUserId;
136 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800137 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000138 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800139
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800140 if (this.sourceTag != null) {
141 StringBuilder sb = new StringBuilder();
142 sb.append(job.getService().getPackageName());
143 sb.append('/');
144 sb.append(this.sourceTag);
Dianne Hackborn970510b2016-02-24 16:56:42 -0800145 if (sourcePackageName != null) {
146 sb.append('/');
147 sb.append(this.sourcePackageName);
148 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800149 this.batteryName = sb.toString();
150 } else {
151 this.batteryName = job.getService().flattenToShortString();
152 }
153 this.tag = "*job*/" + this.batteryName;
154
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800155 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
156 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
157 this.numFailures = numFailures;
158
159 int requiredConstraints = 0;
160 if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
161 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
162 }
163 if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
164 requiredConstraints |= CONSTRAINT_UNMETERED;
165 }
166 if (job.isRequireCharging()) {
167 requiredConstraints |= CONSTRAINT_CHARGING;
168 }
169 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
170 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
171 }
172 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
173 requiredConstraints |= CONSTRAINT_DEADLINE;
174 }
175 if (job.isRequireDeviceIdle()) {
176 requiredConstraints |= CONSTRAINT_IDLE;
177 }
178 if (job.getTriggerContentUris() != null) {
179 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
180 }
181 this.requiredConstraints = requiredConstraints;
Christopher Tate7060b042014-06-09 19:50:00 -0700182 }
183
Matthew Williams0cc76542015-10-16 21:04:51 -0700184 /** Copy constructor. */
185 public JobStatus(JobStatus jobStatus) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800186 this(jobStatus.getJob(), jobStatus.getUid(),
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800187 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800188 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
189 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
Christopher Tate7060b042014-06-09 19:50:00 -0700190 }
191
192 /**
193 * Create a new JobStatus that was loaded from disk. We ignore the provided
194 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
195 * from the {@link com.android.server.job.JobStore} and still want to respect its
196 * wallclock runtime rather than resetting it on every boot.
197 * We consider a freshly loaded job to no longer be in back-off.
198 */
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800199 public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
200 String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
201 this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
202 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700203 }
204
205 /** Create a new job to be rescheduled with the provided parameters. */
206 public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
207 long newLatestRuntimeElapsedMillis, int backoffAttempt) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800208 this(rescheduling.job, rescheduling.getUid(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800209 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
210 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800211 newLatestRuntimeElapsedMillis);
212 }
Christopher Tate7060b042014-06-09 19:50:00 -0700213
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800214 /**
215 * Create a newly scheduled job.
216 * @param callingUid Uid of the package that scheduled this job.
217 * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
218 * the calling package is the source.
219 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
220 */
221 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800222 int sourceUserId, String tag) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800223 final long elapsedNow = SystemClock.elapsedRealtime();
224 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
225 if (job.isPeriodic()) {
226 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
227 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
228 } else {
229 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
230 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
231 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
232 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
233 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800234 return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800235 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700236 }
237
238 public JobInfo getJob() {
239 return job;
240 }
241
242 public int getJobId() {
243 return job.getId();
244 }
245
246 public int getNumFailures() {
247 return numFailures;
248 }
249
250 public ComponentName getServiceComponent() {
251 return job.getService();
252 }
253
Shreyas Basarge968ac752016-01-11 23:09:26 +0000254 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000255 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000256 }
257
258 public int getSourceUid() {
259 return sourceUid;
260 }
261
262 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000263 return sourceUserId;
264 }
265
Christopher Tate7060b042014-06-09 19:50:00 -0700266 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000267 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700268 }
269
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800270 public String getSourceTag() {
271 return sourceTag;
272 }
273
Christopher Tate7060b042014-06-09 19:50:00 -0700274 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000275 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700276 }
277
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800278 public String getBatteryName() {
279 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700280 }
281
282 public String getTag() {
283 return tag;
284 }
285
Christopher Tate7060b042014-06-09 19:50:00 -0700286 public PersistableBundle getExtras() {
287 return job.getExtras();
288 }
Shreyas Basarge968ac752016-01-11 23:09:26 +0000289
Shreyas Basarge5db09082016-01-07 13:38:29 +0000290 public int getPriority() {
291 return job.getPriority();
292 }
Christopher Tate7060b042014-06-09 19:50:00 -0700293
294 public boolean hasConnectivityConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800295 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700296 }
297
298 public boolean hasUnmeteredConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800299 return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700300 }
301
302 public boolean hasChargingConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800303 return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700304 }
305
306 public boolean hasTimingDelayConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800307 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700308 }
309
310 public boolean hasDeadlineConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800311 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700312 }
313
314 public boolean hasIdleConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800315 return (requiredConstraints&CONSTRAINT_IDLE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700316 }
317
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800318 public boolean hasContentTriggerConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800319 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800320 }
321
Matthew Williams900c67f2014-07-09 12:46:53 -0700322 public boolean isPersisted() {
323 return job.isPersisted();
324 }
325
Christopher Tate7060b042014-06-09 19:50:00 -0700326 public long getEarliestRunTime() {
327 return earliestRunTimeElapsedMillis;
328 }
329
330 public long getLatestRunTimeElapsed() {
331 return latestRunTimeElapsedMillis;
332 }
333
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800334 boolean setChargingConstraintSatisfied(boolean state) {
335 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
336 }
337
338 boolean setTimingDelayConstraintSatisfied(boolean state) {
339 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
340 }
341
342 boolean setDeadlineConstraintSatisfied(boolean state) {
343 return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
344 }
345
346 boolean setIdleConstraintSatisfied(boolean state) {
347 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
348 }
349
350 boolean setUnmeteredConstraintSatisfied(boolean state) {
351 return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
352 }
353
354 boolean setConnectivityConstraintSatisfied(boolean state) {
355 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
356 }
357
358 boolean setAppNotIdleConstraintSatisfied(boolean state) {
359 return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
360 }
361
362 boolean setContentTriggerConstraintSatisfied(boolean state) {
363 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
364 }
365
366 boolean setConstraintSatisfied(int constraint, boolean state) {
367 boolean old = (satisfiedConstraints&constraint) != 0;
368 if (old == state) {
369 return false;
370 }
371 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
372 return true;
373 }
374
Christopher Tate7060b042014-06-09 19:50:00 -0700375 /**
Matthew Williams03a4da62014-09-10 17:32:18 -0700376 * @return Whether or not this job is ready to run, based on its requirements. This is true if
377 * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
Christopher Tate7060b042014-06-09 19:50:00 -0700378 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800379 public boolean isReady() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800380 // Deadline constraint trumps other constraints (except for periodic jobs where deadline
Christopher Tate5d346052016-03-08 12:56:08 -0800381 // is an implementation detail. A periodic job should only run if its constraints are
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800382 // satisfied).
383 // AppNotIdle implicit constraint trumps all!
384 return (isConstraintsSatisfied()
385 || (!job.isPeriodic()
386 && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0))
387 && (satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0;
Matthew Williams03a4da62014-09-10 17:32:18 -0700388 }
389
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800390 static final int CONSTRAINTS_OF_INTEREST =
391 CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
392 CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
393 CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
394
Christopher Tate5d346052016-03-08 12:56:08 -0800395 // Soft override covers all non-"functional" constraints
396 static final int SOFT_OVERRIDE_CONSTRAINTS =
397 CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
398
Matthew Williams03a4da62014-09-10 17:32:18 -0700399 /**
400 * @return Whether the constraints set on this job are satisfied.
401 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800402 public boolean isConstraintsSatisfied() {
Christopher Tate5d346052016-03-08 12:56:08 -0800403 if (overrideState == OVERRIDE_FULL) {
404 // force override: the job is always runnable
405 return true;
406 }
407
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800408 final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
Christopher Tate5d346052016-03-08 12:56:08 -0800409
410 int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
411 if (overrideState == OVERRIDE_SOFT) {
412 // override: pretend all 'soft' requirements are satisfied
413 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
414 }
415
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800416 return (sat & req) == req;
Christopher Tate7060b042014-06-09 19:50:00 -0700417 }
418
419 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000420 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -0700421 }
422
423 @Override
424 public String toString() {
425 return String.valueOf(hashCode()).substring(0, 3) + ".."
Christopher Tate1b8b3aa2014-06-20 13:17:01 -0700426 + ":[" + job.getService()
427 + ",jId=" + job.getId()
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700428 + ",u" + getUserId()
429 + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
430 + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
Matthew Williamsd1c06752014-08-22 14:15:28 -0700431 + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800432 + ",I=" + job.isRequireDeviceIdle()
433 + ",U=" + (job.getTriggerContentUris() != null)
434 + ",F=" + numFailures + ",P=" + job.isPersisted()
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800435 + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
Christopher Tate7060b042014-06-09 19:50:00 -0700436 + (isReady() ? "(READY)" : "")
437 + "]";
438 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700439
440 private String formatRunTime(long runtime, long defaultValue) {
441 if (runtime == defaultValue) {
442 return "none";
443 } else {
444 long elapsedNow = SystemClock.elapsedRealtime();
445 long nextRuntime = runtime - elapsedNow;
446 if (nextRuntime > 0) {
447 return DateUtils.formatElapsedTime(nextRuntime / 1000);
448 } else {
449 return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
450 }
451 }
452 }
453
454 /**
455 * Convenience function to identify a job uniquely without pulling all the data that
456 * {@link #toString()} returns.
457 */
458 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800459 StringBuilder sb = new StringBuilder();
460 sb.append(Integer.toHexString(System.identityHashCode(this)));
461 sb.append(" jId=");
462 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800463 sb.append(' ');
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000464 UserHandle.formatUid(sb, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800465 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -0800466 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800467 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700468 }
469
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800470 void dumpConstraints(PrintWriter pw, int constraints) {
471 if ((constraints&CONSTRAINT_CHARGING) != 0) {
472 pw.print(" CHARGING");
473 }
474 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
475 pw.print(" TIMING_DELAY");
476 }
477 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
478 pw.print(" DEADLINE");
479 }
480 if ((constraints&CONSTRAINT_IDLE) != 0) {
481 pw.print(" IDLE");
482 }
483 if ((constraints&CONSTRAINT_UNMETERED) != 0) {
484 pw.print(" UNMETERED");
485 }
486 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
487 pw.print(" CONNECTIVITY");
488 }
489 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
490 pw.print(" APP_NOT_IDLE");
491 }
492 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
493 pw.print(" CONTENT_TRIGGER");
494 }
495 }
496
Christopher Tate7060b042014-06-09 19:50:00 -0700497 // Dumpsys infrastructure
Dianne Hackborn970510b2016-02-24 16:56:42 -0800498 public void dump(PrintWriter pw, String prefix, boolean full) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000499 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800500 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -0700501 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000502 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
503 pw.print(" user="); pw.print(getSourceUserId());
504 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800505 if (full) {
506 pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix);
507 pw.print(" Service: "); pw.println(job.getService().flattenToShortString());
508 if (job.isPeriodic()) {
509 pw.print(prefix); pw.print(" PERIODIC: interval=");
510 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
511 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
512 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800513 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800514 if (job.isPersisted()) {
515 pw.print(prefix); pw.println(" PERSISTED");
516 }
517 if (job.getPriority() != 0) {
518 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
519 }
520 pw.print(prefix); pw.print(" Requires: charging=");
521 pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
522 pw.println(job.isRequireDeviceIdle());
523 if (job.getTriggerContentUris() != null) {
524 pw.print(prefix); pw.println(" Trigger content URIs:");
525 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
526 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
527 pw.print(prefix); pw.print(" ");
528 pw.print(Integer.toHexString(trig.getFlags()));
529 pw.print(' '); pw.println(trig.getUri());
530 }
531 }
532 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
533 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
534 }
535 if (job.getMinLatencyMillis() != 0) {
536 pw.print(prefix); pw.print(" Minimum latency: ");
537 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
538 pw.println();
539 }
540 if (job.getMaxExecutionDelayMillis() != 0) {
541 pw.print(prefix); pw.print(" Max execution delay: ");
542 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
543 pw.println();
544 }
545 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
546 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800547 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -0800548 if (job.hasEarlyConstraint()) {
549 pw.print(prefix); pw.println(" Has early constraint");
550 }
551 if (job.hasLateConstraint()) {
552 pw.print(prefix); pw.println(" Has late constraint");
553 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800554 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800555 pw.print(prefix); pw.print("Required constraints:");
556 dumpConstraints(pw, requiredConstraints);
557 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -0800558 if (full) {
559 pw.print(prefix); pw.print("Satisfied constraints:");
560 dumpConstraints(pw, satisfiedConstraints);
561 pw.println();
562 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800563 if (changedAuthorities != null) {
564 pw.print(prefix); pw.println("Changed authorities:");
565 for (int i=0; i<changedAuthorities.size(); i++) {
566 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
567 }
568 if (changedUris != null) {
569 pw.print(prefix); pw.println("Changed URIs:");
570 for (int i=0; i<changedUris.size(); i++) {
571 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i));
572 }
573 }
574 }
575 pw.print(prefix); pw.print("Earliest run time: ");
576 pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
577 pw.print(prefix); pw.print("Latest run time: ");
578 pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
579 if (numFailures != 0) {
580 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
581 }
Christopher Tate7060b042014-06-09 19:50:00 -0700582 }
583}