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 + ",suid=" + getSourceUid() 490 + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME) 491 + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")" 492 + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging() 493 + ",I=" + job.isRequireDeviceIdle() 494 + ",U=" + (job.getTriggerContentUris() != null) 495 + ",F=" + numFailures + ",P=" + job.isPersisted() 496 + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0) 497 + ",DND=" + ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) 498 + (isReady() ? "(READY)" : "") 499 + "]"; 500 } 501 formatRunTime(long runtime, long defaultValue)502 private String formatRunTime(long runtime, long defaultValue) { 503 if (runtime == defaultValue) { 504 return "none"; 505 } else { 506 long elapsedNow = SystemClock.elapsedRealtime(); 507 long nextRuntime = runtime - elapsedNow; 508 if (nextRuntime > 0) { 509 return DateUtils.formatElapsedTime(nextRuntime / 1000); 510 } else { 511 return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000); 512 } 513 } 514 } 515 516 /** 517 * Convenience function to identify a job uniquely without pulling all the data that 518 * {@link #toString()} returns. 519 */ toShortString()520 public String toShortString() { 521 StringBuilder sb = new StringBuilder(); 522 sb.append(Integer.toHexString(System.identityHashCode(this))); 523 sb.append(" #"); 524 UserHandle.formatUid(sb, callingUid); 525 sb.append("/"); 526 sb.append(job.getId()); 527 sb.append(' '); 528 sb.append(batteryName); 529 return sb.toString(); 530 } 531 532 /** 533 * Convenience function to identify a job uniquely without pulling all the data that 534 * {@link #toString()} returns. 535 */ toShortStringExceptUniqueId()536 public String toShortStringExceptUniqueId() { 537 StringBuilder sb = new StringBuilder(); 538 sb.append(Integer.toHexString(System.identityHashCode(this))); 539 sb.append(' '); 540 sb.append(batteryName); 541 return sb.toString(); 542 } 543 dumpConstraints(PrintWriter pw, int constraints)544 void dumpConstraints(PrintWriter pw, int constraints) { 545 if ((constraints&CONSTRAINT_CHARGING) != 0) { 546 pw.print(" CHARGING"); 547 } 548 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) { 549 pw.print(" TIMING_DELAY"); 550 } 551 if ((constraints&CONSTRAINT_DEADLINE) != 0) { 552 pw.print(" DEADLINE"); 553 } 554 if ((constraints&CONSTRAINT_IDLE) != 0) { 555 pw.print(" IDLE"); 556 } 557 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) { 558 pw.print(" CONNECTIVITY"); 559 } 560 if ((constraints&CONSTRAINT_UNMETERED) != 0) { 561 pw.print(" UNMETERED"); 562 } 563 if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) { 564 pw.print(" NOT_ROAMING"); 565 } 566 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) { 567 pw.print(" APP_NOT_IDLE"); 568 } 569 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) { 570 pw.print(" CONTENT_TRIGGER"); 571 } 572 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) { 573 pw.print(" DEVICE_NOT_DOZING"); 574 } 575 } 576 577 // Dumpsys infrastructure dump(PrintWriter pw, String prefix, boolean full)578 public void dump(PrintWriter pw, String prefix, boolean full) { 579 pw.print(prefix); UserHandle.formatUid(pw, callingUid); 580 pw.print(" tag="); pw.println(tag); 581 pw.print(prefix); 582 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid()); 583 pw.print(" user="); pw.print(getSourceUserId()); 584 pw.print(" pkg="); pw.println(getSourcePackageName()); 585 if (full) { 586 pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix); 587 pw.print(" Service: "); pw.println(job.getService().flattenToShortString()); 588 if (job.isPeriodic()) { 589 pw.print(prefix); pw.print(" PERIODIC: interval="); 590 TimeUtils.formatDuration(job.getIntervalMillis(), pw); 591 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw); 592 pw.println(); 593 } 594 if (job.isPersisted()) { 595 pw.print(prefix); pw.println(" PERSISTED"); 596 } 597 if (job.getPriority() != 0) { 598 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority()); 599 } 600 if (job.getFlags() != 0) { 601 pw.print(prefix); pw.print(" Flags: "); 602 pw.println(Integer.toHexString(job.getFlags())); 603 } 604 pw.print(prefix); pw.print(" Requires: charging="); 605 pw.print(job.isRequireCharging()); pw.print(" deviceIdle="); 606 pw.println(job.isRequireDeviceIdle()); 607 if (job.getTriggerContentUris() != null) { 608 pw.print(prefix); pw.println(" Trigger content URIs:"); 609 for (int i = 0; i < job.getTriggerContentUris().length; i++) { 610 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i]; 611 pw.print(prefix); pw.print(" "); 612 pw.print(Integer.toHexString(trig.getFlags())); 613 pw.print(' '); pw.println(trig.getUri()); 614 } 615 if (job.getTriggerContentUpdateDelay() >= 0) { 616 pw.print(prefix); pw.print(" Trigger update delay: "); 617 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw); 618 pw.println(); 619 } 620 if (job.getTriggerContentMaxDelay() >= 0) { 621 pw.print(prefix); pw.print(" Trigger max delay: "); 622 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw); 623 pw.println(); 624 } 625 } 626 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) { 627 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType()); 628 } 629 if (job.getMinLatencyMillis() != 0) { 630 pw.print(prefix); pw.print(" Minimum latency: "); 631 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw); 632 pw.println(); 633 } 634 if (job.getMaxExecutionDelayMillis() != 0) { 635 pw.print(prefix); pw.print(" Max execution delay: "); 636 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw); 637 pw.println(); 638 } 639 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy()); 640 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw); 641 pw.println(); 642 if (job.hasEarlyConstraint()) { 643 pw.print(prefix); pw.println(" Has early constraint"); 644 } 645 if (job.hasLateConstraint()) { 646 pw.print(prefix); pw.println(" Has late constraint"); 647 } 648 } 649 pw.print(prefix); pw.print("Required constraints:"); 650 dumpConstraints(pw, requiredConstraints); 651 pw.println(); 652 if (full) { 653 pw.print(prefix); pw.print("Satisfied constraints:"); 654 dumpConstraints(pw, satisfiedConstraints); 655 pw.println(); 656 pw.print(prefix); pw.print("Unsatisfied constraints:"); 657 dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints)); 658 pw.println(); 659 if (dozeWhitelisted) { 660 pw.print(prefix); pw.println("Doze whitelisted: true"); 661 } 662 } 663 if (changedAuthorities != null) { 664 pw.print(prefix); pw.println("Changed authorities:"); 665 for (int i=0; i<changedAuthorities.size(); i++) { 666 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i)); 667 } 668 if (changedUris != null) { 669 pw.print(prefix); pw.println("Changed URIs:"); 670 for (int i=0; i<changedUris.size(); i++) { 671 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i)); 672 } 673 } 674 } 675 pw.print(prefix); pw.print("Earliest run time: "); 676 pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)); 677 pw.print(prefix); pw.print("Latest run time: "); 678 pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME)); 679 if (numFailures != 0) { 680 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures); 681 } 682 } 683 } 684