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.IActivityManager; 21 import android.app.job.JobInfo; 22 import android.app.job.JobWorkItem; 23 import android.content.ClipData; 24 import android.content.ComponentName; 25 import android.net.Uri; 26 import android.os.RemoteException; 27 import android.os.SystemClock; 28 import android.os.UserHandle; 29 import android.util.ArraySet; 30 import android.util.Slog; 31 import android.util.TimeUtils; 32 33 import com.android.server.job.GrantedUriPermissions; 34 35 import java.io.PrintWriter; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 39 /** 40 * Uniquely identifies a job internally. 41 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler. 42 * Contains current state of the requirements of the job, as well as a function to evaluate 43 * whether it's ready to run. 44 * This object is shared among the various controllers - hence why the different fields are atomic. 45 * This isn't strictly necessary because each controller is only interested in a specific field, 46 * and the receivers that are listening for global state change will all run on the main looper, 47 * but we don't enforce that so this is safer. 48 * @hide 49 */ 50 public final class JobStatus { 51 static final String TAG = "JobSchedulerService"; 52 53 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE; 54 public static final long NO_EARLIEST_RUNTIME = 0L; 55 56 static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; 57 static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; 58 static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; 59 static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW; 60 static final int CONSTRAINT_TIMING_DELAY = 1<<31; 61 static final int CONSTRAINT_DEADLINE = 1<<30; 62 static final int CONSTRAINT_UNMETERED = 1<<29; 63 static final int CONSTRAINT_CONNECTIVITY = 1<<28; 64 static final int CONSTRAINT_APP_NOT_IDLE = 1<<27; 65 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26; 66 static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25; 67 static final int CONSTRAINT_NOT_ROAMING = 1<<24; 68 static final int CONSTRAINT_METERED = 1<<23; 69 70 static final int CONNECTIVITY_MASK = 71 CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY | 72 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED; 73 74 // Soft override: ignore constraints like time that don't affect API availability 75 public static final int OVERRIDE_SOFT = 1; 76 // Full override: ignore all constraints including API-affecting like connectivity 77 public static final int OVERRIDE_FULL = 2; 78 79 /** If not specified, trigger update delay is 10 seconds. */ 80 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000; 81 82 /** The minimum possible update delay is 1/2 second. */ 83 public static final long MIN_TRIGGER_UPDATE_DELAY = 500; 84 85 /** If not specified, trigger maxumum delay is 2 minutes. */ 86 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000; 87 88 /** The minimum possible update delay is 1 second. */ 89 public static final long MIN_TRIGGER_MAX_DELAY = 1000; 90 91 final JobInfo job; 92 /** Uid of the package requesting this job. */ 93 final int callingUid; 94 final String batteryName; 95 96 final String sourcePackageName; 97 final int sourceUserId; 98 final int sourceUid; 99 final String sourceTag; 100 101 final String tag; 102 103 private GrantedUriPermissions uriPerms; 104 private boolean prepared; 105 106 static final boolean DEBUG_PREPARE = true; 107 private Throwable unpreparedPoint = null; 108 109 /** 110 * Earliest point in the future at which this job will be eligible to run. A value of 0 111 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}. 112 */ 113 private final long earliestRunTimeElapsedMillis; 114 /** 115 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE} 116 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}. 117 */ 118 private final long latestRunTimeElapsedMillis; 119 120 /** How many times this job has failed, used to compute back-off. */ 121 private final int numFailures; 122 123 // Constraints. 124 final int requiredConstraints; 125 int satisfiedConstraints = 0; 126 127 // Set to true if doze constraint was satisfied due to app being whitelisted. 128 public boolean dozeWhitelisted; 129 130 /** 131 * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job. 132 */ 133 public static final int TRACKING_BATTERY = 1<<0; 134 /** 135 * Flag for {@link #trackingControllers}: the network connectivity controller is currently 136 * tracking this job. 137 */ 138 public static final int TRACKING_CONNECTIVITY = 1<<1; 139 /** 140 * Flag for {@link #trackingControllers}: the content observer controller is currently 141 * tracking this job. 142 */ 143 public static final int TRACKING_CONTENT = 1<<2; 144 /** 145 * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job. 146 */ 147 public static final int TRACKING_IDLE = 1<<3; 148 /** 149 * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job. 150 */ 151 public static final int TRACKING_STORAGE = 1<<4; 152 /** 153 * Flag for {@link #trackingControllers}: the time controller is currently tracking this job. 154 */ 155 public static final int TRACKING_TIME = 1<<5; 156 157 /** 158 * Bit mask of controllers that are currently tracking the job. 159 */ 160 private int trackingControllers; 161 162 // These are filled in by controllers when preparing for execution. 163 public ArraySet<Uri> changedUris; 164 public ArraySet<String> changedAuthorities; 165 166 public int lastEvaluatedPriority; 167 168 // If non-null, this is work that has been enqueued for the job. 169 public ArrayList<JobWorkItem> pendingWork; 170 171 // If non-null, this is work that is currently being executed. 172 public ArrayList<JobWorkItem> executingWork; 173 174 public int nextPendingWorkId = 1; 175 176 // Used by shell commands 177 public int overrideState = 0; 178 179 // When this job was enqueued, for ordering. (in elapsedRealtimeMillis) 180 public long enqueueTime; 181 182 // Metrics about queue latency. (in uptimeMillis) 183 public long madePending; 184 public long madeActive; 185 186 /** 187 * For use only by ContentObserverController: state it is maintaining about content URIs 188 * being observed. 189 */ 190 ContentObserverController.JobInstance contentObserverJobInstance; 191 192 /** Provide a handle to the service that this job will be run on. */ 193 public int getServiceToken() { 194 return callingUid; 195 } 196 197 private JobStatus(JobInfo job, int callingUid, String sourcePackageName, 198 int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis, 199 long latestRunTimeElapsedMillis) { 200 this.job = job; 201 this.callingUid = callingUid; 202 203 int tempSourceUid = -1; 204 if (sourceUserId != -1 && sourcePackageName != null) { 205 try { 206 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0, 207 sourceUserId); 208 } catch (RemoteException ex) { 209 // Can't happen, PackageManager runs in the same process. 210 } 211 } 212 if (tempSourceUid == -1) { 213 this.sourceUid = callingUid; 214 this.sourceUserId = UserHandle.getUserId(callingUid); 215 this.sourcePackageName = job.getService().getPackageName(); 216 this.sourceTag = null; 217 } else { 218 this.sourceUid = tempSourceUid; 219 this.sourceUserId = sourceUserId; 220 this.sourcePackageName = sourcePackageName; 221 this.sourceTag = tag; 222 } 223 224 this.batteryName = this.sourceTag != null 225 ? this.sourceTag + ":" + job.getService().getPackageName() 226 : job.getService().flattenToShortString(); 227 this.tag = "*job*/" + this.batteryName; 228 229 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis; 230 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis; 231 this.numFailures = numFailures; 232 233 int requiredConstraints = job.getConstraintFlags(); 234 235 switch (job.getNetworkType()) { 236 case JobInfo.NETWORK_TYPE_NONE: 237 // No constraint. 238 break; 239 case JobInfo.NETWORK_TYPE_ANY: 240 requiredConstraints |= CONSTRAINT_CONNECTIVITY; 241 break; 242 case JobInfo.NETWORK_TYPE_UNMETERED: 243 requiredConstraints |= CONSTRAINT_UNMETERED; 244 break; 245 case JobInfo.NETWORK_TYPE_NOT_ROAMING: 246 requiredConstraints |= CONSTRAINT_NOT_ROAMING; 247 break; 248 case JobInfo.NETWORK_TYPE_METERED: 249 requiredConstraints |= CONSTRAINT_METERED; 250 break; 251 default: 252 Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType()); 253 break; 254 } 255 256 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) { 257 requiredConstraints |= CONSTRAINT_TIMING_DELAY; 258 } 259 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { 260 requiredConstraints |= CONSTRAINT_DEADLINE; 261 } 262 if (job.getTriggerContentUris() != null) { 263 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER; 264 } 265 this.requiredConstraints = requiredConstraints; 266 } 267 268 /** Copy constructor. */ 269 public JobStatus(JobStatus jobStatus) { 270 this(jobStatus.getJob(), jobStatus.getUid(), 271 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), 272 jobStatus.getSourceTag(), jobStatus.getNumFailures(), 273 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed()); 274 } 275 276 /** 277 * Create a new JobStatus that was loaded from disk. We ignore the provided 278 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job 279 * from the {@link com.android.server.job.JobStore} and still want to respect its 280 * wallclock runtime rather than resetting it on every boot. 281 * We consider a freshly loaded job to no longer be in back-off. 282 */ 283 public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, 284 String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) { 285 this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0, 286 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis); 287 } 288 289 /** Create a new job to be rescheduled with the provided parameters. */ 290 public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, 291 long newLatestRuntimeElapsedMillis, int backoffAttempt) { 292 this(rescheduling.job, rescheduling.getUid(), 293 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), 294 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis, 295 newLatestRuntimeElapsedMillis); 296 } 297 298 /** 299 * Create a newly scheduled job. 300 * @param callingUid Uid of the package that scheduled this job. 301 * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates 302 * the calling package is the source. 303 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the 304 */ 305 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName, 306 int sourceUserId, String tag) { 307 final long elapsedNow = SystemClock.elapsedRealtime(); 308 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis; 309 if (job.isPeriodic()) { 310 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis(); 311 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis(); 312 } else { 313 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ? 314 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME; 315 latestRunTimeElapsedMillis = job.hasLateConstraint() ? 316 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME; 317 } 318 return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0, 319 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis); 320 } 321 322 public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) { 323 if (pendingWork == null) { 324 pendingWork = new ArrayList<>(); 325 } 326 work.setWorkId(nextPendingWorkId); 327 nextPendingWorkId++; 328 if (work.getIntent() != null 329 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) { 330 work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid, 331 sourcePackageName, sourceUserId, toShortString())); 332 } 333 pendingWork.add(work); 334 } 335 336 public JobWorkItem dequeueWorkLocked() { 337 if (pendingWork != null && pendingWork.size() > 0) { 338 JobWorkItem work = pendingWork.remove(0); 339 if (work != null) { 340 if (executingWork == null) { 341 executingWork = new ArrayList<>(); 342 } 343 executingWork.add(work); 344 work.bumpDeliveryCount(); 345 } 346 return work; 347 } 348 return null; 349 } 350 351 public boolean hasWorkLocked() { 352 return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked(); 353 } 354 355 public boolean hasExecutingWorkLocked() { 356 return executingWork != null && executingWork.size() > 0; 357 } 358 359 private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) { 360 if (work.getGrants() != null) { 361 ((GrantedUriPermissions)work.getGrants()).revoke(am); 362 } 363 } 364 365 public boolean completeWorkLocked(IActivityManager am, int workId) { 366 if (executingWork != null) { 367 final int N = executingWork.size(); 368 for (int i = 0; i < N; i++) { 369 JobWorkItem work = executingWork.get(i); 370 if (work.getWorkId() == workId) { 371 executingWork.remove(i); 372 ungrantWorkItem(am, work); 373 return true; 374 } 375 } 376 } 377 return false; 378 } 379 380 private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) { 381 if (list != null) { 382 final int N = list.size(); 383 for (int i = 0; i < N; i++) { 384 ungrantWorkItem(am, list.get(i)); 385 } 386 } 387 } 388 389 public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) { 390 if (incomingJob != null) { 391 // We are replacing with a new job -- transfer the work! We do any executing 392 // work first, since that was originally at the front of the pending work. 393 if (executingWork != null && executingWork.size() > 0) { 394 incomingJob.pendingWork = executingWork; 395 } 396 if (incomingJob.pendingWork == null) { 397 incomingJob.pendingWork = pendingWork; 398 } else if (pendingWork != null && pendingWork.size() > 0) { 399 incomingJob.pendingWork.addAll(pendingWork); 400 } 401 pendingWork = null; 402 executingWork = null; 403 incomingJob.nextPendingWorkId = nextPendingWorkId; 404 } else { 405 // We are completely stopping the job... need to clean up work. 406 ungrantWorkList(am, pendingWork); 407 pendingWork = null; 408 ungrantWorkList(am, executingWork); 409 executingWork = null; 410 } 411 } 412 413 public void prepareLocked(IActivityManager am) { 414 if (prepared) { 415 Slog.wtf(TAG, "Already prepared: " + this); 416 return; 417 } 418 prepared = true; 419 if (DEBUG_PREPARE) { 420 unpreparedPoint = null; 421 } 422 final ClipData clip = job.getClipData(); 423 if (clip != null) { 424 uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName, 425 sourceUserId, job.getClipGrantFlags(), toShortString()); 426 } 427 } 428 429 public void unprepareLocked(IActivityManager am) { 430 if (!prepared) { 431 Slog.wtf(TAG, "Hasn't been prepared: " + this); 432 if (DEBUG_PREPARE && unpreparedPoint != null) { 433 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint); 434 } 435 return; 436 } 437 prepared = false; 438 if (DEBUG_PREPARE) { 439 unpreparedPoint = new Throwable().fillInStackTrace(); 440 } 441 if (uriPerms != null) { 442 uriPerms.revoke(am); 443 uriPerms = null; 444 } 445 } 446 447 public boolean isPreparedLocked() { 448 return prepared; 449 } 450 451 public JobInfo getJob() { 452 return job; 453 } 454 455 public int getJobId() { 456 return job.getId(); 457 } 458 459 public void printUniqueId(PrintWriter pw) { 460 UserHandle.formatUid(pw, callingUid); 461 pw.print("/"); 462 pw.print(job.getId()); 463 } 464 465 public int getNumFailures() { 466 return numFailures; 467 } 468 469 public ComponentName getServiceComponent() { 470 return job.getService(); 471 } 472 473 public String getSourcePackageName() { 474 return sourcePackageName; 475 } 476 477 public int getSourceUid() { 478 return sourceUid; 479 } 480 481 public int getSourceUserId() { 482 return sourceUserId; 483 } 484 485 public int getUserId() { 486 return UserHandle.getUserId(callingUid); 487 } 488 489 public String getSourceTag() { 490 return sourceTag; 491 } 492 493 public int getUid() { 494 return callingUid; 495 } 496 497 public String getBatteryName() { 498 return batteryName; 499 } 500 501 public String getTag() { 502 return tag; 503 } 504 505 public int getPriority() { 506 return job.getPriority(); 507 } 508 509 public int getFlags() { 510 return job.getFlags(); 511 } 512 513 /** Does this job have any sort of networking constraint? */ 514 public boolean hasConnectivityConstraint() { 515 return (requiredConstraints&CONNECTIVITY_MASK) != 0; 516 } 517 518 public boolean needsAnyConnectivity() { 519 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0; 520 } 521 522 public boolean needsUnmeteredConnectivity() { 523 return (requiredConstraints&CONSTRAINT_UNMETERED) != 0; 524 } 525 526 public boolean needsMeteredConnectivity() { 527 return (requiredConstraints&CONSTRAINT_METERED) != 0; 528 } 529 530 public boolean needsNonRoamingConnectivity() { 531 return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0; 532 } 533 534 public boolean hasChargingConstraint() { 535 return (requiredConstraints&CONSTRAINT_CHARGING) != 0; 536 } 537 538 public boolean hasBatteryNotLowConstraint() { 539 return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0; 540 } 541 542 public boolean hasPowerConstraint() { 543 return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0; 544 } 545 546 public boolean hasStorageNotLowConstraint() { 547 return (requiredConstraints&CONSTRAINT_STORAGE_NOT_LOW) != 0; 548 } 549 550 public boolean hasTimingDelayConstraint() { 551 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0; 552 } 553 554 public boolean hasDeadlineConstraint() { 555 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0; 556 } 557 558 public boolean hasIdleConstraint() { 559 return (requiredConstraints&CONSTRAINT_IDLE) != 0; 560 } 561 562 public boolean hasContentTriggerConstraint() { 563 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0; 564 } 565 566 public long getTriggerContentUpdateDelay() { 567 long time = job.getTriggerContentUpdateDelay(); 568 if (time < 0) { 569 return DEFAULT_TRIGGER_UPDATE_DELAY; 570 } 571 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY); 572 } 573 574 public long getTriggerContentMaxDelay() { 575 long time = job.getTriggerContentMaxDelay(); 576 if (time < 0) { 577 return DEFAULT_TRIGGER_MAX_DELAY; 578 } 579 return Math.max(time, MIN_TRIGGER_MAX_DELAY); 580 } 581 582 public boolean isPersisted() { 583 return job.isPersisted(); 584 } 585 586 public long getEarliestRunTime() { 587 return earliestRunTimeElapsedMillis; 588 } 589 590 public long getLatestRunTimeElapsed() { 591 return latestRunTimeElapsedMillis; 592 } 593 594 boolean setChargingConstraintSatisfied(boolean state) { 595 return setConstraintSatisfied(CONSTRAINT_CHARGING, state); 596 } 597 598 boolean setBatteryNotLowConstraintSatisfied(boolean state) { 599 return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state); 600 } 601 602 boolean setStorageNotLowConstraintSatisfied(boolean state) { 603 return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state); 604 } 605 606 boolean setTimingDelayConstraintSatisfied(boolean state) { 607 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state); 608 } 609 610 boolean setDeadlineConstraintSatisfied(boolean state) { 611 return setConstraintSatisfied(CONSTRAINT_DEADLINE, state); 612 } 613 614 boolean setIdleConstraintSatisfied(boolean state) { 615 return setConstraintSatisfied(CONSTRAINT_IDLE, state); 616 } 617 618 boolean setConnectivityConstraintSatisfied(boolean state) { 619 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state); 620 } 621 622 boolean setUnmeteredConstraintSatisfied(boolean state) { 623 return setConstraintSatisfied(CONSTRAINT_UNMETERED, state); 624 } 625 626 boolean setMeteredConstraintSatisfied(boolean state) { 627 return setConstraintSatisfied(CONSTRAINT_METERED, state); 628 } 629 630 boolean setNotRoamingConstraintSatisfied(boolean state) { 631 return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state); 632 } 633 634 boolean setAppNotIdleConstraintSatisfied(boolean state) { 635 return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state); 636 } 637 638 boolean setContentTriggerConstraintSatisfied(boolean state) { 639 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state); 640 } 641 642 boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) { 643 dozeWhitelisted = whitelisted; 644 return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state); 645 } 646 647 boolean setConstraintSatisfied(int constraint, boolean state) { 648 boolean old = (satisfiedConstraints&constraint) != 0; 649 if (old == state) { 650 return false; 651 } 652 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0); 653 return true; 654 } 655 656 boolean isConstraintSatisfied(int constraint) { 657 return (satisfiedConstraints&constraint) != 0; 658 } 659 660 boolean clearTrackingController(int which) { 661 if ((trackingControllers&which) != 0) { 662 trackingControllers &= ~which; 663 return true; 664 } 665 return false; 666 } 667 668 void setTrackingController(int which) { 669 trackingControllers |= which; 670 } 671 672 public boolean shouldDump(int filterUid) { 673 return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid 674 || UserHandle.getAppId(getSourceUid()) == filterUid; 675 } 676 677 /** 678 * @return Whether or not this job is ready to run, based on its requirements. This is true if 679 * the constraints are satisfied <strong>or</strong> the deadline on the job has expired. 680 * TODO: This function is called a *lot*. We should probably just have it check an 681 * already-computed boolean, which we updated whenever we see one of the states it depends 682 * on here change. 683 */ 684 public boolean isReady() { 685 // Deadline constraint trumps other constraints (except for periodic jobs where deadline 686 // is an implementation detail. A periodic job should only run if its constraints are 687 // satisfied). 688 // AppNotIdle implicit constraint must be satisfied 689 // DeviceNotDozing implicit constraint must be satisfied 690 final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint() 691 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0); 692 final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0; 693 final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0 694 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; 695 return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing; 696 } 697 698 static final int CONSTRAINTS_OF_INTEREST = 699 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW | 700 CONSTRAINT_TIMING_DELAY | 701 CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | 702 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED | 703 CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER; 704 705 // Soft override covers all non-"functional" constraints 706 static final int SOFT_OVERRIDE_CONSTRAINTS = 707 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW 708 | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE; 709 710 /** 711 * @return Whether the constraints set on this job are satisfied. 712 */ 713 public boolean isConstraintsSatisfied() { 714 if (overrideState == OVERRIDE_FULL) { 715 // force override: the job is always runnable 716 return true; 717 } 718 719 final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST; 720 721 int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST; 722 if (overrideState == OVERRIDE_SOFT) { 723 // override: pretend all 'soft' requirements are satisfied 724 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS); 725 } 726 727 return (sat & req) == req; 728 } 729 730 public boolean matches(int uid, int jobId) { 731 return this.job.getId() == jobId && this.callingUid == uid; 732 } 733 734 @Override 735 public String toString() { 736 StringBuilder sb = new StringBuilder(128); 737 sb.append("JobStatus{"); 738 sb.append(Integer.toHexString(System.identityHashCode(this))); 739 sb.append(" #"); 740 UserHandle.formatUid(sb, callingUid); 741 sb.append("/"); 742 sb.append(job.getId()); 743 sb.append(' '); 744 sb.append(batteryName); 745 sb.append(" u="); 746 sb.append(getUserId()); 747 sb.append(" s="); 748 sb.append(getSourceUid()); 749 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME 750 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { 751 long now = SystemClock.elapsedRealtime(); 752 sb.append(" TIME="); 753 formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now); 754 sb.append(":"); 755 formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now); 756 } 757 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) { 758 sb.append(" NET="); 759 sb.append(job.getNetworkType()); 760 } 761 if (job.isRequireCharging()) { 762 sb.append(" CHARGING"); 763 } 764 if (job.isRequireBatteryNotLow()) { 765 sb.append(" BATNOTLOW"); 766 } 767 if (job.isRequireStorageNotLow()) { 768 sb.append(" STORENOTLOW"); 769 } 770 if (job.isRequireDeviceIdle()) { 771 sb.append(" IDLE"); 772 } 773 if (job.isPersisted()) { 774 sb.append(" PERSISTED"); 775 } 776 if ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) == 0) { 777 sb.append(" WAIT:APP_NOT_IDLE"); 778 } 779 if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) { 780 sb.append(" WAIT:DEV_NOT_DOZING"); 781 } 782 if (job.getTriggerContentUris() != null) { 783 sb.append(" URIS="); 784 sb.append(Arrays.toString(job.getTriggerContentUris())); 785 } 786 if (numFailures != 0) { 787 sb.append(" failures="); 788 sb.append(numFailures); 789 } 790 if (isReady()) { 791 sb.append(" READY"); 792 } 793 sb.append("}"); 794 return sb.toString(); 795 } 796 797 private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) { 798 if (runtime == defaultValue) { 799 pw.print("none"); 800 } else { 801 TimeUtils.formatDuration(runtime - now, pw); 802 } 803 } 804 805 private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) { 806 if (runtime == defaultValue) { 807 sb.append("none"); 808 } else { 809 TimeUtils.formatDuration(runtime - now, sb); 810 } 811 } 812 813 /** 814 * Convenience function to identify a job uniquely without pulling all the data that 815 * {@link #toString()} returns. 816 */ 817 public String toShortString() { 818 StringBuilder sb = new StringBuilder(); 819 sb.append(Integer.toHexString(System.identityHashCode(this))); 820 sb.append(" #"); 821 UserHandle.formatUid(sb, callingUid); 822 sb.append("/"); 823 sb.append(job.getId()); 824 sb.append(' '); 825 sb.append(batteryName); 826 return sb.toString(); 827 } 828 829 /** 830 * Convenience function to identify a job uniquely without pulling all the data that 831 * {@link #toString()} returns. 832 */ 833 public String toShortStringExceptUniqueId() { 834 StringBuilder sb = new StringBuilder(); 835 sb.append(Integer.toHexString(System.identityHashCode(this))); 836 sb.append(' '); 837 sb.append(batteryName); 838 return sb.toString(); 839 } 840 841 void dumpConstraints(PrintWriter pw, int constraints) { 842 if ((constraints&CONSTRAINT_CHARGING) != 0) { 843 pw.print(" CHARGING"); 844 } 845 if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) { 846 pw.print(" BATTERY_NOT_LOW"); 847 } 848 if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) { 849 pw.print(" STORAGE_NOT_LOW"); 850 } 851 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) { 852 pw.print(" TIMING_DELAY"); 853 } 854 if ((constraints&CONSTRAINT_DEADLINE) != 0) { 855 pw.print(" DEADLINE"); 856 } 857 if ((constraints&CONSTRAINT_IDLE) != 0) { 858 pw.print(" IDLE"); 859 } 860 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) { 861 pw.print(" CONNECTIVITY"); 862 } 863 if ((constraints&CONSTRAINT_UNMETERED) != 0) { 864 pw.print(" UNMETERED"); 865 } 866 if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) { 867 pw.print(" NOT_ROAMING"); 868 } 869 if ((constraints&CONSTRAINT_METERED) != 0) { 870 pw.print(" METERED"); 871 } 872 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) { 873 pw.print(" APP_NOT_IDLE"); 874 } 875 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) { 876 pw.print(" CONTENT_TRIGGER"); 877 } 878 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) { 879 pw.print(" DEVICE_NOT_DOZING"); 880 } 881 } 882 883 private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) { 884 pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #"); 885 pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount()); 886 pw.print("x "); pw.println(work.getIntent()); 887 if (work.getGrants() != null) { 888 pw.print(prefix); pw.println(" URI grants:"); 889 ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " "); 890 } 891 } 892 893 // Dumpsys infrastructure 894 public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) { 895 pw.print(prefix); UserHandle.formatUid(pw, callingUid); 896 pw.print(" tag="); pw.println(tag); 897 pw.print(prefix); 898 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid()); 899 pw.print(" user="); pw.print(getSourceUserId()); 900 pw.print(" pkg="); pw.println(getSourcePackageName()); 901 if (full) { 902 pw.print(prefix); pw.println("JobInfo:"); 903 pw.print(prefix); pw.print(" Service: "); 904 pw.println(job.getService().flattenToShortString()); 905 if (job.isPeriodic()) { 906 pw.print(prefix); pw.print(" PERIODIC: interval="); 907 TimeUtils.formatDuration(job.getIntervalMillis(), pw); 908 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw); 909 pw.println(); 910 } 911 if (job.isPersisted()) { 912 pw.print(prefix); pw.println(" PERSISTED"); 913 } 914 if (job.getPriority() != 0) { 915 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority()); 916 } 917 if (job.getFlags() != 0) { 918 pw.print(prefix); pw.print(" Flags: "); 919 pw.println(Integer.toHexString(job.getFlags())); 920 } 921 pw.print(prefix); pw.print(" Requires: charging="); 922 pw.print(job.isRequireCharging()); pw.print(" batteryNotLow="); 923 pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle="); 924 pw.println(job.isRequireDeviceIdle()); 925 if (job.getTriggerContentUris() != null) { 926 pw.print(prefix); pw.println(" Trigger content URIs:"); 927 for (int i = 0; i < job.getTriggerContentUris().length; i++) { 928 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i]; 929 pw.print(prefix); pw.print(" "); 930 pw.print(Integer.toHexString(trig.getFlags())); 931 pw.print(' '); pw.println(trig.getUri()); 932 } 933 if (job.getTriggerContentUpdateDelay() >= 0) { 934 pw.print(prefix); pw.print(" Trigger update delay: "); 935 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw); 936 pw.println(); 937 } 938 if (job.getTriggerContentMaxDelay() >= 0) { 939 pw.print(prefix); pw.print(" Trigger max delay: "); 940 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw); 941 pw.println(); 942 } 943 } 944 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) { 945 pw.print(prefix); pw.print(" Extras: "); 946 pw.println(job.getExtras().toShortString()); 947 } 948 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) { 949 pw.print(prefix); pw.print(" Transient extras: "); 950 pw.println(job.getTransientExtras().toShortString()); 951 } 952 if (job.getClipData() != null) { 953 pw.print(prefix); pw.print(" Clip data: "); 954 StringBuilder b = new StringBuilder(128); 955 job.getClipData().toShortString(b); 956 pw.println(b); 957 } 958 if (uriPerms != null) { 959 pw.print(prefix); pw.println(" Granted URI permissions:"); 960 uriPerms.dump(pw, prefix + " "); 961 } 962 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) { 963 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType()); 964 } 965 if (job.getMinLatencyMillis() != 0) { 966 pw.print(prefix); pw.print(" Minimum latency: "); 967 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw); 968 pw.println(); 969 } 970 if (job.getMaxExecutionDelayMillis() != 0) { 971 pw.print(prefix); pw.print(" Max execution delay: "); 972 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw); 973 pw.println(); 974 } 975 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy()); 976 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw); 977 pw.println(); 978 if (job.hasEarlyConstraint()) { 979 pw.print(prefix); pw.println(" Has early constraint"); 980 } 981 if (job.hasLateConstraint()) { 982 pw.print(prefix); pw.println(" Has late constraint"); 983 } 984 } 985 pw.print(prefix); pw.print("Required constraints:"); 986 dumpConstraints(pw, requiredConstraints); 987 pw.println(); 988 if (full) { 989 pw.print(prefix); pw.print("Satisfied constraints:"); 990 dumpConstraints(pw, satisfiedConstraints); 991 pw.println(); 992 pw.print(prefix); pw.print("Unsatisfied constraints:"); 993 dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints)); 994 pw.println(); 995 if (dozeWhitelisted) { 996 pw.print(prefix); pw.println("Doze whitelisted: true"); 997 } 998 } 999 if (trackingControllers != 0) { 1000 pw.print(prefix); pw.print("Tracking:"); 1001 if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY"); 1002 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY"); 1003 if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT"); 1004 if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE"); 1005 if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE"); 1006 if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME"); 1007 pw.println(); 1008 } 1009 if (changedAuthorities != null) { 1010 pw.print(prefix); pw.println("Changed authorities:"); 1011 for (int i=0; i<changedAuthorities.size(); i++) { 1012 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i)); 1013 } 1014 if (changedUris != null) { 1015 pw.print(prefix); pw.println("Changed URIs:"); 1016 for (int i=0; i<changedUris.size(); i++) { 1017 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i)); 1018 } 1019 } 1020 } 1021 if (pendingWork != null && pendingWork.size() > 0) { 1022 pw.print(prefix); pw.println("Pending work:"); 1023 for (int i = 0; i < pendingWork.size(); i++) { 1024 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i); 1025 } 1026 } 1027 if (executingWork != null && executingWork.size() > 0) { 1028 pw.print(prefix); pw.println("Executing work:"); 1029 for (int i = 0; i < executingWork.size(); i++) { 1030 dumpJobWorkItem(pw, prefix, executingWork.get(i), i); 1031 } 1032 } 1033 pw.print(prefix); pw.print("Enqueue time: "); 1034 TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw); 1035 pw.println(); 1036 pw.print(prefix); pw.print("Run time: earliest="); 1037 formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis); 1038 pw.print(", latest="); 1039 formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis); 1040 pw.println(); 1041 if (numFailures != 0) { 1042 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures); 1043 } 1044 } 1045 } 1046