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