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