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 static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; 20 import static com.android.server.job.JobSchedulerService.NEVER_INDEX; 21 import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; 22 import static com.android.server.job.JobSchedulerService.WORKING_INDEX; 23 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; 24 25 import android.app.AppGlobals; 26 import android.app.job.JobInfo; 27 import android.app.job.JobWorkItem; 28 import android.content.ClipData; 29 import android.content.ComponentName; 30 import android.net.Network; 31 import android.net.Uri; 32 import android.os.RemoteException; 33 import android.os.UserHandle; 34 import android.provider.MediaStore; 35 import android.text.format.DateFormat; 36 import android.util.ArraySet; 37 import android.util.Pair; 38 import android.util.Slog; 39 import android.util.TimeUtils; 40 import android.util.proto.ProtoOutputStream; 41 42 import com.android.internal.util.ArrayUtils; 43 import com.android.internal.util.FrameworkStatsLog; 44 import com.android.server.LocalServices; 45 import com.android.server.job.GrantedUriPermissions; 46 import com.android.server.job.JobSchedulerInternal; 47 import com.android.server.job.JobSchedulerService; 48 import com.android.server.job.JobServerProtoEnums; 49 import com.android.server.job.JobStatusDumpProto; 50 import com.android.server.job.JobStatusShortInfoProto; 51 52 import java.io.PrintWriter; 53 import java.util.ArrayList; 54 import java.util.Arrays; 55 import java.util.function.Predicate; 56 57 /** 58 * Uniquely identifies a job internally. 59 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler. 60 * Contains current state of the requirements of the job, as well as a function to evaluate 61 * whether it's ready to run. 62 * This object is shared among the various controllers - hence why the different fields are atomic. 63 * This isn't strictly necessary because each controller is only interested in a specific field, 64 * and the receivers that are listening for global state change will all run on the main looper, 65 * but we don't enforce that so this is safer. 66 * 67 * Test: atest com.android.server.job.controllers.JobStatusTest 68 * @hide 69 */ 70 public final class JobStatus { 71 private static final String TAG = "JobScheduler.JobStatus"; 72 static final boolean DEBUG = JobSchedulerService.DEBUG; 73 74 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE; 75 public static final long NO_EARLIEST_RUNTIME = 0L; 76 77 static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0 78 static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2 79 static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1 80 static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW; // 1 << 3 81 static final int CONSTRAINT_TIMING_DELAY = 1<<31; 82 static final int CONSTRAINT_DEADLINE = 1<<30; 83 static final int CONSTRAINT_CONNECTIVITY = 1 << 28; 84 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26; 85 static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint 86 static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint 87 static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint 88 89 /** 90 * The additional set of dynamic constraints that must be met if the job's effective bucket is 91 * {@link JobSchedulerService#RESTRICTED_INDEX}. Connectivity can be ignored if the job doesn't 92 * need network. 93 */ 94 private static final int DYNAMIC_RESTRICTED_CONSTRAINTS = 95 CONSTRAINT_BATTERY_NOT_LOW 96 | CONSTRAINT_CHARGING 97 | CONSTRAINT_CONNECTIVITY 98 | CONSTRAINT_IDLE; 99 100 /** 101 * Standard media URIs that contain the media files that might be important to the user. 102 * @see #mHasMediaBackupExemption 103 */ 104 private static final Uri[] MEDIA_URIS_FOR_STANDBY_EXEMPTION = { 105 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 106 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, 107 }; 108 109 /** 110 * The constraints that we want to log to statsd. 111 * 112 * Constraints that can be inferred from other atoms have been excluded to avoid logging too 113 * much information and to reduce redundancy: 114 * 115 * * CONSTRAINT_CHARGING can be inferred with PluggedStateChanged (Atom #32) 116 * * CONSTRAINT_BATTERY_NOT_LOW can be inferred with BatteryLevelChanged (Atom #30) 117 * * CONSTRAINT_CONNECTIVITY can be partially inferred with ConnectivityStateChanged 118 * (Atom #98) and BatterySaverModeStateChanged (Atom #20). 119 * * CONSTRAINT_DEVICE_NOT_DOZING can be mostly inferred with DeviceIdleModeStateChanged 120 * (Atom #21) 121 * * CONSTRAINT_BACKGROUND_NOT_RESTRICTED can be inferred with BatterySaverModeStateChanged 122 * (Atom #20) 123 */ 124 private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER 125 | CONSTRAINT_DEADLINE 126 | CONSTRAINT_IDLE 127 | CONSTRAINT_STORAGE_NOT_LOW 128 | CONSTRAINT_TIMING_DELAY 129 | CONSTRAINT_WITHIN_QUOTA; 130 131 // TODO(b/129954980) 132 private static final boolean STATS_LOG_ENABLED = false; 133 134 // No override. 135 public static final int OVERRIDE_NONE = 0; 136 // Override to improve sorting order. Does not affect constraint evaluation. 137 public static final int OVERRIDE_SORTING = 1; 138 // Soft override: ignore constraints like time that don't affect API availability 139 public static final int OVERRIDE_SOFT = 2; 140 // Full override: ignore all constraints including API-affecting like connectivity 141 public static final int OVERRIDE_FULL = 3; 142 143 /** If not specified, trigger update delay is 10 seconds. */ 144 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000; 145 146 /** The minimum possible update delay is 1/2 second. */ 147 public static final long MIN_TRIGGER_UPDATE_DELAY = 500; 148 149 /** If not specified, trigger maximum delay is 2 minutes. */ 150 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000; 151 152 /** The minimum possible update delay is 1 second. */ 153 public static final long MIN_TRIGGER_MAX_DELAY = 1000; 154 155 final JobInfo job; 156 /** 157 * Uid of the package requesting this job. This can differ from the "source" 158 * uid when the job was scheduled on the app's behalf, such as with the jobs 159 * that underly Sync Manager operation. 160 */ 161 final int callingUid; 162 final String batteryName; 163 164 /** 165 * Identity of the app in which the job is hosted. 166 */ 167 final String sourcePackageName; 168 final int sourceUserId; 169 final int sourceUid; 170 final String sourceTag; 171 172 final String tag; 173 174 private GrantedUriPermissions uriPerms; 175 private boolean prepared; 176 177 static final boolean DEBUG_PREPARE = true; 178 private Throwable unpreparedPoint = null; 179 180 /** 181 * Earliest point in the future at which this job will be eligible to run. A value of 0 182 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}. 183 */ 184 private final long earliestRunTimeElapsedMillis; 185 /** 186 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE} 187 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}. 188 */ 189 private final long latestRunTimeElapsedMillis; 190 191 /** 192 * Valid only for periodic jobs. The original latest point in the future at which this 193 * job was expected to run. 194 */ 195 private long mOriginalLatestRunTimeElapsedMillis; 196 197 /** How many times this job has failed, used to compute back-off. */ 198 private final int numFailures; 199 200 /** 201 * Which app standby bucket this job's app is in. Updated when the app is moved to a 202 * different bucket. 203 */ 204 private int standbyBucket; 205 206 /** 207 * Debugging: timestamp if we ever defer this job based on standby bucketing, this 208 * is when we did so. 209 */ 210 private long whenStandbyDeferred; 211 212 /** The first time this job was force batched. */ 213 private long mFirstForceBatchedTimeElapsed; 214 215 // Constraints. 216 final int requiredConstraints; 217 private final int mRequiredConstraintsOfInterest; 218 int satisfiedConstraints = 0; 219 private int mSatisfiedConstraintsOfInterest = 0; 220 /** 221 * Set of constraints that must be satisfied for the job if/because it's in the RESTRICTED 222 * bucket. 223 */ 224 private int mDynamicConstraints = 0; 225 226 /** 227 * Indicates whether the job is responsible for backing up media, so we can be lenient in 228 * applying standby throttling. 229 * 230 * Doesn't exempt jobs with a deadline constraint, as they can be started without any content or 231 * network changes, in which case this exemption does not make sense. 232 * 233 * TODO(b/149519887): Use a more explicit signal, maybe an API flag, that the scheduling package 234 * needs to provide at the time of scheduling a job. 235 */ 236 private final boolean mHasMediaBackupExemption; 237 238 // Set to true if doze constraint was satisfied due to app being whitelisted. 239 public boolean dozeWhitelisted; 240 241 // Set to true when the app is "active" per AppStateTracker 242 public boolean uidActive; 243 244 /** 245 * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job. 246 */ 247 public static final int TRACKING_BATTERY = 1<<0; 248 /** 249 * Flag for {@link #trackingControllers}: the network connectivity controller is currently 250 * tracking this job. 251 */ 252 public static final int TRACKING_CONNECTIVITY = 1<<1; 253 /** 254 * Flag for {@link #trackingControllers}: the content observer controller is currently 255 * tracking this job. 256 */ 257 public static final int TRACKING_CONTENT = 1<<2; 258 /** 259 * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job. 260 */ 261 public static final int TRACKING_IDLE = 1<<3; 262 /** 263 * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job. 264 */ 265 public static final int TRACKING_STORAGE = 1<<4; 266 /** 267 * Flag for {@link #trackingControllers}: the time controller is currently tracking this job. 268 */ 269 public static final int TRACKING_TIME = 1<<5; 270 /** 271 * Flag for {@link #trackingControllers}: the quota controller is currently tracking this job. 272 */ 273 public static final int TRACKING_QUOTA = 1 << 6; 274 275 /** 276 * Bit mask of controllers that are currently tracking the job. 277 */ 278 private int trackingControllers; 279 280 /** 281 * Flag for {@link #mInternalFlags}: this job was scheduled when the app that owns the job 282 * service (not necessarily the caller) was in the foreground and the job has no time 283 * constraints, which makes it exempted from the battery saver job restriction. 284 * 285 * @hide 286 */ 287 public static final int INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION = 1 << 0; 288 289 /** 290 * Versatile, persistable flags for a job that's updated within the system server, 291 * as opposed to {@link JobInfo#flags} that's set by callers. 292 */ 293 private int mInternalFlags; 294 295 // These are filled in by controllers when preparing for execution. 296 public ArraySet<Uri> changedUris; 297 public ArraySet<String> changedAuthorities; 298 public Network network; 299 300 public int lastEvaluatedPriority; 301 302 // If non-null, this is work that has been enqueued for the job. 303 public ArrayList<JobWorkItem> pendingWork; 304 305 // If non-null, this is work that is currently being executed. 306 public ArrayList<JobWorkItem> executingWork; 307 308 public int nextPendingWorkId = 1; 309 310 // Used by shell commands 311 public int overrideState = JobStatus.OVERRIDE_NONE; 312 313 // When this job was enqueued, for ordering. (in elapsedRealtimeMillis) 314 public long enqueueTime; 315 316 // Metrics about queue latency. (in uptimeMillis) 317 public long madePending; 318 public long madeActive; 319 320 /** 321 * Last time a job finished successfully for a periodic job, in the currentTimeMillis time, 322 * for dumpsys. 323 */ 324 private long mLastSuccessfulRunTime; 325 326 /** 327 * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys. 328 */ 329 private long mLastFailedRunTime; 330 331 /** 332 * Transient: when a job is inflated from disk before we have a reliable RTC clock time, 333 * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent 334 * store in UTC so that we can fix up the job's scheduling criteria once we get a good 335 * wall-clock time. If we have to persist the job again before the clock has been updated, 336 * we record these times again rather than calculating based on the earliest/latest elapsed 337 * time base figures. 338 * 339 * 'first' is the earliest/delay time, and 'second' is the latest/deadline time. 340 */ 341 private Pair<Long, Long> mPersistedUtcTimes; 342 343 /** 344 * For use only by ContentObserverController: state it is maintaining about content URIs 345 * being observed. 346 */ 347 ContentObserverController.JobInstance contentObserverJobInstance; 348 349 private long mTotalNetworkDownloadBytes = JobInfo.NETWORK_BYTES_UNKNOWN; 350 private long mTotalNetworkUploadBytes = JobInfo.NETWORK_BYTES_UNKNOWN; 351 352 /////// Booleans that track if a job is ready to run. They should be updated whenever dependent 353 /////// states change. 354 355 /** 356 * The deadline for the job has passed. This is only good for non-periodic jobs. A periodic job 357 * should only run if its constraints are satisfied. 358 * Computed as: NOT periodic AND has deadline constraint AND deadline constraint satisfied. 359 */ 360 private boolean mReadyDeadlineSatisfied; 361 362 /** 363 * The device isn't Dozing or this job will be in the foreground. This implicit constraint must 364 * be satisfied. 365 */ 366 private boolean mReadyNotDozing; 367 368 /** 369 * The job is not restricted from running in the background (due to Battery Saver). This 370 * implicit constraint must be satisfied. 371 */ 372 private boolean mReadyNotRestrictedInBg; 373 374 /** The job is within its quota based on its standby bucket. */ 375 private boolean mReadyWithinQuota; 376 377 /** The job's dynamic requirements have been satisfied. */ 378 private boolean mReadyDynamicSatisfied; 379 380 /** Provide a handle to the service that this job will be run on. */ getServiceToken()381 public int getServiceToken() { 382 return callingUid; 383 } 384 385 /** 386 * Core constructor for JobStatus instances. All other ctors funnel down to this one. 387 * 388 * @param job The actual requested parameters for the job 389 * @param callingUid Identity of the app that is scheduling the job. This may not be the 390 * app in which the job is implemented; such as with sync jobs. 391 * @param sourcePackageName The package name of the app in which the job will run. 392 * @param sourceUserId The user in which the job will run 393 * @param standbyBucket The standby bucket that the source package is currently assigned to, 394 * cached here for speed of handling during runnability evaluations (and updated when bucket 395 * assignments are changed) 396 * @param tag A string associated with the job for debugging/logging purposes. 397 * @param numFailures Count of how many times this job has requested a reschedule because 398 * its work was not yet finished. 399 * @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job 400 * is to be considered runnable 401 * @param latestRunTimeElapsedMillis Milestone: point in time at which the job will be 402 * considered overdue 403 * @param lastSuccessfulRunTime When did we last run this job to completion? 404 * @param lastFailedRunTime When did we last run this job only to have it stop incomplete? 405 * @param internalFlags Non-API property flags about this job 406 */ JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, int standbyBucket, String tag, int numFailures, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags)407 private JobStatus(JobInfo job, int callingUid, String sourcePackageName, 408 int sourceUserId, int standbyBucket, String tag, int numFailures, 409 long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, 410 long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) { 411 this.job = job; 412 this.callingUid = callingUid; 413 this.standbyBucket = standbyBucket; 414 415 int tempSourceUid = -1; 416 if (sourceUserId != -1 && sourcePackageName != null) { 417 try { 418 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0, 419 sourceUserId); 420 } catch (RemoteException ex) { 421 // Can't happen, PackageManager runs in the same process. 422 } 423 } 424 if (tempSourceUid == -1) { 425 this.sourceUid = callingUid; 426 this.sourceUserId = UserHandle.getUserId(callingUid); 427 this.sourcePackageName = job.getService().getPackageName(); 428 this.sourceTag = null; 429 } else { 430 this.sourceUid = tempSourceUid; 431 this.sourceUserId = sourceUserId; 432 this.sourcePackageName = sourcePackageName; 433 this.sourceTag = tag; 434 } 435 436 this.batteryName = this.sourceTag != null 437 ? this.sourceTag + ":" + job.getService().getPackageName() 438 : job.getService().flattenToShortString(); 439 this.tag = "*job*/" + this.batteryName; 440 441 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis; 442 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis; 443 this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis; 444 this.numFailures = numFailures; 445 446 boolean requiresNetwork = false; 447 int requiredConstraints = job.getConstraintFlags(); 448 if (job.getRequiredNetwork() != null) { 449 requiredConstraints |= CONSTRAINT_CONNECTIVITY; 450 requiresNetwork = true; 451 } 452 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) { 453 requiredConstraints |= CONSTRAINT_TIMING_DELAY; 454 } 455 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { 456 requiredConstraints |= CONSTRAINT_DEADLINE; 457 } 458 boolean exemptedMediaUrisOnly = false; 459 if (job.getTriggerContentUris() != null) { 460 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER; 461 exemptedMediaUrisOnly = true; 462 for (JobInfo.TriggerContentUri uri : job.getTriggerContentUris()) { 463 if (!ArrayUtils.contains(MEDIA_URIS_FOR_STANDBY_EXEMPTION, uri.getUri())) { 464 exemptedMediaUrisOnly = false; 465 break; 466 } 467 } 468 } 469 this.requiredConstraints = requiredConstraints; 470 mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST; 471 mReadyNotDozing = (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; 472 if (standbyBucket == RESTRICTED_INDEX) { 473 addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); 474 } else { 475 mReadyDynamicSatisfied = false; 476 } 477 478 mLastSuccessfulRunTime = lastSuccessfulRunTime; 479 mLastFailedRunTime = lastFailedRunTime; 480 481 mInternalFlags = internalFlags; 482 483 updateEstimatedNetworkBytesLocked(); 484 485 if (job.getRequiredNetwork() != null) { 486 // Later, when we check if a given network satisfies the required 487 // network, we need to know the UID that is requesting it, so push 488 // our source UID into place. 489 job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid); 490 } 491 final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class); 492 mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly 493 && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); 494 } 495 496 /** Copy constructor: used specifically when cloning JobStatus objects for persistence, 497 * so we preserve RTC window bounds if the source object has them. */ JobStatus(JobStatus jobStatus)498 public JobStatus(JobStatus jobStatus) { 499 this(jobStatus.getJob(), jobStatus.getUid(), 500 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), 501 jobStatus.getStandbyBucket(), 502 jobStatus.getSourceTag(), jobStatus.getNumFailures(), 503 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), 504 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(), 505 jobStatus.getInternalFlags()); 506 mPersistedUtcTimes = jobStatus.mPersistedUtcTimes; 507 if (jobStatus.mPersistedUtcTimes != null) { 508 if (DEBUG) { 509 Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here")); 510 } 511 } 512 } 513 514 /** 515 * Create a new JobStatus that was loaded from disk. We ignore the provided 516 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job 517 * from the {@link com.android.server.job.JobStore} and still want to respect its 518 * wallclock runtime rather than resetting it on every boot. 519 * We consider a freshly loaded job to no longer be in back-off, and the associated 520 * standby bucket is whatever the OS thinks it should be at this moment. 521 */ JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId, int standbyBucket, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, Pair<Long, Long> persistedExecutionTimesUTC, int innerFlags)522 public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId, 523 int standbyBucket, String sourceTag, 524 long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, 525 long lastSuccessfulRunTime, long lastFailedRunTime, 526 Pair<Long, Long> persistedExecutionTimesUTC, 527 int innerFlags) { 528 this(job, callingUid, sourcePkgName, sourceUserId, 529 standbyBucket, 530 sourceTag, 0, 531 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 532 lastSuccessfulRunTime, lastFailedRunTime, innerFlags); 533 534 // Only during initial inflation do we record the UTC-timebase execution bounds 535 // read from the persistent store. If we ever have to recreate the JobStatus on 536 // the fly, it means we're rescheduling the job; and this means that the calculated 537 // elapsed timebase bounds intrinsically become correct. 538 this.mPersistedUtcTimes = persistedExecutionTimesUTC; 539 if (persistedExecutionTimesUTC != null) { 540 if (DEBUG) { 541 Slog.i(TAG, "+ restored job with RTC times because of bad boot clock"); 542 } 543 } 544 } 545 546 /** Create a new job to be rescheduled with the provided parameters. */ JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, long newLatestRuntimeElapsedMillis, int backoffAttempt, long lastSuccessfulRunTime, long lastFailedRunTime)547 public JobStatus(JobStatus rescheduling, 548 long newEarliestRuntimeElapsedMillis, 549 long newLatestRuntimeElapsedMillis, int backoffAttempt, 550 long lastSuccessfulRunTime, long lastFailedRunTime) { 551 this(rescheduling.job, rescheduling.getUid(), 552 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), 553 rescheduling.getStandbyBucket(), 554 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis, 555 newLatestRuntimeElapsedMillis, 556 lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags()); 557 } 558 559 /** 560 * Create a newly scheduled job. 561 * @param callingUid Uid of the package that scheduled this job. 562 * @param sourcePkg Package name of the app that will actually run the job. Null indicates 563 * that the calling package is the source. 564 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the 565 * caller. 566 */ createFromJobInfo(JobInfo job, int callingUid, String sourcePkg, int sourceUserId, String tag)567 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePkg, 568 int sourceUserId, String tag) { 569 final long elapsedNow = sElapsedRealtimeClock.millis(); 570 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis; 571 if (job.isPeriodic()) { 572 // Make sure period is in the interval [min_possible_period, max_possible_period]. 573 final long period = Math.max(JobInfo.getMinPeriodMillis(), 574 Math.min(JobSchedulerService.MAX_ALLOWED_PERIOD_MS, job.getIntervalMillis())); 575 latestRunTimeElapsedMillis = elapsedNow + period; 576 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis 577 // Make sure flex is in the interval [min_possible_flex, period]. 578 - Math.max(JobInfo.getMinFlexMillis(), Math.min(period, job.getFlexMillis())); 579 } else { 580 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ? 581 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME; 582 latestRunTimeElapsedMillis = job.hasLateConstraint() ? 583 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME; 584 } 585 String jobPackage = (sourcePkg != null) ? sourcePkg : job.getService().getPackageName(); 586 587 int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage, 588 sourceUserId, elapsedNow); 589 return new JobStatus(job, callingUid, sourcePkg, sourceUserId, 590 standbyBucket, tag, 0, 591 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 592 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, 593 /*innerFlags=*/ 0); 594 } 595 enqueueWorkLocked(JobWorkItem work)596 public void enqueueWorkLocked(JobWorkItem work) { 597 if (pendingWork == null) { 598 pendingWork = new ArrayList<>(); 599 } 600 work.setWorkId(nextPendingWorkId); 601 nextPendingWorkId++; 602 if (work.getIntent() != null 603 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) { 604 work.setGrants(GrantedUriPermissions.createFromIntent(work.getIntent(), sourceUid, 605 sourcePackageName, sourceUserId, toShortString())); 606 } 607 pendingWork.add(work); 608 updateEstimatedNetworkBytesLocked(); 609 } 610 dequeueWorkLocked()611 public JobWorkItem dequeueWorkLocked() { 612 if (pendingWork != null && pendingWork.size() > 0) { 613 JobWorkItem work = pendingWork.remove(0); 614 if (work != null) { 615 if (executingWork == null) { 616 executingWork = new ArrayList<>(); 617 } 618 executingWork.add(work); 619 work.bumpDeliveryCount(); 620 } 621 updateEstimatedNetworkBytesLocked(); 622 return work; 623 } 624 return null; 625 } 626 hasWorkLocked()627 public boolean hasWorkLocked() { 628 return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked(); 629 } 630 hasExecutingWorkLocked()631 public boolean hasExecutingWorkLocked() { 632 return executingWork != null && executingWork.size() > 0; 633 } 634 ungrantWorkItem(JobWorkItem work)635 private static void ungrantWorkItem(JobWorkItem work) { 636 if (work.getGrants() != null) { 637 ((GrantedUriPermissions)work.getGrants()).revoke(); 638 } 639 } 640 completeWorkLocked(int workId)641 public boolean completeWorkLocked(int workId) { 642 if (executingWork != null) { 643 final int N = executingWork.size(); 644 for (int i = 0; i < N; i++) { 645 JobWorkItem work = executingWork.get(i); 646 if (work.getWorkId() == workId) { 647 executingWork.remove(i); 648 ungrantWorkItem(work); 649 return true; 650 } 651 } 652 } 653 return false; 654 } 655 ungrantWorkList(ArrayList<JobWorkItem> list)656 private static void ungrantWorkList(ArrayList<JobWorkItem> list) { 657 if (list != null) { 658 final int N = list.size(); 659 for (int i = 0; i < N; i++) { 660 ungrantWorkItem(list.get(i)); 661 } 662 } 663 } 664 stopTrackingJobLocked(JobStatus incomingJob)665 public void stopTrackingJobLocked(JobStatus incomingJob) { 666 if (incomingJob != null) { 667 // We are replacing with a new job -- transfer the work! We do any executing 668 // work first, since that was originally at the front of the pending work. 669 if (executingWork != null && executingWork.size() > 0) { 670 incomingJob.pendingWork = executingWork; 671 } 672 if (incomingJob.pendingWork == null) { 673 incomingJob.pendingWork = pendingWork; 674 } else if (pendingWork != null && pendingWork.size() > 0) { 675 incomingJob.pendingWork.addAll(pendingWork); 676 } 677 pendingWork = null; 678 executingWork = null; 679 incomingJob.nextPendingWorkId = nextPendingWorkId; 680 incomingJob.updateEstimatedNetworkBytesLocked(); 681 } else { 682 // We are completely stopping the job... need to clean up work. 683 ungrantWorkList(pendingWork); 684 pendingWork = null; 685 ungrantWorkList(executingWork); 686 executingWork = null; 687 } 688 updateEstimatedNetworkBytesLocked(); 689 } 690 prepareLocked()691 public void prepareLocked() { 692 if (prepared) { 693 Slog.wtf(TAG, "Already prepared: " + this); 694 return; 695 } 696 prepared = true; 697 if (DEBUG_PREPARE) { 698 unpreparedPoint = null; 699 } 700 final ClipData clip = job.getClipData(); 701 if (clip != null) { 702 uriPerms = GrantedUriPermissions.createFromClip(clip, sourceUid, sourcePackageName, 703 sourceUserId, job.getClipGrantFlags(), toShortString()); 704 } 705 } 706 unprepareLocked()707 public void unprepareLocked() { 708 if (!prepared) { 709 Slog.wtf(TAG, "Hasn't been prepared: " + this); 710 if (DEBUG_PREPARE && unpreparedPoint != null) { 711 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint); 712 } 713 return; 714 } 715 prepared = false; 716 if (DEBUG_PREPARE) { 717 unpreparedPoint = new Throwable().fillInStackTrace(); 718 } 719 if (uriPerms != null) { 720 uriPerms.revoke(); 721 uriPerms = null; 722 } 723 } 724 isPreparedLocked()725 public boolean isPreparedLocked() { 726 return prepared; 727 } 728 getJob()729 public JobInfo getJob() { 730 return job; 731 } 732 getJobId()733 public int getJobId() { 734 return job.getId(); 735 } 736 printUniqueId(PrintWriter pw)737 public void printUniqueId(PrintWriter pw) { 738 UserHandle.formatUid(pw, callingUid); 739 pw.print("/"); 740 pw.print(job.getId()); 741 } 742 getNumFailures()743 public int getNumFailures() { 744 return numFailures; 745 } 746 getServiceComponent()747 public ComponentName getServiceComponent() { 748 return job.getService(); 749 } 750 getSourcePackageName()751 public String getSourcePackageName() { 752 return sourcePackageName; 753 } 754 getSourceUid()755 public int getSourceUid() { 756 return sourceUid; 757 } 758 getSourceUserId()759 public int getSourceUserId() { 760 return sourceUserId; 761 } 762 getUserId()763 public int getUserId() { 764 return UserHandle.getUserId(callingUid); 765 } 766 767 /** 768 * Returns an appropriate standby bucket for the job, taking into account any standby 769 * exemptions. 770 */ getEffectiveStandbyBucket()771 public int getEffectiveStandbyBucket() { 772 if (uidActive || getJob().isExemptedFromAppStandby()) { 773 // Treat these cases as if they're in the ACTIVE bucket so that they get throttled 774 // like other ACTIVE apps. 775 return ACTIVE_INDEX; 776 } 777 final int actualBucket = getStandbyBucket(); 778 if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX 779 && mHasMediaBackupExemption) { 780 // Cap it at WORKING_INDEX as media back up jobs are important to the user, and the 781 // source package may not have been used directly in a while. 782 return Math.min(WORKING_INDEX, actualBucket); 783 } 784 return actualBucket; 785 } 786 787 /** Returns the real standby bucket of the job. */ getStandbyBucket()788 public int getStandbyBucket() { 789 return standbyBucket; 790 } 791 setStandbyBucket(int newBucket)792 public void setStandbyBucket(int newBucket) { 793 if (newBucket == RESTRICTED_INDEX) { 794 // Adding to the bucket. 795 addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); 796 } else if (standbyBucket == RESTRICTED_INDEX) { 797 // Removing from the RESTRICTED bucket. 798 removeDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); 799 } 800 801 standbyBucket = newBucket; 802 } 803 804 // Called only by the standby monitoring code getWhenStandbyDeferred()805 public long getWhenStandbyDeferred() { 806 return whenStandbyDeferred; 807 } 808 809 // Called only by the standby monitoring code setWhenStandbyDeferred(long now)810 public void setWhenStandbyDeferred(long now) { 811 whenStandbyDeferred = now; 812 } 813 814 /** 815 * Returns the first time this job was force batched, in the elapsed realtime timebase. Will be 816 * 0 if this job was never force batched. 817 */ getFirstForceBatchedTimeElapsed()818 public long getFirstForceBatchedTimeElapsed() { 819 return mFirstForceBatchedTimeElapsed; 820 } 821 setFirstForceBatchedTimeElapsed(long now)822 public void setFirstForceBatchedTimeElapsed(long now) { 823 mFirstForceBatchedTimeElapsed = now; 824 } 825 getSourceTag()826 public String getSourceTag() { 827 return sourceTag; 828 } 829 getUid()830 public int getUid() { 831 return callingUid; 832 } 833 getBatteryName()834 public String getBatteryName() { 835 return batteryName; 836 } 837 getTag()838 public String getTag() { 839 return tag; 840 } 841 getPriority()842 public int getPriority() { 843 return job.getPriority(); 844 } 845 getFlags()846 public int getFlags() { 847 return job.getFlags(); 848 } 849 getInternalFlags()850 public int getInternalFlags() { 851 return mInternalFlags; 852 } 853 addInternalFlags(int flags)854 public void addInternalFlags(int flags) { 855 mInternalFlags |= flags; 856 } 857 getSatisfiedConstraintFlags()858 public int getSatisfiedConstraintFlags() { 859 return satisfiedConstraints; 860 } 861 maybeAddForegroundExemption(Predicate<Integer> uidForegroundChecker)862 public void maybeAddForegroundExemption(Predicate<Integer> uidForegroundChecker) { 863 // Jobs with time constraints shouldn't be exempted. 864 if (job.hasEarlyConstraint() || job.hasLateConstraint()) { 865 return; 866 } 867 // Already exempted, skip the foreground check. 868 if ((mInternalFlags & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) { 869 return; 870 } 871 if (uidForegroundChecker.test(getSourceUid())) { 872 addInternalFlags(INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION); 873 } 874 } 875 updateEstimatedNetworkBytesLocked()876 private void updateEstimatedNetworkBytesLocked() { 877 mTotalNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes(); 878 mTotalNetworkUploadBytes = job.getEstimatedNetworkUploadBytes(); 879 880 if (pendingWork != null) { 881 for (int i = 0; i < pendingWork.size(); i++) { 882 if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 883 // If any component of the job has unknown usage, we don't have a 884 // complete picture of what data will be used, and we have to treat the 885 // entire up/download as unknown. 886 long downloadBytes = pendingWork.get(i).getEstimatedNetworkDownloadBytes(); 887 if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 888 mTotalNetworkDownloadBytes += downloadBytes; 889 } 890 } 891 if (mTotalNetworkUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 892 // If any component of the job has unknown usage, we don't have a 893 // complete picture of what data will be used, and we have to treat the 894 // entire up/download as unknown. 895 long uploadBytes = pendingWork.get(i).getEstimatedNetworkUploadBytes(); 896 if (uploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 897 mTotalNetworkUploadBytes += uploadBytes; 898 } 899 } 900 } 901 } 902 } 903 getEstimatedNetworkDownloadBytes()904 public long getEstimatedNetworkDownloadBytes() { 905 return mTotalNetworkDownloadBytes; 906 } 907 getEstimatedNetworkUploadBytes()908 public long getEstimatedNetworkUploadBytes() { 909 return mTotalNetworkUploadBytes; 910 } 911 912 /** Does this job have any sort of networking constraint? */ hasConnectivityConstraint()913 public boolean hasConnectivityConstraint() { 914 // No need to check mDynamicConstraints since connectivity will only be in that list if 915 // it's already in the requiredConstraints list. 916 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0; 917 } 918 hasChargingConstraint()919 public boolean hasChargingConstraint() { 920 return hasConstraint(CONSTRAINT_CHARGING); 921 } 922 hasBatteryNotLowConstraint()923 public boolean hasBatteryNotLowConstraint() { 924 return hasConstraint(CONSTRAINT_BATTERY_NOT_LOW); 925 } 926 927 /** Returns true if the job requires charging OR battery not low. */ hasPowerConstraint()928 boolean hasPowerConstraint() { 929 return hasConstraint(CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW); 930 } 931 hasStorageNotLowConstraint()932 public boolean hasStorageNotLowConstraint() { 933 return hasConstraint(CONSTRAINT_STORAGE_NOT_LOW); 934 } 935 hasTimingDelayConstraint()936 public boolean hasTimingDelayConstraint() { 937 return hasConstraint(CONSTRAINT_TIMING_DELAY); 938 } 939 hasDeadlineConstraint()940 public boolean hasDeadlineConstraint() { 941 return hasConstraint(CONSTRAINT_DEADLINE); 942 } 943 hasIdleConstraint()944 public boolean hasIdleConstraint() { 945 return hasConstraint(CONSTRAINT_IDLE); 946 } 947 hasContentTriggerConstraint()948 public boolean hasContentTriggerConstraint() { 949 // No need to check mDynamicConstraints since content trigger will only be in that list if 950 // it's already in the requiredConstraints list. 951 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0; 952 } 953 954 /** 955 * Checks both {@link #requiredConstraints} and {@link #mDynamicConstraints} to see if this job 956 * requires the specified constraint. 957 */ hasConstraint(int constraint)958 private boolean hasConstraint(int constraint) { 959 return (requiredConstraints & constraint) != 0 || (mDynamicConstraints & constraint) != 0; 960 } 961 getTriggerContentUpdateDelay()962 public long getTriggerContentUpdateDelay() { 963 long time = job.getTriggerContentUpdateDelay(); 964 if (time < 0) { 965 return DEFAULT_TRIGGER_UPDATE_DELAY; 966 } 967 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY); 968 } 969 getTriggerContentMaxDelay()970 public long getTriggerContentMaxDelay() { 971 long time = job.getTriggerContentMaxDelay(); 972 if (time < 0) { 973 return DEFAULT_TRIGGER_MAX_DELAY; 974 } 975 return Math.max(time, MIN_TRIGGER_MAX_DELAY); 976 } 977 isPersisted()978 public boolean isPersisted() { 979 return job.isPersisted(); 980 } 981 getEarliestRunTime()982 public long getEarliestRunTime() { 983 return earliestRunTimeElapsedMillis; 984 } 985 getLatestRunTimeElapsed()986 public long getLatestRunTimeElapsed() { 987 return latestRunTimeElapsedMillis; 988 } 989 getOriginalLatestRunTimeElapsed()990 public long getOriginalLatestRunTimeElapsed() { 991 return mOriginalLatestRunTimeElapsedMillis; 992 } 993 setOriginalLatestRunTimeElapsed(long latestRunTimeElapsed)994 public void setOriginalLatestRunTimeElapsed(long latestRunTimeElapsed) { 995 mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsed; 996 } 997 998 /** 999 * Return the fractional position of "now" within the "run time" window of 1000 * this job. 1001 * <p> 1002 * For example, if the earliest run time was 10 minutes ago, and the latest 1003 * run time is 30 minutes from now, this would return 0.25. 1004 * <p> 1005 * If the job has no window defined, returns 1. When only an earliest or 1006 * latest time is defined, it's treated as an infinitely small window at 1007 * that time. 1008 */ getFractionRunTime()1009 public float getFractionRunTime() { 1010 final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); 1011 if (earliestRunTimeElapsedMillis == 0 && latestRunTimeElapsedMillis == Long.MAX_VALUE) { 1012 return 1; 1013 } else if (earliestRunTimeElapsedMillis == 0) { 1014 return now >= latestRunTimeElapsedMillis ? 1 : 0; 1015 } else if (latestRunTimeElapsedMillis == Long.MAX_VALUE) { 1016 return now >= earliestRunTimeElapsedMillis ? 1 : 0; 1017 } else { 1018 if (now <= earliestRunTimeElapsedMillis) { 1019 return 0; 1020 } else if (now >= latestRunTimeElapsedMillis) { 1021 return 1; 1022 } else { 1023 return (float) (now - earliestRunTimeElapsedMillis) 1024 / (float) (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis); 1025 } 1026 } 1027 } 1028 getPersistedUtcTimes()1029 public Pair<Long, Long> getPersistedUtcTimes() { 1030 return mPersistedUtcTimes; 1031 } 1032 clearPersistedUtcTimes()1033 public void clearPersistedUtcTimes() { 1034 mPersistedUtcTimes = null; 1035 } 1036 1037 /** @return true if the constraint was changed, false otherwise. */ setChargingConstraintSatisfied(boolean state)1038 boolean setChargingConstraintSatisfied(boolean state) { 1039 return setConstraintSatisfied(CONSTRAINT_CHARGING, state); 1040 } 1041 1042 /** @return true if the constraint was changed, false otherwise. */ setBatteryNotLowConstraintSatisfied(boolean state)1043 boolean setBatteryNotLowConstraintSatisfied(boolean state) { 1044 return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state); 1045 } 1046 1047 /** @return true if the constraint was changed, false otherwise. */ setStorageNotLowConstraintSatisfied(boolean state)1048 boolean setStorageNotLowConstraintSatisfied(boolean state) { 1049 return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state); 1050 } 1051 1052 /** @return true if the constraint was changed, false otherwise. */ setTimingDelayConstraintSatisfied(boolean state)1053 boolean setTimingDelayConstraintSatisfied(boolean state) { 1054 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state); 1055 } 1056 1057 /** @return true if the constraint was changed, false otherwise. */ setDeadlineConstraintSatisfied(boolean state)1058 boolean setDeadlineConstraintSatisfied(boolean state) { 1059 if (setConstraintSatisfied(CONSTRAINT_DEADLINE, state)) { 1060 // The constraint was changed. Update the ready flag. 1061 mReadyDeadlineSatisfied = !job.isPeriodic() && hasDeadlineConstraint() && state; 1062 return true; 1063 } 1064 return false; 1065 } 1066 1067 /** @return true if the constraint was changed, false otherwise. */ setIdleConstraintSatisfied(boolean state)1068 boolean setIdleConstraintSatisfied(boolean state) { 1069 return setConstraintSatisfied(CONSTRAINT_IDLE, state); 1070 } 1071 1072 /** @return true if the constraint was changed, false otherwise. */ setConnectivityConstraintSatisfied(boolean state)1073 boolean setConnectivityConstraintSatisfied(boolean state) { 1074 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state); 1075 } 1076 1077 /** @return true if the constraint was changed, false otherwise. */ setContentTriggerConstraintSatisfied(boolean state)1078 boolean setContentTriggerConstraintSatisfied(boolean state) { 1079 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state); 1080 } 1081 1082 /** @return true if the constraint was changed, false otherwise. */ setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted)1083 boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) { 1084 dozeWhitelisted = whitelisted; 1085 if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state)) { 1086 // The constraint was changed. Update the ready flag. 1087 mReadyNotDozing = state || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; 1088 return true; 1089 } 1090 return false; 1091 } 1092 1093 /** @return true if the constraint was changed, false otherwise. */ setBackgroundNotRestrictedConstraintSatisfied(boolean state)1094 boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) { 1095 if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state)) { 1096 // The constraint was changed. Update the ready flag. 1097 mReadyNotRestrictedInBg = state; 1098 return true; 1099 } 1100 return false; 1101 } 1102 1103 /** @return true if the constraint was changed, false otherwise. */ setQuotaConstraintSatisfied(boolean state)1104 boolean setQuotaConstraintSatisfied(boolean state) { 1105 if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, state)) { 1106 // The constraint was changed. Update the ready flag. 1107 mReadyWithinQuota = state; 1108 return true; 1109 } 1110 return false; 1111 } 1112 1113 /** @return true if the state was changed, false otherwise. */ setUidActive(final boolean newActiveState)1114 boolean setUidActive(final boolean newActiveState) { 1115 if (newActiveState != uidActive) { 1116 uidActive = newActiveState; 1117 return true; 1118 } 1119 return false; /* unchanged */ 1120 } 1121 1122 /** @return true if the constraint was changed, false otherwise. */ setConstraintSatisfied(int constraint, boolean state)1123 boolean setConstraintSatisfied(int constraint, boolean state) { 1124 boolean old = (satisfiedConstraints&constraint) != 0; 1125 if (old == state) { 1126 return false; 1127 } 1128 if (DEBUG) { 1129 Slog.v(TAG, 1130 "Constraint " + constraint + " is " + (!state ? "NOT " : "") + "satisfied for " 1131 + toShortString()); 1132 } 1133 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0); 1134 mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST; 1135 mReadyDynamicSatisfied = mDynamicConstraints != 0 1136 && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints); 1137 if (STATS_LOG_ENABLED && (STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) { 1138 FrameworkStatsLog.write_non_chained( 1139 FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED, 1140 sourceUid, null, getBatteryName(), getProtoConstraint(constraint), 1141 state ? FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED 1142 : FrameworkStatsLog 1143 .SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED); 1144 } 1145 return true; 1146 } 1147 isConstraintSatisfied(int constraint)1148 boolean isConstraintSatisfied(int constraint) { 1149 return (satisfiedConstraints&constraint) != 0; 1150 } 1151 clearTrackingController(int which)1152 boolean clearTrackingController(int which) { 1153 if ((trackingControllers&which) != 0) { 1154 trackingControllers &= ~which; 1155 return true; 1156 } 1157 return false; 1158 } 1159 setTrackingController(int which)1160 void setTrackingController(int which) { 1161 trackingControllers |= which; 1162 } 1163 1164 /** 1165 * Indicates that this job cannot run without the specified constraints. This is evaluated 1166 * separately from the job's explicitly requested constraints and MUST be satisfied before 1167 * the job can run if the app doesn't have quota. 1168 */ addDynamicConstraints(int constraints)1169 private void addDynamicConstraints(int constraints) { 1170 if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) { 1171 // Quota should never be used as a dynamic constraint. 1172 Slog.wtf(TAG, "Tried to set quota as a dynamic constraint"); 1173 constraints &= ~CONSTRAINT_WITHIN_QUOTA; 1174 } 1175 1176 // Connectivity and content trigger are special since they're only valid to add if the 1177 // job has requested network or specific content URIs. Adding these constraints to jobs 1178 // that don't need them doesn't make sense. 1179 if (!hasConnectivityConstraint()) { 1180 constraints &= ~CONSTRAINT_CONNECTIVITY; 1181 } 1182 if (!hasContentTriggerConstraint()) { 1183 constraints &= ~CONSTRAINT_CONTENT_TRIGGER; 1184 } 1185 1186 mDynamicConstraints |= constraints; 1187 mReadyDynamicSatisfied = mDynamicConstraints != 0 1188 && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints); 1189 } 1190 1191 /** 1192 * Removes dynamic constraints from a job, meaning that the requirements are not required for 1193 * the job to run (if the job itself hasn't requested the constraint. This is separate from 1194 * the job's explicitly requested constraints and does not remove those requested constraints. 1195 * 1196 */ removeDynamicConstraints(int constraints)1197 private void removeDynamicConstraints(int constraints) { 1198 mDynamicConstraints &= ~constraints; 1199 mReadyDynamicSatisfied = mDynamicConstraints != 0 1200 && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints); 1201 } 1202 getLastSuccessfulRunTime()1203 public long getLastSuccessfulRunTime() { 1204 return mLastSuccessfulRunTime; 1205 } 1206 getLastFailedRunTime()1207 public long getLastFailedRunTime() { 1208 return mLastFailedRunTime; 1209 } 1210 1211 /** 1212 * @return Whether or not this job is ready to run, based on its requirements. 1213 */ isReady()1214 public boolean isReady() { 1215 return isReady(mSatisfiedConstraintsOfInterest); 1216 } 1217 1218 /** 1219 * @return Whether or not this job would be ready to run if it had the specified constraint 1220 * granted, based on its requirements. 1221 */ wouldBeReadyWithConstraint(int constraint)1222 boolean wouldBeReadyWithConstraint(int constraint) { 1223 boolean oldValue = false; 1224 int satisfied = mSatisfiedConstraintsOfInterest; 1225 switch (constraint) { 1226 case CONSTRAINT_BACKGROUND_NOT_RESTRICTED: 1227 oldValue = mReadyNotRestrictedInBg; 1228 mReadyNotRestrictedInBg = true; 1229 break; 1230 case CONSTRAINT_DEADLINE: 1231 oldValue = mReadyDeadlineSatisfied; 1232 mReadyDeadlineSatisfied = true; 1233 break; 1234 case CONSTRAINT_DEVICE_NOT_DOZING: 1235 oldValue = mReadyNotDozing; 1236 mReadyNotDozing = true; 1237 break; 1238 case CONSTRAINT_WITHIN_QUOTA: 1239 oldValue = mReadyWithinQuota; 1240 mReadyWithinQuota = true; 1241 break; 1242 default: 1243 satisfied |= constraint; 1244 mReadyDynamicSatisfied = mDynamicConstraints != 0 1245 && mDynamicConstraints == (satisfied & mDynamicConstraints); 1246 break; 1247 } 1248 1249 boolean toReturn = isReady(satisfied); 1250 1251 switch (constraint) { 1252 case CONSTRAINT_BACKGROUND_NOT_RESTRICTED: 1253 mReadyNotRestrictedInBg = oldValue; 1254 break; 1255 case CONSTRAINT_DEADLINE: 1256 mReadyDeadlineSatisfied = oldValue; 1257 break; 1258 case CONSTRAINT_DEVICE_NOT_DOZING: 1259 mReadyNotDozing = oldValue; 1260 break; 1261 case CONSTRAINT_WITHIN_QUOTA: 1262 mReadyWithinQuota = oldValue; 1263 break; 1264 default: 1265 mReadyDynamicSatisfied = mDynamicConstraints != 0 1266 && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints); 1267 break; 1268 } 1269 return toReturn; 1270 } 1271 isReady(int satisfiedConstraints)1272 private boolean isReady(int satisfiedConstraints) { 1273 // Quota and dynamic constraints trump all other constraints. 1274 // NEVER jobs are not supposed to run at all. Since we're using quota to allow parole 1275 // sessions (exempt from dynamic restrictions), we need the additional check to ensure 1276 // that NEVER jobs don't run. 1277 // TODO: cleanup quota and standby bucket management so we don't need the additional checks 1278 if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) 1279 || getEffectiveStandbyBucket() == NEVER_INDEX) { 1280 return false; 1281 } 1282 // Deadline constraint trumps other constraints besides quota and dynamic (except for 1283 // periodic jobs where deadline is an implementation detail. A periodic job should only 1284 // run if its constraints are satisfied). 1285 // DeviceNotDozing implicit constraint must be satisfied 1286 // NotRestrictedInBackground implicit constraint must be satisfied 1287 return mReadyNotDozing && mReadyNotRestrictedInBg && (mReadyDeadlineSatisfied 1288 || isConstraintsSatisfied(satisfiedConstraints)); 1289 } 1290 1291 /** All constraints besides implicit and deadline. */ 1292 static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW 1293 | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_CONNECTIVITY 1294 | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER; 1295 1296 // Soft override covers all non-"functional" constraints 1297 static final int SOFT_OVERRIDE_CONSTRAINTS = 1298 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW 1299 | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE; 1300 1301 /** Returns true whenever all dynamically set constraints are satisfied. */ areDynamicConstraintsSatisfied()1302 public boolean areDynamicConstraintsSatisfied() { 1303 return mReadyDynamicSatisfied; 1304 } 1305 1306 /** 1307 * @return Whether the constraints set on this job are satisfied. 1308 */ isConstraintsSatisfied()1309 public boolean isConstraintsSatisfied() { 1310 return isConstraintsSatisfied(mSatisfiedConstraintsOfInterest); 1311 } 1312 isConstraintsSatisfied(int satisfiedConstraints)1313 private boolean isConstraintsSatisfied(int satisfiedConstraints) { 1314 if (overrideState == OVERRIDE_FULL) { 1315 // force override: the job is always runnable 1316 return true; 1317 } 1318 1319 int sat = satisfiedConstraints; 1320 if (overrideState == OVERRIDE_SOFT) { 1321 // override: pretend all 'soft' requirements are satisfied 1322 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS); 1323 } 1324 1325 return (sat & mRequiredConstraintsOfInterest) == mRequiredConstraintsOfInterest; 1326 } 1327 matches(int uid, int jobId)1328 public boolean matches(int uid, int jobId) { 1329 return this.job.getId() == jobId && this.callingUid == uid; 1330 } 1331 1332 @Override toString()1333 public String toString() { 1334 StringBuilder sb = new StringBuilder(128); 1335 sb.append("JobStatus{"); 1336 sb.append(Integer.toHexString(System.identityHashCode(this))); 1337 sb.append(" #"); 1338 UserHandle.formatUid(sb, callingUid); 1339 sb.append("/"); 1340 sb.append(job.getId()); 1341 sb.append(' '); 1342 sb.append(batteryName); 1343 sb.append(" u="); 1344 sb.append(getUserId()); 1345 sb.append(" s="); 1346 sb.append(getSourceUid()); 1347 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME 1348 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { 1349 long now = sElapsedRealtimeClock.millis(); 1350 sb.append(" TIME="); 1351 formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now); 1352 sb.append(":"); 1353 formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now); 1354 } 1355 if (job.getRequiredNetwork() != null) { 1356 sb.append(" NET"); 1357 } 1358 if (job.isRequireCharging()) { 1359 sb.append(" CHARGING"); 1360 } 1361 if (job.isRequireBatteryNotLow()) { 1362 sb.append(" BATNOTLOW"); 1363 } 1364 if (job.isRequireStorageNotLow()) { 1365 sb.append(" STORENOTLOW"); 1366 } 1367 if (job.isRequireDeviceIdle()) { 1368 sb.append(" IDLE"); 1369 } 1370 if (job.isPeriodic()) { 1371 sb.append(" PERIODIC"); 1372 } 1373 if (job.isPersisted()) { 1374 sb.append(" PERSISTED"); 1375 } 1376 if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) { 1377 sb.append(" WAIT:DEV_NOT_DOZING"); 1378 } 1379 if (job.getTriggerContentUris() != null) { 1380 sb.append(" URIS="); 1381 sb.append(Arrays.toString(job.getTriggerContentUris())); 1382 } 1383 if (numFailures != 0) { 1384 sb.append(" failures="); 1385 sb.append(numFailures); 1386 } 1387 if (isReady()) { 1388 sb.append(" READY"); 1389 } 1390 sb.append("}"); 1391 return sb.toString(); 1392 } 1393 formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now)1394 private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) { 1395 if (runtime == defaultValue) { 1396 pw.print("none"); 1397 } else { 1398 TimeUtils.formatDuration(runtime - now, pw); 1399 } 1400 } 1401 formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now)1402 private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) { 1403 if (runtime == defaultValue) { 1404 sb.append("none"); 1405 } else { 1406 TimeUtils.formatDuration(runtime - now, sb); 1407 } 1408 } 1409 1410 /** 1411 * Convenience function to identify a job uniquely without pulling all the data that 1412 * {@link #toString()} returns. 1413 */ toShortString()1414 public String toShortString() { 1415 StringBuilder sb = new StringBuilder(); 1416 sb.append(Integer.toHexString(System.identityHashCode(this))); 1417 sb.append(" #"); 1418 UserHandle.formatUid(sb, callingUid); 1419 sb.append("/"); 1420 sb.append(job.getId()); 1421 sb.append(' '); 1422 sb.append(batteryName); 1423 return sb.toString(); 1424 } 1425 1426 /** 1427 * Convenience function to identify a job uniquely without pulling all the data that 1428 * {@link #toString()} returns. 1429 */ toShortStringExceptUniqueId()1430 public String toShortStringExceptUniqueId() { 1431 StringBuilder sb = new StringBuilder(); 1432 sb.append(Integer.toHexString(System.identityHashCode(this))); 1433 sb.append(' '); 1434 sb.append(batteryName); 1435 return sb.toString(); 1436 } 1437 1438 /** 1439 * Convenience function to dump data that identifies a job uniquely to proto. This is intended 1440 * to mimic {@link #toShortString}. 1441 */ writeToShortProto(ProtoOutputStream proto, long fieldId)1442 public void writeToShortProto(ProtoOutputStream proto, long fieldId) { 1443 final long token = proto.start(fieldId); 1444 1445 proto.write(JobStatusShortInfoProto.CALLING_UID, callingUid); 1446 proto.write(JobStatusShortInfoProto.JOB_ID, job.getId()); 1447 proto.write(JobStatusShortInfoProto.BATTERY_NAME, batteryName); 1448 1449 proto.end(token); 1450 } 1451 dumpConstraints(PrintWriter pw, int constraints)1452 void dumpConstraints(PrintWriter pw, int constraints) { 1453 if ((constraints&CONSTRAINT_CHARGING) != 0) { 1454 pw.print(" CHARGING"); 1455 } 1456 if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) { 1457 pw.print(" BATTERY_NOT_LOW"); 1458 } 1459 if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) { 1460 pw.print(" STORAGE_NOT_LOW"); 1461 } 1462 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) { 1463 pw.print(" TIMING_DELAY"); 1464 } 1465 if ((constraints&CONSTRAINT_DEADLINE) != 0) { 1466 pw.print(" DEADLINE"); 1467 } 1468 if ((constraints&CONSTRAINT_IDLE) != 0) { 1469 pw.print(" IDLE"); 1470 } 1471 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) { 1472 pw.print(" CONNECTIVITY"); 1473 } 1474 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) { 1475 pw.print(" CONTENT_TRIGGER"); 1476 } 1477 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) { 1478 pw.print(" DEVICE_NOT_DOZING"); 1479 } 1480 if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) { 1481 pw.print(" BACKGROUND_NOT_RESTRICTED"); 1482 } 1483 if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) { 1484 pw.print(" WITHIN_QUOTA"); 1485 } 1486 if (constraints != 0) { 1487 pw.print(" [0x"); 1488 pw.print(Integer.toHexString(constraints)); 1489 pw.print("]"); 1490 } 1491 } 1492 1493 /** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */ getProtoConstraint(int constraint)1494 private int getProtoConstraint(int constraint) { 1495 switch (constraint) { 1496 case CONSTRAINT_BACKGROUND_NOT_RESTRICTED: 1497 return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED; 1498 case CONSTRAINT_BATTERY_NOT_LOW: 1499 return JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW; 1500 case CONSTRAINT_CHARGING: 1501 return JobServerProtoEnums.CONSTRAINT_CHARGING; 1502 case CONSTRAINT_CONNECTIVITY: 1503 return JobServerProtoEnums.CONSTRAINT_CONNECTIVITY; 1504 case CONSTRAINT_CONTENT_TRIGGER: 1505 return JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER; 1506 case CONSTRAINT_DEADLINE: 1507 return JobServerProtoEnums.CONSTRAINT_DEADLINE; 1508 case CONSTRAINT_DEVICE_NOT_DOZING: 1509 return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING; 1510 case CONSTRAINT_IDLE: 1511 return JobServerProtoEnums.CONSTRAINT_IDLE; 1512 case CONSTRAINT_STORAGE_NOT_LOW: 1513 return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW; 1514 case CONSTRAINT_TIMING_DELAY: 1515 return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY; 1516 case CONSTRAINT_WITHIN_QUOTA: 1517 return JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA; 1518 default: 1519 return JobServerProtoEnums.CONSTRAINT_UNKNOWN; 1520 } 1521 } 1522 1523 /** Writes constraints to the given repeating proto field. */ dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints)1524 void dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints) { 1525 if ((constraints & CONSTRAINT_CHARGING) != 0) { 1526 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CHARGING); 1527 } 1528 if ((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0) { 1529 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW); 1530 } 1531 if ((constraints & CONSTRAINT_STORAGE_NOT_LOW) != 0) { 1532 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW); 1533 } 1534 if ((constraints & CONSTRAINT_TIMING_DELAY) != 0) { 1535 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_TIMING_DELAY); 1536 } 1537 if ((constraints & CONSTRAINT_DEADLINE) != 0) { 1538 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEADLINE); 1539 } 1540 if ((constraints & CONSTRAINT_IDLE) != 0) { 1541 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_IDLE); 1542 } 1543 if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) { 1544 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONNECTIVITY); 1545 } 1546 if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) { 1547 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER); 1548 } 1549 if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) { 1550 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING); 1551 } 1552 if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) { 1553 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA); 1554 } 1555 if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) { 1556 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED); 1557 } 1558 } 1559 dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index)1560 private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) { 1561 pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #"); 1562 pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount()); 1563 pw.print("x "); pw.println(work.getIntent()); 1564 if (work.getGrants() != null) { 1565 pw.print(prefix); pw.println(" URI grants:"); 1566 ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " "); 1567 } 1568 } 1569 dumpJobWorkItem(ProtoOutputStream proto, long fieldId, JobWorkItem work)1570 private void dumpJobWorkItem(ProtoOutputStream proto, long fieldId, JobWorkItem work) { 1571 final long token = proto.start(fieldId); 1572 1573 proto.write(JobStatusDumpProto.JobWorkItem.WORK_ID, work.getWorkId()); 1574 proto.write(JobStatusDumpProto.JobWorkItem.DELIVERY_COUNT, work.getDeliveryCount()); 1575 if (work.getIntent() != null) { 1576 work.getIntent().dumpDebug(proto, JobStatusDumpProto.JobWorkItem.INTENT); 1577 } 1578 Object grants = work.getGrants(); 1579 if (grants != null) { 1580 ((GrantedUriPermissions) grants).dump(proto, JobStatusDumpProto.JobWorkItem.URI_GRANTS); 1581 } 1582 1583 proto.end(token); 1584 } 1585 1586 /** 1587 * Returns a bucket name based on the normalized bucket indices, not the AppStandby constants. 1588 */ getBucketName()1589 String getBucketName() { 1590 return bucketName(standbyBucket); 1591 } 1592 1593 /** 1594 * Returns a bucket name based on the normalized bucket indices, not the AppStandby constants. 1595 */ bucketName(int standbyBucket)1596 static String bucketName(int standbyBucket) { 1597 switch (standbyBucket) { 1598 case 0: return "ACTIVE"; 1599 case 1: return "WORKING_SET"; 1600 case 2: return "FREQUENT"; 1601 case 3: return "RARE"; 1602 case 4: return "NEVER"; 1603 case 5: 1604 return "RESTRICTED"; 1605 default: 1606 return "Unknown: " + standbyBucket; 1607 } 1608 } 1609 1610 // Dumpsys infrastructure dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis)1611 public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) { 1612 pw.print(prefix); UserHandle.formatUid(pw, callingUid); 1613 pw.print(" tag="); pw.println(tag); 1614 pw.print(prefix); 1615 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid()); 1616 pw.print(" user="); pw.print(getSourceUserId()); 1617 pw.print(" pkg="); pw.println(getSourcePackageName()); 1618 if (full) { 1619 pw.print(prefix); pw.println("JobInfo:"); 1620 pw.print(prefix); pw.print(" Service: "); 1621 pw.println(job.getService().flattenToShortString()); 1622 if (job.isPeriodic()) { 1623 pw.print(prefix); pw.print(" PERIODIC: interval="); 1624 TimeUtils.formatDuration(job.getIntervalMillis(), pw); 1625 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw); 1626 pw.println(); 1627 } 1628 if (job.isPersisted()) { 1629 pw.print(prefix); pw.println(" PERSISTED"); 1630 } 1631 if (job.getPriority() != 0) { 1632 pw.print(prefix); pw.print(" Priority: "); 1633 pw.println(JobInfo.getPriorityString(job.getPriority())); 1634 } 1635 if (job.getFlags() != 0) { 1636 pw.print(prefix); pw.print(" Flags: "); 1637 pw.println(Integer.toHexString(job.getFlags())); 1638 } 1639 if (getInternalFlags() != 0) { 1640 pw.print(prefix); pw.print(" Internal flags: "); 1641 pw.print(Integer.toHexString(getInternalFlags())); 1642 1643 if ((getInternalFlags()&INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) { 1644 pw.print(" HAS_FOREGROUND_EXEMPTION"); 1645 } 1646 pw.println(); 1647 } 1648 pw.print(prefix); pw.print(" Requires: charging="); 1649 pw.print(job.isRequireCharging()); pw.print(" batteryNotLow="); 1650 pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle="); 1651 pw.println(job.isRequireDeviceIdle()); 1652 if (job.getTriggerContentUris() != null) { 1653 pw.print(prefix); pw.println(" Trigger content URIs:"); 1654 for (int i = 0; i < job.getTriggerContentUris().length; i++) { 1655 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i]; 1656 pw.print(prefix); pw.print(" "); 1657 pw.print(Integer.toHexString(trig.getFlags())); 1658 pw.print(' '); pw.println(trig.getUri()); 1659 } 1660 if (job.getTriggerContentUpdateDelay() >= 0) { 1661 pw.print(prefix); pw.print(" Trigger update delay: "); 1662 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw); 1663 pw.println(); 1664 } 1665 if (job.getTriggerContentMaxDelay() >= 0) { 1666 pw.print(prefix); pw.print(" Trigger max delay: "); 1667 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw); 1668 pw.println(); 1669 } 1670 } 1671 if (job.getExtras() != null && !job.getExtras().isDefinitelyEmpty()) { 1672 pw.print(prefix); pw.print(" Extras: "); 1673 pw.println(job.getExtras().toShortString()); 1674 } 1675 if (job.getTransientExtras() != null && !job.getTransientExtras().isDefinitelyEmpty()) { 1676 pw.print(prefix); pw.print(" Transient extras: "); 1677 pw.println(job.getTransientExtras().toShortString()); 1678 } 1679 if (job.getClipData() != null) { 1680 pw.print(prefix); pw.print(" Clip data: "); 1681 StringBuilder b = new StringBuilder(128); 1682 b.append(job.getClipData()); 1683 pw.println(b); 1684 } 1685 if (uriPerms != null) { 1686 pw.print(prefix); pw.println(" Granted URI permissions:"); 1687 uriPerms.dump(pw, prefix + " "); 1688 } 1689 if (job.getRequiredNetwork() != null) { 1690 pw.print(prefix); pw.print(" Network type: "); 1691 pw.println(job.getRequiredNetwork()); 1692 } 1693 if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 1694 pw.print(prefix); pw.print(" Network download bytes: "); 1695 pw.println(mTotalNetworkDownloadBytes); 1696 } 1697 if (mTotalNetworkUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 1698 pw.print(prefix); pw.print(" Network upload bytes: "); 1699 pw.println(mTotalNetworkUploadBytes); 1700 } 1701 if (job.getMinLatencyMillis() != 0) { 1702 pw.print(prefix); pw.print(" Minimum latency: "); 1703 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw); 1704 pw.println(); 1705 } 1706 if (job.getMaxExecutionDelayMillis() != 0) { 1707 pw.print(prefix); pw.print(" Max execution delay: "); 1708 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw); 1709 pw.println(); 1710 } 1711 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy()); 1712 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw); 1713 pw.println(); 1714 if (job.hasEarlyConstraint()) { 1715 pw.print(prefix); pw.println(" Has early constraint"); 1716 } 1717 if (job.hasLateConstraint()) { 1718 pw.print(prefix); pw.println(" Has late constraint"); 1719 } 1720 } 1721 pw.print(prefix); pw.print("Required constraints:"); 1722 dumpConstraints(pw, requiredConstraints); 1723 pw.println(); 1724 pw.print(prefix); 1725 pw.print("Dynamic constraints:"); 1726 dumpConstraints(pw, mDynamicConstraints); 1727 pw.println(); 1728 if (full) { 1729 pw.print(prefix); pw.print("Satisfied constraints:"); 1730 dumpConstraints(pw, satisfiedConstraints); 1731 pw.println(); 1732 pw.print(prefix); pw.print("Unsatisfied constraints:"); 1733 dumpConstraints(pw, 1734 ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints)); 1735 pw.println(); 1736 if (dozeWhitelisted) { 1737 pw.print(prefix); pw.println("Doze whitelisted: true"); 1738 } 1739 if (uidActive) { 1740 pw.print(prefix); pw.println("Uid: active"); 1741 } 1742 if (job.isExemptedFromAppStandby()) { 1743 pw.print(prefix); pw.println("Is exempted from app standby"); 1744 } 1745 } 1746 if (trackingControllers != 0) { 1747 pw.print(prefix); pw.print("Tracking:"); 1748 if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY"); 1749 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY"); 1750 if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT"); 1751 if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE"); 1752 if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE"); 1753 if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME"); 1754 if ((trackingControllers & TRACKING_QUOTA) != 0) pw.print(" QUOTA"); 1755 pw.println(); 1756 } 1757 1758 pw.print(prefix); pw.println("Implicit constraints:"); 1759 pw.print(prefix); pw.print(" readyNotDozing: "); 1760 pw.println(mReadyNotDozing); 1761 pw.print(prefix); pw.print(" readyNotRestrictedInBg: "); 1762 pw.println(mReadyNotRestrictedInBg); 1763 if (!job.isPeriodic() && hasDeadlineConstraint()) { 1764 pw.print(prefix); pw.print(" readyDeadlineSatisfied: "); 1765 pw.println(mReadyDeadlineSatisfied); 1766 } 1767 pw.print(prefix); 1768 pw.print(" readyDynamicSatisfied: "); 1769 pw.println(mReadyDynamicSatisfied); 1770 1771 if (changedAuthorities != null) { 1772 pw.print(prefix); pw.println("Changed authorities:"); 1773 for (int i=0; i<changedAuthorities.size(); i++) { 1774 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i)); 1775 } 1776 } 1777 if (changedUris != null) { 1778 pw.print(prefix); 1779 pw.println("Changed URIs:"); 1780 for (int i = 0; i < changedUris.size(); i++) { 1781 pw.print(prefix); 1782 pw.print(" "); 1783 pw.println(changedUris.valueAt(i)); 1784 } 1785 } 1786 if (network != null) { 1787 pw.print(prefix); pw.print("Network: "); pw.println(network); 1788 } 1789 if (pendingWork != null && pendingWork.size() > 0) { 1790 pw.print(prefix); pw.println("Pending work:"); 1791 for (int i = 0; i < pendingWork.size(); i++) { 1792 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i); 1793 } 1794 } 1795 if (executingWork != null && executingWork.size() > 0) { 1796 pw.print(prefix); pw.println("Executing work:"); 1797 for (int i = 0; i < executingWork.size(); i++) { 1798 dumpJobWorkItem(pw, prefix, executingWork.get(i), i); 1799 } 1800 } 1801 pw.print(prefix); pw.print("Standby bucket: "); 1802 pw.println(getBucketName()); 1803 if (whenStandbyDeferred != 0) { 1804 pw.print(prefix); pw.print(" Deferred since: "); 1805 TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw); 1806 pw.println(); 1807 } 1808 if (mFirstForceBatchedTimeElapsed != 0) { 1809 pw.print(prefix); 1810 pw.print(" Time since first force batch attempt: "); 1811 TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, elapsedRealtimeMillis, pw); 1812 pw.println(); 1813 } 1814 pw.print(prefix); pw.print("Enqueue time: "); 1815 TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw); 1816 pw.println(); 1817 pw.print(prefix); pw.print("Run time: earliest="); 1818 formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis); 1819 pw.print(", latest="); 1820 formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis); 1821 pw.print(", original latest="); 1822 formatRunTime(pw, mOriginalLatestRunTimeElapsedMillis, 1823 NO_LATEST_RUNTIME, elapsedRealtimeMillis); 1824 pw.println(); 1825 if (numFailures != 0) { 1826 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures); 1827 } 1828 if (mLastSuccessfulRunTime != 0) { 1829 pw.print(prefix); pw.print("Last successful run: "); 1830 pw.println(formatTime(mLastSuccessfulRunTime)); 1831 } 1832 if (mLastFailedRunTime != 0) { 1833 pw.print(prefix); pw.print("Last failed run: "); 1834 pw.println(formatTime(mLastFailedRunTime)); 1835 } 1836 } 1837 formatTime(long time)1838 private static CharSequence formatTime(long time) { 1839 return DateFormat.format("yyyy-MM-dd HH:mm:ss", time); 1840 } 1841 dump(ProtoOutputStream proto, long fieldId, boolean full, long elapsedRealtimeMillis)1842 public void dump(ProtoOutputStream proto, long fieldId, boolean full, long elapsedRealtimeMillis) { 1843 final long token = proto.start(fieldId); 1844 1845 proto.write(JobStatusDumpProto.CALLING_UID, callingUid); 1846 proto.write(JobStatusDumpProto.TAG, tag); 1847 proto.write(JobStatusDumpProto.SOURCE_UID, getSourceUid()); 1848 proto.write(JobStatusDumpProto.SOURCE_USER_ID, getSourceUserId()); 1849 proto.write(JobStatusDumpProto.SOURCE_PACKAGE_NAME, getSourcePackageName()); 1850 1851 if (full) { 1852 final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO); 1853 1854 job.getService().dumpDebug(proto, JobStatusDumpProto.JobInfo.SERVICE); 1855 1856 proto.write(JobStatusDumpProto.JobInfo.IS_PERIODIC, job.isPeriodic()); 1857 proto.write(JobStatusDumpProto.JobInfo.PERIOD_INTERVAL_MS, job.getIntervalMillis()); 1858 proto.write(JobStatusDumpProto.JobInfo.PERIOD_FLEX_MS, job.getFlexMillis()); 1859 1860 proto.write(JobStatusDumpProto.JobInfo.IS_PERSISTED, job.isPersisted()); 1861 proto.write(JobStatusDumpProto.JobInfo.PRIORITY, job.getPriority()); 1862 proto.write(JobStatusDumpProto.JobInfo.FLAGS, job.getFlags()); 1863 proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags()); 1864 // Foreground exemption can be determined from internal flags value. 1865 1866 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_CHARGING, job.isRequireCharging()); 1867 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_BATTERY_NOT_LOW, job.isRequireBatteryNotLow()); 1868 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_DEVICE_IDLE, job.isRequireDeviceIdle()); 1869 1870 if (job.getTriggerContentUris() != null) { 1871 for (int i = 0; i < job.getTriggerContentUris().length; i++) { 1872 final long tcuToken = proto.start(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_URIS); 1873 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i]; 1874 1875 proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.FLAGS, trig.getFlags()); 1876 Uri u = trig.getUri(); 1877 if (u != null) { 1878 proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.URI, u.toString()); 1879 } 1880 1881 proto.end(tcuToken); 1882 } 1883 if (job.getTriggerContentUpdateDelay() >= 0) { 1884 proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_UPDATE_DELAY_MS, 1885 job.getTriggerContentUpdateDelay()); 1886 } 1887 if (job.getTriggerContentMaxDelay() >= 0) { 1888 proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_MAX_DELAY_MS, 1889 job.getTriggerContentMaxDelay()); 1890 } 1891 } 1892 if (job.getExtras() != null && !job.getExtras().isDefinitelyEmpty()) { 1893 job.getExtras().dumpDebug(proto, JobStatusDumpProto.JobInfo.EXTRAS); 1894 } 1895 if (job.getTransientExtras() != null && !job.getTransientExtras().isDefinitelyEmpty()) { 1896 job.getTransientExtras().dumpDebug(proto, JobStatusDumpProto.JobInfo.TRANSIENT_EXTRAS); 1897 } 1898 if (job.getClipData() != null) { 1899 job.getClipData().dumpDebug(proto, JobStatusDumpProto.JobInfo.CLIP_DATA); 1900 } 1901 if (uriPerms != null) { 1902 uriPerms.dump(proto, JobStatusDumpProto.JobInfo.GRANTED_URI_PERMISSIONS); 1903 } 1904 if (job.getRequiredNetwork() != null) { 1905 job.getRequiredNetwork().dumpDebug(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK); 1906 } 1907 if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 1908 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_DOWNLOAD_BYTES, 1909 mTotalNetworkDownloadBytes); 1910 } 1911 if (mTotalNetworkUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { 1912 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_UPLOAD_BYTES, 1913 mTotalNetworkUploadBytes); 1914 } 1915 proto.write(JobStatusDumpProto.JobInfo.MIN_LATENCY_MS, job.getMinLatencyMillis()); 1916 proto.write(JobStatusDumpProto.JobInfo.MAX_EXECUTION_DELAY_MS, job.getMaxExecutionDelayMillis()); 1917 1918 final long bpToken = proto.start(JobStatusDumpProto.JobInfo.BACKOFF_POLICY); 1919 proto.write(JobStatusDumpProto.JobInfo.Backoff.POLICY, job.getBackoffPolicy()); 1920 proto.write(JobStatusDumpProto.JobInfo.Backoff.INITIAL_BACKOFF_MS, 1921 job.getInitialBackoffMillis()); 1922 proto.end(bpToken); 1923 1924 proto.write(JobStatusDumpProto.JobInfo.HAS_EARLY_CONSTRAINT, job.hasEarlyConstraint()); 1925 proto.write(JobStatusDumpProto.JobInfo.HAS_LATE_CONSTRAINT, job.hasLateConstraint()); 1926 1927 proto.end(jiToken); 1928 } 1929 1930 dumpConstraints(proto, JobStatusDumpProto.REQUIRED_CONSTRAINTS, requiredConstraints); 1931 dumpConstraints(proto, JobStatusDumpProto.DYNAMIC_CONSTRAINTS, mDynamicConstraints); 1932 if (full) { 1933 dumpConstraints(proto, JobStatusDumpProto.SATISFIED_CONSTRAINTS, satisfiedConstraints); 1934 dumpConstraints(proto, JobStatusDumpProto.UNSATISFIED_CONSTRAINTS, 1935 ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints)); 1936 proto.write(JobStatusDumpProto.IS_DOZE_WHITELISTED, dozeWhitelisted); 1937 proto.write(JobStatusDumpProto.IS_UID_ACTIVE, uidActive); 1938 proto.write(JobStatusDumpProto.IS_EXEMPTED_FROM_APP_STANDBY, 1939 job.isExemptedFromAppStandby()); 1940 } 1941 1942 // Tracking controllers 1943 if ((trackingControllers&TRACKING_BATTERY) != 0) { 1944 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS, 1945 JobStatusDumpProto.TRACKING_BATTERY); 1946 } 1947 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) { 1948 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS, 1949 JobStatusDumpProto.TRACKING_CONNECTIVITY); 1950 } 1951 if ((trackingControllers&TRACKING_CONTENT) != 0) { 1952 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS, 1953 JobStatusDumpProto.TRACKING_CONTENT); 1954 } 1955 if ((trackingControllers&TRACKING_IDLE) != 0) { 1956 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS, 1957 JobStatusDumpProto.TRACKING_IDLE); 1958 } 1959 if ((trackingControllers&TRACKING_STORAGE) != 0) { 1960 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS, 1961 JobStatusDumpProto.TRACKING_STORAGE); 1962 } 1963 if ((trackingControllers&TRACKING_TIME) != 0) { 1964 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS, 1965 JobStatusDumpProto.TRACKING_TIME); 1966 } 1967 if ((trackingControllers & TRACKING_QUOTA) != 0) { 1968 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS, 1969 JobStatusDumpProto.TRACKING_QUOTA); 1970 } 1971 1972 // Implicit constraints 1973 final long icToken = proto.start(JobStatusDumpProto.IMPLICIT_CONSTRAINTS); 1974 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_DOZING, mReadyNotDozing); 1975 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_RESTRICTED_IN_BG, 1976 mReadyNotRestrictedInBg); 1977 // mReadyDeadlineSatisfied isn't an implicit constraint...and can be determined from other 1978 // field values. 1979 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_DYNAMIC_SATISFIED, 1980 mReadyDynamicSatisfied); 1981 proto.end(icToken); 1982 1983 if (changedAuthorities != null) { 1984 for (int k = 0; k < changedAuthorities.size(); k++) { 1985 proto.write(JobStatusDumpProto.CHANGED_AUTHORITIES, changedAuthorities.valueAt(k)); 1986 } 1987 } 1988 if (changedUris != null) { 1989 for (int i = 0; i < changedUris.size(); i++) { 1990 Uri u = changedUris.valueAt(i); 1991 proto.write(JobStatusDumpProto.CHANGED_URIS, u.toString()); 1992 } 1993 } 1994 1995 if (network != null) { 1996 network.dumpDebug(proto, JobStatusDumpProto.NETWORK); 1997 } 1998 1999 if (pendingWork != null) { 2000 for (int i = 0; i < pendingWork.size(); i++) { 2001 dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i)); 2002 } 2003 } 2004 if (executingWork != null) { 2005 for (int i = 0; i < executingWork.size(); i++) { 2006 dumpJobWorkItem(proto, JobStatusDumpProto.EXECUTING_WORK, executingWork.get(i)); 2007 } 2008 } 2009 2010 proto.write(JobStatusDumpProto.STANDBY_BUCKET, standbyBucket); 2011 proto.write(JobStatusDumpProto.ENQUEUE_DURATION_MS, elapsedRealtimeMillis - enqueueTime); 2012 proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_DEFERRAL_MS, 2013 whenStandbyDeferred == 0 ? 0 : elapsedRealtimeMillis - whenStandbyDeferred); 2014 proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_FORCE_BATCH_ATTEMPT_MS, 2015 mFirstForceBatchedTimeElapsed == 0 2016 ? 0 : elapsedRealtimeMillis - mFirstForceBatchedTimeElapsed); 2017 if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) { 2018 proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS, 0); 2019 } else { 2020 proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS, 2021 earliestRunTimeElapsedMillis - elapsedRealtimeMillis); 2022 } 2023 if (latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) { 2024 proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS, 0); 2025 } else { 2026 proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS, 2027 latestRunTimeElapsedMillis - elapsedRealtimeMillis); 2028 } 2029 proto.write(JobStatusDumpProto.ORIGINAL_LATEST_RUNTIME_ELAPSED, 2030 mOriginalLatestRunTimeElapsedMillis); 2031 2032 proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures); 2033 proto.write(JobStatusDumpProto.LAST_SUCCESSFUL_RUN_TIME, mLastSuccessfulRunTime); 2034 proto.write(JobStatusDumpProto.LAST_FAILED_RUN_TIME, mLastFailedRunTime); 2035 2036 proto.end(token); 2037 } 2038 } 2039