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