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