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