blob: 98bf8a9a8d08d72bf89910fd2f5c90e529cb4065 [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 Tate7060b042014-06-09 19:50:00 -070058 final JobInfo job;
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070059 /** Uid of the package requesting this job. */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000060 final int callingUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080061 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -070062
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000063 final String sourcePackageName;
64 final int sourceUserId;
65 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080066 final String sourceTag;
67
68 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +000069
Dianne Hackbornb0001f62016-02-16 10:30:33 -080070 /**
71 * Earliest point in the future at which this job will be eligible to run. A value of 0
72 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
73 */
74 private final long earliestRunTimeElapsedMillis;
75 /**
76 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
77 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
78 */
79 private final long latestRunTimeElapsedMillis;
80
81 /** How many times this job has failed, used to compute back-off. */
82 private final int numFailures;
83
Christopher Tate7060b042014-06-09 19:50:00 -070084 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -080085 final int requiredConstraints;
86 int satisfiedConstraints = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080087
88 // These are filled in by controllers when preparing for execution.
89 public ArraySet<Uri> changedUris;
90 public ArraySet<String> changedAuthorities;
91
Dianne Hackborn1085ff62016-02-23 17:04:58 -080092 public int lastEvaluatedPriority;
93
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080094 /**
95 * For use only by ContentObserverController: state it is maintaining about content URIs
96 * being observed.
97 */
98 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -070099
Christopher Tate7060b042014-06-09 19:50:00 -0700100 /** Provide a handle to the service that this job will be run on. */
101 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000102 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700103 }
104
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800105 private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800106 int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800107 long latestRunTimeElapsedMillis) {
Christopher Tate7060b042014-06-09 19:50:00 -0700108 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000109 this.callingUid = callingUid;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000110
111 int tempSourceUid = -1;
112 if (sourceUserId != -1 && sourcePackageName != null) {
113 try {
114 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
115 sourceUserId);
116 } catch (RemoteException ex) {
117 // Can't happen, PackageManager runs in the same process.
118 }
119 }
120 if (tempSourceUid == -1) {
121 this.sourceUid = callingUid;
122 this.sourceUserId = UserHandle.getUserId(callingUid);
123 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800124 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000125 } else {
126 this.sourceUid = tempSourceUid;
127 this.sourceUserId = sourceUserId;
128 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800129 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000130 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800131
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800132 if (this.sourceTag != null) {
133 StringBuilder sb = new StringBuilder();
134 sb.append(job.getService().getPackageName());
135 sb.append('/');
136 sb.append(this.sourceTag);
Dianne Hackborn970510b2016-02-24 16:56:42 -0800137 if (sourcePackageName != null) {
138 sb.append('/');
139 sb.append(this.sourcePackageName);
140 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800141 this.batteryName = sb.toString();
142 } else {
143 this.batteryName = job.getService().flattenToShortString();
144 }
145 this.tag = "*job*/" + this.batteryName;
146
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800147 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
148 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
149 this.numFailures = numFailures;
150
151 int requiredConstraints = 0;
152 if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
153 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
154 }
155 if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
156 requiredConstraints |= CONSTRAINT_UNMETERED;
157 }
158 if (job.isRequireCharging()) {
159 requiredConstraints |= CONSTRAINT_CHARGING;
160 }
161 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
162 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
163 }
164 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
165 requiredConstraints |= CONSTRAINT_DEADLINE;
166 }
167 if (job.isRequireDeviceIdle()) {
168 requiredConstraints |= CONSTRAINT_IDLE;
169 }
170 if (job.getTriggerContentUris() != null) {
171 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
172 }
173 this.requiredConstraints = requiredConstraints;
Christopher Tate7060b042014-06-09 19:50:00 -0700174 }
175
Matthew Williams0cc76542015-10-16 21:04:51 -0700176 /** Copy constructor. */
177 public JobStatus(JobStatus jobStatus) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800178 this(jobStatus.getJob(), jobStatus.getUid(),
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800179 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800180 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
181 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
Christopher Tate7060b042014-06-09 19:50:00 -0700182 }
183
184 /**
185 * Create a new JobStatus that was loaded from disk. We ignore the provided
186 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
187 * from the {@link com.android.server.job.JobStore} and still want to respect its
188 * wallclock runtime rather than resetting it on every boot.
189 * We consider a freshly loaded job to no longer be in back-off.
190 */
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800191 public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
192 String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
193 this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
194 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700195 }
196
197 /** Create a new job to be rescheduled with the provided parameters. */
198 public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
199 long newLatestRuntimeElapsedMillis, int backoffAttempt) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800200 this(rescheduling.job, rescheduling.getUid(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800201 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
202 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800203 newLatestRuntimeElapsedMillis);
204 }
Christopher Tate7060b042014-06-09 19:50:00 -0700205
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800206 /**
207 * Create a newly scheduled job.
208 * @param callingUid Uid of the package that scheduled this job.
209 * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
210 * the calling package is the source.
211 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
212 */
213 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800214 int sourceUserId, String tag) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800215 final long elapsedNow = SystemClock.elapsedRealtime();
216 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
217 if (job.isPeriodic()) {
218 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
219 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
220 } else {
221 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
222 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
223 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
224 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
225 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800226 return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800227 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700228 }
229
230 public JobInfo getJob() {
231 return job;
232 }
233
234 public int getJobId() {
235 return job.getId();
236 }
237
238 public int getNumFailures() {
239 return numFailures;
240 }
241
242 public ComponentName getServiceComponent() {
243 return job.getService();
244 }
245
Shreyas Basarge968ac752016-01-11 23:09:26 +0000246 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000247 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000248 }
249
250 public int getSourceUid() {
251 return sourceUid;
252 }
253
254 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000255 return sourceUserId;
256 }
257
Christopher Tate7060b042014-06-09 19:50:00 -0700258 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000259 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700260 }
261
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800262 public String getSourceTag() {
263 return sourceTag;
264 }
265
Christopher Tate7060b042014-06-09 19:50:00 -0700266 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000267 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700268 }
269
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800270 public String getBatteryName() {
271 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700272 }
273
274 public String getTag() {
275 return tag;
276 }
277
Christopher Tate7060b042014-06-09 19:50:00 -0700278 public PersistableBundle getExtras() {
279 return job.getExtras();
280 }
Shreyas Basarge968ac752016-01-11 23:09:26 +0000281
Shreyas Basarge5db09082016-01-07 13:38:29 +0000282 public int getPriority() {
283 return job.getPriority();
284 }
Christopher Tate7060b042014-06-09 19:50:00 -0700285
286 public boolean hasConnectivityConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800287 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700288 }
289
290 public boolean hasUnmeteredConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800291 return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700292 }
293
294 public boolean hasChargingConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800295 return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700296 }
297
298 public boolean hasTimingDelayConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800299 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700300 }
301
302 public boolean hasDeadlineConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800303 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700304 }
305
306 public boolean hasIdleConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800307 return (requiredConstraints&CONSTRAINT_IDLE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700308 }
309
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800310 public boolean hasContentTriggerConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800311 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800312 }
313
Matthew Williams900c67f2014-07-09 12:46:53 -0700314 public boolean isPersisted() {
315 return job.isPersisted();
316 }
317
Christopher Tate7060b042014-06-09 19:50:00 -0700318 public long getEarliestRunTime() {
319 return earliestRunTimeElapsedMillis;
320 }
321
322 public long getLatestRunTimeElapsed() {
323 return latestRunTimeElapsedMillis;
324 }
325
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800326 boolean setChargingConstraintSatisfied(boolean state) {
327 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
328 }
329
330 boolean setTimingDelayConstraintSatisfied(boolean state) {
331 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
332 }
333
334 boolean setDeadlineConstraintSatisfied(boolean state) {
335 return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
336 }
337
338 boolean setIdleConstraintSatisfied(boolean state) {
339 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
340 }
341
342 boolean setUnmeteredConstraintSatisfied(boolean state) {
343 return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
344 }
345
346 boolean setConnectivityConstraintSatisfied(boolean state) {
347 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
348 }
349
350 boolean setAppNotIdleConstraintSatisfied(boolean state) {
351 return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
352 }
353
354 boolean setContentTriggerConstraintSatisfied(boolean state) {
355 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
356 }
357
358 boolean setConstraintSatisfied(int constraint, boolean state) {
359 boolean old = (satisfiedConstraints&constraint) != 0;
360 if (old == state) {
361 return false;
362 }
363 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
364 return true;
365 }
366
Christopher Tate7060b042014-06-09 19:50:00 -0700367 /**
Matthew Williams03a4da62014-09-10 17:32:18 -0700368 * @return Whether or not this job is ready to run, based on its requirements. This is true if
369 * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
Christopher Tate7060b042014-06-09 19:50:00 -0700370 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800371 public boolean isReady() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800372 // Deadline constraint trumps other constraints (except for periodic jobs where deadline
373 // (is an implementation detail. A periodic job should only run if it's constraints are
374 // satisfied).
375 // AppNotIdle implicit constraint trumps all!
376 return (isConstraintsSatisfied()
377 || (!job.isPeriodic()
378 && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0))
379 && (satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0;
Matthew Williams03a4da62014-09-10 17:32:18 -0700380 }
381
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800382 static final int CONSTRAINTS_OF_INTEREST =
383 CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
384 CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
385 CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
386
Matthew Williams03a4da62014-09-10 17:32:18 -0700387 /**
388 * @return Whether the constraints set on this job are satisfied.
389 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800390 public boolean isConstraintsSatisfied() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800391 final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
392 final int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
393 return (sat & req) == req;
Christopher Tate7060b042014-06-09 19:50:00 -0700394 }
395
396 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000397 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -0700398 }
399
400 @Override
401 public String toString() {
402 return String.valueOf(hashCode()).substring(0, 3) + ".."
Christopher Tate1b8b3aa2014-06-20 13:17:01 -0700403 + ":[" + job.getService()
404 + ",jId=" + job.getId()
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700405 + ",u" + getUserId()
406 + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
407 + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
Matthew Williamsd1c06752014-08-22 14:15:28 -0700408 + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800409 + ",I=" + job.isRequireDeviceIdle()
410 + ",U=" + (job.getTriggerContentUris() != null)
411 + ",F=" + numFailures + ",P=" + job.isPersisted()
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800412 + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
Christopher Tate7060b042014-06-09 19:50:00 -0700413 + (isReady() ? "(READY)" : "")
414 + "]";
415 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700416
417 private String formatRunTime(long runtime, long defaultValue) {
418 if (runtime == defaultValue) {
419 return "none";
420 } else {
421 long elapsedNow = SystemClock.elapsedRealtime();
422 long nextRuntime = runtime - elapsedNow;
423 if (nextRuntime > 0) {
424 return DateUtils.formatElapsedTime(nextRuntime / 1000);
425 } else {
426 return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
427 }
428 }
429 }
430
431 /**
432 * Convenience function to identify a job uniquely without pulling all the data that
433 * {@link #toString()} returns.
434 */
435 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800436 StringBuilder sb = new StringBuilder();
437 sb.append(Integer.toHexString(System.identityHashCode(this)));
438 sb.append(" jId=");
439 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800440 sb.append(' ');
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000441 UserHandle.formatUid(sb, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800442 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -0800443 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800444 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700445 }
446
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800447 void dumpConstraints(PrintWriter pw, int constraints) {
448 if ((constraints&CONSTRAINT_CHARGING) != 0) {
449 pw.print(" CHARGING");
450 }
451 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
452 pw.print(" TIMING_DELAY");
453 }
454 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
455 pw.print(" DEADLINE");
456 }
457 if ((constraints&CONSTRAINT_IDLE) != 0) {
458 pw.print(" IDLE");
459 }
460 if ((constraints&CONSTRAINT_UNMETERED) != 0) {
461 pw.print(" UNMETERED");
462 }
463 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
464 pw.print(" CONNECTIVITY");
465 }
466 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
467 pw.print(" APP_NOT_IDLE");
468 }
469 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
470 pw.print(" CONTENT_TRIGGER");
471 }
472 }
473
Christopher Tate7060b042014-06-09 19:50:00 -0700474 // Dumpsys infrastructure
Dianne Hackborn970510b2016-02-24 16:56:42 -0800475 public void dump(PrintWriter pw, String prefix, boolean full) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000476 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800477 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -0700478 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000479 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
480 pw.print(" user="); pw.print(getSourceUserId());
481 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800482 if (full) {
483 pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix);
484 pw.print(" Service: "); pw.println(job.getService().flattenToShortString());
485 if (job.isPeriodic()) {
486 pw.print(prefix); pw.print(" PERIODIC: interval=");
487 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
488 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
489 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800490 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800491 if (job.isPersisted()) {
492 pw.print(prefix); pw.println(" PERSISTED");
493 }
494 if (job.getPriority() != 0) {
495 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
496 }
497 pw.print(prefix); pw.print(" Requires: charging=");
498 pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
499 pw.println(job.isRequireDeviceIdle());
500 if (job.getTriggerContentUris() != null) {
501 pw.print(prefix); pw.println(" Trigger content URIs:");
502 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
503 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
504 pw.print(prefix); pw.print(" ");
505 pw.print(Integer.toHexString(trig.getFlags()));
506 pw.print(' '); pw.println(trig.getUri());
507 }
508 }
509 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
510 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
511 }
512 if (job.getMinLatencyMillis() != 0) {
513 pw.print(prefix); pw.print(" Minimum latency: ");
514 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
515 pw.println();
516 }
517 if (job.getMaxExecutionDelayMillis() != 0) {
518 pw.print(prefix); pw.print(" Max execution delay: ");
519 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
520 pw.println();
521 }
522 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
523 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800524 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -0800525 if (job.hasEarlyConstraint()) {
526 pw.print(prefix); pw.println(" Has early constraint");
527 }
528 if (job.hasLateConstraint()) {
529 pw.print(prefix); pw.println(" Has late constraint");
530 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800531 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800532 pw.print(prefix); pw.print("Required constraints:");
533 dumpConstraints(pw, requiredConstraints);
534 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -0800535 if (full) {
536 pw.print(prefix); pw.print("Satisfied constraints:");
537 dumpConstraints(pw, satisfiedConstraints);
538 pw.println();
539 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800540 if (changedAuthorities != null) {
541 pw.print(prefix); pw.println("Changed authorities:");
542 for (int i=0; i<changedAuthorities.size(); i++) {
543 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
544 }
545 if (changedUris != null) {
546 pw.print(prefix); pw.println("Changed URIs:");
547 for (int i=0; i<changedUris.size(); i++) {
548 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i));
549 }
550 }
551 }
552 pw.print(prefix); pw.print("Earliest run time: ");
553 pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
554 pw.print(prefix); pw.print("Latest run time: ");
555 pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
556 if (numFailures != 0) {
557 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
558 }
Christopher Tate7060b042014-06-09 19:50:00 -0700559 }
560}