1 /*
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 
17 package com.android.server.job.controllers;
18 
19 import android.app.AppGlobals;
20 import android.app.job.JobInfo;
21 import android.content.ComponentName;
22 import android.net.Uri;
23 import android.os.PersistableBundle;
24 import android.os.RemoteException;
25 import android.os.SystemClock;
26 import android.os.UserHandle;
27 import android.text.format.DateUtils;
28 import android.util.ArraySet;
29 import android.util.TimeUtils;
30 
31 import java.io.PrintWriter;
32 
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  */
44 public final class JobStatus {
45     public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
46     public static final long NO_EARLIEST_RUNTIME = 0L;
47 
48     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;
56     static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<8;
57     static final int CONSTRAINT_NOT_ROAMING = 1<<9;
58 
59     // 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 
64     /** 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 
76     final JobInfo job;
77     /** Uid of the package requesting this job. */
78     final int callingUid;
79     final String batteryName;
80 
81     final String sourcePackageName;
82     final int sourceUserId;
83     final int sourceUid;
84     final String sourceTag;
85 
86     final String tag;
87 
88     /**
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 
102     // Constraints.
103     final int requiredConstraints;
104     int satisfiedConstraints = 0;
105 
106     // Set to true if doze constraint was satisfied due to app being whitelisted.
107     public boolean dozeWhitelisted;
108 
109     // These are filled in by controllers when preparing for execution.
110     public ArraySet<Uri> changedUris;
111     public ArraySet<String> changedAuthorities;
112 
113     public int lastEvaluatedPriority;
114 
115     // Used by shell commands
116     public int overrideState = 0;
117 
118     /**
119      * For use only by ContentObserverController: state it is maintaining about content URIs
120      * being observed.
121      */
122     ContentObserverController.JobInstance contentObserverJobInstance;
123 
124     /** Provide a handle to the service that this job will be run on. */
getServiceToken()125     public int getServiceToken() {
126         return callingUid;
127     }
128 
JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis)129     private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
130             int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
131             long latestRunTimeElapsedMillis) {
132         this.job = job;
133         this.callingUid = callingUid;
134 
135         int tempSourceUid = -1;
136         if (sourceUserId != -1 && sourcePackageName != null) {
137             try {
138                 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
139                         sourceUserId);
140             } catch (RemoteException ex) {
141                 // Can't happen, PackageManager runs in the same process.
142             }
143         }
144         if (tempSourceUid == -1) {
145             this.sourceUid = callingUid;
146             this.sourceUserId = UserHandle.getUserId(callingUid);
147             this.sourcePackageName = job.getService().getPackageName();
148             this.sourceTag = null;
149         } else {
150             this.sourceUid = tempSourceUid;
151             this.sourceUserId = sourceUserId;
152             this.sourcePackageName = sourcePackageName;
153             this.sourceTag = tag;
154         }
155 
156         this.batteryName = this.sourceTag != null
157                 ? this.sourceTag + ":" + job.getService().getPackageName()
158                 : job.getService().flattenToShortString();
159         this.tag = "*job*/" + this.batteryName;
160 
161         this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
162         this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
163         this.numFailures = numFailures;
164 
165         int requiredConstraints = 0;
166         if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
167             requiredConstraints |= CONSTRAINT_CONNECTIVITY;
168         }
169         if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
170             requiredConstraints |= CONSTRAINT_UNMETERED;
171         }
172         if (job.getNetworkType() == JobInfo.NETWORK_TYPE_NOT_ROAMING) {
173             requiredConstraints |= CONSTRAINT_NOT_ROAMING;
174         }
175         if (job.isRequireCharging()) {
176             requiredConstraints |= CONSTRAINT_CHARGING;
177         }
178         if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
179             requiredConstraints |= CONSTRAINT_TIMING_DELAY;
180         }
181         if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
182             requiredConstraints |= CONSTRAINT_DEADLINE;
183         }
184         if (job.isRequireDeviceIdle()) {
185             requiredConstraints |= CONSTRAINT_IDLE;
186         }
187         if (job.getTriggerContentUris() != null) {
188             requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
189         }
190         this.requiredConstraints = requiredConstraints;
191     }
192 
193     /** Copy constructor. */
JobStatus(JobStatus jobStatus)194     public JobStatus(JobStatus jobStatus) {
195         this(jobStatus.getJob(), jobStatus.getUid(),
196                 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
197                 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
198                 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
199     }
200 
201     /**
202      * Create a new JobStatus that was loaded from disk. We ignore the provided
203      * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
204      * from the {@link com.android.server.job.JobStore} and still want to respect its
205      * wallclock runtime rather than resetting it on every boot.
206      * We consider a freshly loaded job to no longer be in back-off.
207      */
JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis)208     public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
209             String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
210         this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
211                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
212     }
213 
214     /** Create a new job to be rescheduled with the provided parameters. */
JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, long newLatestRuntimeElapsedMillis, int backoffAttempt)215     public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
216                       long newLatestRuntimeElapsedMillis, int backoffAttempt) {
217         this(rescheduling.job, rescheduling.getUid(),
218                 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
219                 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
220                 newLatestRuntimeElapsedMillis);
221     }
222 
223     /**
224      * Create a newly scheduled job.
225      * @param callingUid Uid of the package that scheduled this job.
226      * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
227      *                          the calling package is the source.
228      * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
229      */
createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, String tag)230     public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
231             int sourceUserId, String tag) {
232         final long elapsedNow = SystemClock.elapsedRealtime();
233         final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
234         if (job.isPeriodic()) {
235             latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
236             earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
237         } else {
238             earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
239                     elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
240             latestRunTimeElapsedMillis = job.hasLateConstraint() ?
241                     elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
242         }
243         return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
244                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
245     }
246 
getJob()247     public JobInfo getJob() {
248         return job;
249     }
250 
getJobId()251     public int getJobId() {
252         return job.getId();
253     }
254 
printUniqueId(PrintWriter pw)255     public void printUniqueId(PrintWriter pw) {
256         UserHandle.formatUid(pw, callingUid);
257         pw.print("/");
258         pw.print(job.getId());
259     }
260 
getNumFailures()261     public int getNumFailures() {
262         return numFailures;
263     }
264 
getServiceComponent()265     public ComponentName getServiceComponent() {
266         return job.getService();
267     }
268 
getSourcePackageName()269     public String getSourcePackageName() {
270         return sourcePackageName;
271     }
272 
getSourceUid()273     public int getSourceUid() {
274         return sourceUid;
275     }
276 
getSourceUserId()277     public int getSourceUserId() {
278         return sourceUserId;
279     }
280 
getUserId()281     public int getUserId() {
282         return UserHandle.getUserId(callingUid);
283     }
284 
getSourceTag()285     public String getSourceTag() {
286         return sourceTag;
287     }
288 
getUid()289     public int getUid() {
290         return callingUid;
291     }
292 
getBatteryName()293     public String getBatteryName() {
294         return batteryName;
295     }
296 
getTag()297     public String getTag() {
298         return tag;
299     }
300 
getExtras()301     public PersistableBundle getExtras() {
302         return job.getExtras();
303     }
304 
getPriority()305     public int getPriority() {
306         return job.getPriority();
307     }
308 
getFlags()309     public int getFlags() {
310         return job.getFlags();
311     }
312 
hasConnectivityConstraint()313     public boolean hasConnectivityConstraint() {
314         return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
315     }
316 
hasUnmeteredConstraint()317     public boolean hasUnmeteredConstraint() {
318         return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
319     }
320 
hasNotRoamingConstraint()321     public boolean hasNotRoamingConstraint() {
322         return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0;
323     }
324 
hasChargingConstraint()325     public boolean hasChargingConstraint() {
326         return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
327     }
328 
hasTimingDelayConstraint()329     public boolean hasTimingDelayConstraint() {
330         return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
331     }
332 
hasDeadlineConstraint()333     public boolean hasDeadlineConstraint() {
334         return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
335     }
336 
hasIdleConstraint()337     public boolean hasIdleConstraint() {
338         return (requiredConstraints&CONSTRAINT_IDLE) != 0;
339     }
340 
hasContentTriggerConstraint()341     public boolean hasContentTriggerConstraint() {
342         return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
343     }
344 
getTriggerContentUpdateDelay()345     public long getTriggerContentUpdateDelay() {
346         long time = job.getTriggerContentUpdateDelay();
347         if (time < 0) {
348             return DEFAULT_TRIGGER_UPDATE_DELAY;
349         }
350         return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
351     }
352 
getTriggerContentMaxDelay()353     public long getTriggerContentMaxDelay() {
354         long time = job.getTriggerContentMaxDelay();
355         if (time < 0) {
356             return DEFAULT_TRIGGER_MAX_DELAY;
357         }
358         return Math.max(time, MIN_TRIGGER_MAX_DELAY);
359     }
360 
isPersisted()361     public boolean isPersisted() {
362         return job.isPersisted();
363     }
364 
getEarliestRunTime()365     public long getEarliestRunTime() {
366         return earliestRunTimeElapsedMillis;
367     }
368 
getLatestRunTimeElapsed()369     public long getLatestRunTimeElapsed() {
370         return latestRunTimeElapsedMillis;
371     }
372 
setChargingConstraintSatisfied(boolean state)373     boolean setChargingConstraintSatisfied(boolean state) {
374         return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
375     }
376 
setTimingDelayConstraintSatisfied(boolean state)377     boolean setTimingDelayConstraintSatisfied(boolean state) {
378         return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
379     }
380 
setDeadlineConstraintSatisfied(boolean state)381     boolean setDeadlineConstraintSatisfied(boolean state) {
382         return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
383     }
384 
setIdleConstraintSatisfied(boolean state)385     boolean setIdleConstraintSatisfied(boolean state) {
386         return setConstraintSatisfied(CONSTRAINT_IDLE, state);
387     }
388 
setConnectivityConstraintSatisfied(boolean state)389     boolean setConnectivityConstraintSatisfied(boolean state) {
390         return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
391     }
392 
setUnmeteredConstraintSatisfied(boolean state)393     boolean setUnmeteredConstraintSatisfied(boolean state) {
394         return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
395     }
396 
setNotRoamingConstraintSatisfied(boolean state)397     boolean setNotRoamingConstraintSatisfied(boolean state) {
398         return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state);
399     }
400 
setAppNotIdleConstraintSatisfied(boolean state)401     boolean setAppNotIdleConstraintSatisfied(boolean state) {
402         return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
403     }
404 
setContentTriggerConstraintSatisfied(boolean state)405     boolean setContentTriggerConstraintSatisfied(boolean state) {
406         return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
407     }
408 
setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted)409     boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
410         dozeWhitelisted = whitelisted;
411         return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
412     }
413 
setConstraintSatisfied(int constraint, boolean state)414     boolean setConstraintSatisfied(int constraint, boolean state) {
415         boolean old = (satisfiedConstraints&constraint) != 0;
416         if (old == state) {
417             return false;
418         }
419         satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
420         return true;
421     }
422 
isConstraintSatisfied(int constraint)423     boolean isConstraintSatisfied(int constraint) {
424         return (satisfiedConstraints&constraint) != 0;
425     }
426 
shouldDump(int filterUid)427     public boolean shouldDump(int filterUid) {
428         return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
429                 || UserHandle.getAppId(getSourceUid()) == filterUid;
430     }
431 
432     /**
433      * @return Whether or not this job is ready to run, based on its requirements. This is true if
434      * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
435      */
isReady()436     public boolean isReady() {
437         // Deadline constraint trumps other constraints (except for periodic jobs where deadline
438         // is an implementation detail. A periodic job should only run if its constraints are
439         // satisfied).
440         // AppNotIdle implicit constraint must be satisfied
441         // DeviceNotDozing implicit constraint must be satisfied
442         final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
443                 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
444         final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
445         final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
446                 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
447         return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing;
448     }
449 
450     static final int CONSTRAINTS_OF_INTEREST =
451             CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
452             CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING |
453             CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
454 
455     // Soft override covers all non-"functional" constraints
456     static final int SOFT_OVERRIDE_CONSTRAINTS =
457             CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
458 
459     /**
460      * @return Whether the constraints set on this job are satisfied.
461      */
isConstraintsSatisfied()462     public boolean isConstraintsSatisfied() {
463         if (overrideState == OVERRIDE_FULL) {
464             // force override: the job is always runnable
465             return true;
466         }
467 
468         final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
469 
470         int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
471         if (overrideState == OVERRIDE_SOFT) {
472             // override: pretend all 'soft' requirements are satisfied
473             sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
474         }
475 
476         return (sat & req) == req;
477     }
478 
matches(int uid, int jobId)479     public boolean matches(int uid, int jobId) {
480         return this.job.getId() == jobId && this.callingUid == uid;
481     }
482 
483     @Override
toString()484     public String toString() {
485         return String.valueOf(hashCode()).substring(0, 3) + ".."
486                 + ":[" + job.getService()
487                 + ",jId=" + job.getId()
488                 + ",u" + getUserId()
489                 + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
490                 + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
491                 + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
492                 + ",I=" + job.isRequireDeviceIdle()
493                 + ",U=" + (job.getTriggerContentUris() != null)
494                 + ",F=" + numFailures + ",P=" + job.isPersisted()
495                 + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
496                 + ",DND=" + ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0)
497                 + (isReady() ? "(READY)" : "")
498                 + "]";
499     }
500 
formatRunTime(long runtime, long defaultValue)501     private String formatRunTime(long runtime, long  defaultValue) {
502         if (runtime == defaultValue) {
503             return "none";
504         } else {
505             long elapsedNow = SystemClock.elapsedRealtime();
506             long nextRuntime = runtime - elapsedNow;
507             if (nextRuntime > 0) {
508                 return DateUtils.formatElapsedTime(nextRuntime / 1000);
509             } else {
510                 return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
511             }
512         }
513     }
514 
515     /**
516      * Convenience function to identify a job uniquely without pulling all the data that
517      * {@link #toString()} returns.
518      */
toShortString()519     public String toShortString() {
520         StringBuilder sb = new StringBuilder();
521         sb.append(Integer.toHexString(System.identityHashCode(this)));
522         sb.append(" #");
523         UserHandle.formatUid(sb, callingUid);
524         sb.append("/");
525         sb.append(job.getId());
526         sb.append(' ');
527         sb.append(batteryName);
528         return sb.toString();
529     }
530 
531     /**
532      * Convenience function to identify a job uniquely without pulling all the data that
533      * {@link #toString()} returns.
534      */
toShortStringExceptUniqueId()535     public String toShortStringExceptUniqueId() {
536         StringBuilder sb = new StringBuilder();
537         sb.append(Integer.toHexString(System.identityHashCode(this)));
538         sb.append(' ');
539         sb.append(batteryName);
540         return sb.toString();
541     }
542 
dumpConstraints(PrintWriter pw, int constraints)543     void dumpConstraints(PrintWriter pw, int constraints) {
544         if ((constraints&CONSTRAINT_CHARGING) != 0) {
545             pw.print(" CHARGING");
546         }
547         if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
548             pw.print(" TIMING_DELAY");
549         }
550         if ((constraints&CONSTRAINT_DEADLINE) != 0) {
551             pw.print(" DEADLINE");
552         }
553         if ((constraints&CONSTRAINT_IDLE) != 0) {
554             pw.print(" IDLE");
555         }
556         if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
557             pw.print(" CONNECTIVITY");
558         }
559         if ((constraints&CONSTRAINT_UNMETERED) != 0) {
560             pw.print(" UNMETERED");
561         }
562         if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
563             pw.print(" NOT_ROAMING");
564         }
565         if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
566             pw.print(" APP_NOT_IDLE");
567         }
568         if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
569             pw.print(" CONTENT_TRIGGER");
570         }
571         if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
572             pw.print(" DEVICE_NOT_DOZING");
573         }
574     }
575 
576     // Dumpsys infrastructure
dump(PrintWriter pw, String prefix, boolean full)577     public void dump(PrintWriter pw, String prefix, boolean full) {
578         pw.print(prefix); UserHandle.formatUid(pw, callingUid);
579         pw.print(" tag="); pw.println(tag);
580         pw.print(prefix);
581         pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
582         pw.print(" user="); pw.print(getSourceUserId());
583         pw.print(" pkg="); pw.println(getSourcePackageName());
584         if (full) {
585             pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix);
586             pw.print("  Service: "); pw.println(job.getService().flattenToShortString());
587             if (job.isPeriodic()) {
588                 pw.print(prefix); pw.print("  PERIODIC: interval=");
589                 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
590                 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
591                 pw.println();
592             }
593             if (job.isPersisted()) {
594                 pw.print(prefix); pw.println("  PERSISTED");
595             }
596             if (job.getPriority() != 0) {
597                 pw.print(prefix); pw.print("  Priority: "); pw.println(job.getPriority());
598             }
599             if (job.getFlags() != 0) {
600                 pw.print(prefix); pw.print("  Flags: ");
601                 pw.println(Integer.toHexString(job.getFlags()));
602             }
603             pw.print(prefix); pw.print("  Requires: charging=");
604             pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
605             pw.println(job.isRequireDeviceIdle());
606             if (job.getTriggerContentUris() != null) {
607                 pw.print(prefix); pw.println("  Trigger content URIs:");
608                 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
609                     JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
610                     pw.print(prefix); pw.print("    ");
611                     pw.print(Integer.toHexString(trig.getFlags()));
612                     pw.print(' '); pw.println(trig.getUri());
613                 }
614                 if (job.getTriggerContentUpdateDelay() >= 0) {
615                     pw.print(prefix); pw.print("  Trigger update delay: ");
616                     TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
617                     pw.println();
618                 }
619                 if (job.getTriggerContentMaxDelay() >= 0) {
620                     pw.print(prefix); pw.print("  Trigger max delay: ");
621                     TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
622                     pw.println();
623                 }
624             }
625             if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
626                 pw.print(prefix); pw.print("  Network type: "); pw.println(job.getNetworkType());
627             }
628             if (job.getMinLatencyMillis() != 0) {
629                 pw.print(prefix); pw.print("  Minimum latency: ");
630                 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
631                 pw.println();
632             }
633             if (job.getMaxExecutionDelayMillis() != 0) {
634                 pw.print(prefix); pw.print("  Max execution delay: ");
635                 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
636                 pw.println();
637             }
638             pw.print(prefix); pw.print("  Backoff: policy="); pw.print(job.getBackoffPolicy());
639             pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
640             pw.println();
641             if (job.hasEarlyConstraint()) {
642                 pw.print(prefix); pw.println("  Has early constraint");
643             }
644             if (job.hasLateConstraint()) {
645                 pw.print(prefix); pw.println("  Has late constraint");
646             }
647         }
648         pw.print(prefix); pw.print("Required constraints:");
649         dumpConstraints(pw, requiredConstraints);
650         pw.println();
651         if (full) {
652             pw.print(prefix); pw.print("Satisfied constraints:");
653             dumpConstraints(pw, satisfiedConstraints);
654             pw.println();
655             pw.print(prefix); pw.print("Unsatisfied constraints:");
656             dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
657             pw.println();
658             if (dozeWhitelisted) {
659                 pw.print(prefix); pw.println("Doze whitelisted: true");
660             }
661         }
662         if (changedAuthorities != null) {
663             pw.print(prefix); pw.println("Changed authorities:");
664             for (int i=0; i<changedAuthorities.size(); i++) {
665                 pw.print(prefix); pw.print("  "); pw.println(changedAuthorities.valueAt(i));
666             }
667             if (changedUris != null) {
668                 pw.print(prefix); pw.println("Changed URIs:");
669                 for (int i=0; i<changedUris.size(); i++) {
670                     pw.print(prefix); pw.print("  "); pw.println(changedUris.valueAt(i));
671                 }
672             }
673         }
674         pw.print(prefix); pw.print("Earliest run time: ");
675         pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
676         pw.print(prefix); pw.print("Latest run time: ");
677         pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
678         if (numFailures != 0) {
679             pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
680         }
681     }
682 }
683