Home | History | Annotate | Download | only in job
      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 android.app.job;
     18 
     19 import android.content.ComponentName;
     20 import android.os.Parcel;
     21 import android.os.Parcelable;
     22 import android.os.PersistableBundle;
     23 
     24 /**
     25  * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
     26  * parameters required to schedule work against the calling application. These are constructed
     27  * using the {@link JobInfo.Builder}.
     28  * You must specify at least one sort of constraint on the JobInfo object that you are creating.
     29  * The goal here is to provide the scheduler with high-level semantics about the work you want to
     30  * accomplish. Doing otherwise with throw an exception in your app.
     31  */
     32 public class JobInfo implements Parcelable {
     33     /** Default. */
     34     public static final int NETWORK_TYPE_NONE = 0;
     35     /** This job requires network connectivity. */
     36     public static final int NETWORK_TYPE_ANY = 1;
     37     /** This job requires network connectivity that is unmetered. */
     38     public static final int NETWORK_TYPE_UNMETERED = 2;
     39 
     40     /**
     41      * Amount of backoff a job has initially by default, in milliseconds.
     42      */
     43     public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L;  // 30 seconds.
     44 
     45     /**
     46      * Maximum backoff we allow for a job, in milliseconds.
     47      */
     48     public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000;  // 5 hours.
     49 
     50     /**
     51      * Linearly back-off a failed job. See
     52      * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
     53      * retry_time(current_time, num_failures) =
     54      *     current_time + initial_backoff_millis * num_failures, num_failures >= 1
     55      */
     56     public static final int BACKOFF_POLICY_LINEAR = 0;
     57 
     58     /**
     59      * Exponentially back-off a failed job. See
     60      * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
     61      *
     62      * retry_time(current_time, num_failures) =
     63      *     current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1
     64      */
     65     public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
     66 
     67     /**
     68      * Default type of backoff.
     69      * @hide
     70      */
     71     public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
     72 
     73     private final int jobId;
     74     private final PersistableBundle extras;
     75     private final ComponentName service;
     76     private final boolean requireCharging;
     77     private final boolean requireDeviceIdle;
     78     private final boolean hasEarlyConstraint;
     79     private final boolean hasLateConstraint;
     80     private final int networkType;
     81     private final long minLatencyMillis;
     82     private final long maxExecutionDelayMillis;
     83     private final boolean isPeriodic;
     84     private final boolean isPersisted;
     85     private final long intervalMillis;
     86     private final long initialBackoffMillis;
     87     private final int backoffPolicy;
     88 
     89     /**
     90      * Unique job id associated with this class. This is assigned to your job by the scheduler.
     91      */
     92     public int getId() {
     93         return jobId;
     94     }
     95 
     96     /**
     97      * Bundle of extras which are returned to your application at execution time.
     98      */
     99     public PersistableBundle getExtras() {
    100         return extras;
    101     }
    102 
    103     /**
    104      * Name of the service endpoint that will be called back into by the JobScheduler.
    105      */
    106     public ComponentName getService() {
    107         return service;
    108     }
    109 
    110     /**
    111      * Whether this job needs the device to be plugged in.
    112      */
    113     public boolean isRequireCharging() {
    114         return requireCharging;
    115     }
    116 
    117     /**
    118      * Whether this job needs the device to be in an Idle maintenance window.
    119      */
    120     public boolean isRequireDeviceIdle() {
    121         return requireDeviceIdle;
    122     }
    123 
    124     /**
    125      * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
    126      * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
    127      * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
    128      */
    129     public int getNetworkType() {
    130         return networkType;
    131     }
    132 
    133     /**
    134      * Set for a job that does not recur periodically, to specify a delay after which the job
    135      * will be eligible for execution. This value is not set if the job recurs periodically.
    136      */
    137     public long getMinLatencyMillis() {
    138         return minLatencyMillis;
    139     }
    140 
    141     /**
    142      * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
    143      * periodically.
    144      */
    145     public long getMaxExecutionDelayMillis() {
    146         return maxExecutionDelayMillis;
    147     }
    148 
    149     /**
    150      * Track whether this job will repeat with a given period.
    151      */
    152     public boolean isPeriodic() {
    153         return isPeriodic;
    154     }
    155 
    156     /**
    157      * @return Whether or not this job should be persisted across device reboots.
    158      */
    159     public boolean isPersisted() {
    160         return isPersisted;
    161     }
    162 
    163     /**
    164      * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
    165      * job does not recur periodically.
    166      */
    167     public long getIntervalMillis() {
    168         return intervalMillis;
    169     }
    170 
    171     /**
    172      * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
    173      * will be increased depending on the backoff policy specified at job creation time. Defaults
    174      * to 5 seconds.
    175      */
    176     public long getInitialBackoffMillis() {
    177         return initialBackoffMillis;
    178     }
    179 
    180     /**
    181      * One of either {@link android.app.job.JobInfo#BACKOFF_POLICY_EXPONENTIAL}, or
    182      * {@link android.app.job.JobInfo#BACKOFF_POLICY_LINEAR}, depending on which criteria you set
    183      * when creating this job.
    184      */
    185     public int getBackoffPolicy() {
    186         return backoffPolicy;
    187     }
    188 
    189     /**
    190      * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
    191      * function was called at all.
    192      * @hide
    193      */
    194     public boolean hasEarlyConstraint() {
    195         return hasEarlyConstraint;
    196     }
    197 
    198     /**
    199      * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
    200      * function was called at all.
    201      * @hide
    202      */
    203     public boolean hasLateConstraint() {
    204         return hasLateConstraint;
    205     }
    206 
    207     private JobInfo(Parcel in) {
    208         jobId = in.readInt();
    209         extras = in.readPersistableBundle();
    210         service = in.readParcelable(null);
    211         requireCharging = in.readInt() == 1;
    212         requireDeviceIdle = in.readInt() == 1;
    213         networkType = in.readInt();
    214         minLatencyMillis = in.readLong();
    215         maxExecutionDelayMillis = in.readLong();
    216         isPeriodic = in.readInt() == 1;
    217         isPersisted = in.readInt() == 1;
    218         intervalMillis = in.readLong();
    219         initialBackoffMillis = in.readLong();
    220         backoffPolicy = in.readInt();
    221         hasEarlyConstraint = in.readInt() == 1;
    222         hasLateConstraint = in.readInt() == 1;
    223     }
    224 
    225     private JobInfo(JobInfo.Builder b) {
    226         jobId = b.mJobId;
    227         extras = b.mExtras;
    228         service = b.mJobService;
    229         requireCharging = b.mRequiresCharging;
    230         requireDeviceIdle = b.mRequiresDeviceIdle;
    231         networkType = b.mNetworkType;
    232         minLatencyMillis = b.mMinLatencyMillis;
    233         maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
    234         isPeriodic = b.mIsPeriodic;
    235         isPersisted = b.mIsPersisted;
    236         intervalMillis = b.mIntervalMillis;
    237         initialBackoffMillis = b.mInitialBackoffMillis;
    238         backoffPolicy = b.mBackoffPolicy;
    239         hasEarlyConstraint = b.mHasEarlyConstraint;
    240         hasLateConstraint = b.mHasLateConstraint;
    241     }
    242 
    243     @Override
    244     public int describeContents() {
    245         return 0;
    246     }
    247 
    248     @Override
    249     public void writeToParcel(Parcel out, int flags) {
    250         out.writeInt(jobId);
    251         out.writePersistableBundle(extras);
    252         out.writeParcelable(service, flags);
    253         out.writeInt(requireCharging ? 1 : 0);
    254         out.writeInt(requireDeviceIdle ? 1 : 0);
    255         out.writeInt(networkType);
    256         out.writeLong(minLatencyMillis);
    257         out.writeLong(maxExecutionDelayMillis);
    258         out.writeInt(isPeriodic ? 1 : 0);
    259         out.writeInt(isPersisted ? 1 : 0);
    260         out.writeLong(intervalMillis);
    261         out.writeLong(initialBackoffMillis);
    262         out.writeInt(backoffPolicy);
    263         out.writeInt(hasEarlyConstraint ? 1 : 0);
    264         out.writeInt(hasLateConstraint ? 1 : 0);
    265     }
    266 
    267     public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
    268         @Override
    269         public JobInfo createFromParcel(Parcel in) {
    270             return new JobInfo(in);
    271         }
    272 
    273         @Override
    274         public JobInfo[] newArray(int size) {
    275             return new JobInfo[size];
    276         }
    277     };
    278 
    279     @Override
    280     public String toString() {
    281         return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
    282     }
    283 
    284     /** Builder class for constructing {@link JobInfo} objects. */
    285     public static final class Builder {
    286         private int mJobId;
    287         private PersistableBundle mExtras = PersistableBundle.EMPTY;
    288         private ComponentName mJobService;
    289         // Requirements.
    290         private boolean mRequiresCharging;
    291         private boolean mRequiresDeviceIdle;
    292         private int mNetworkType;
    293         private boolean mIsPersisted;
    294         // One-off parameters.
    295         private long mMinLatencyMillis;
    296         private long mMaxExecutionDelayMillis;
    297         // Periodic parameters.
    298         private boolean mIsPeriodic;
    299         private boolean mHasEarlyConstraint;
    300         private boolean mHasLateConstraint;
    301         private long mIntervalMillis;
    302         // Back-off parameters.
    303         private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
    304         private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
    305         /** Easy way to track whether the client has tried to set a back-off policy. */
    306         private boolean mBackoffPolicySet = false;
    307 
    308         /**
    309          * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
    310          *               jobs created with the same jobId, will update the pre-existing job with
    311          *               the same id.
    312          * @param jobService The endpoint that you implement that will receive the callback from the
    313          *            JobScheduler.
    314          */
    315         public Builder(int jobId, ComponentName jobService) {
    316             mJobService = jobService;
    317             mJobId = jobId;
    318         }
    319 
    320         /**
    321          * Set optional extras. This is persisted, so we only allow primitive types.
    322          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
    323          */
    324         public Builder setExtras(PersistableBundle extras) {
    325             mExtras = extras;
    326             return this;
    327         }
    328 
    329         /**
    330          * Set some description of the kind of network type your job needs to have.
    331          * Not calling this function means the network is not necessary, as the default is
    332          * {@link #NETWORK_TYPE_NONE}.
    333          * Bear in mind that calling this function defines network as a strict requirement for your
    334          * job. If the network requested is not available your job will never run. See
    335          * {@link #setOverrideDeadline(long)} to change this behaviour.
    336          */
    337         public Builder setRequiredNetworkType(int networkType) {
    338             mNetworkType = networkType;
    339             return this;
    340         }
    341 
    342         /**
    343          * Specify that to run this job, the device needs to be plugged in. This defaults to
    344          * false.
    345          * @param requiresCharging Whether or not the device is plugged in.
    346          */
    347         public Builder setRequiresCharging(boolean requiresCharging) {
    348             mRequiresCharging = requiresCharging;
    349             return this;
    350         }
    351 
    352         /**
    353          * Specify that to run, the job needs the device to be in idle mode. This defaults to
    354          * false.
    355          * <p>Idle mode is a loose definition provided by the system, which means that the device
    356          * is not in use, and has not been in use for some time. As such, it is a good time to
    357          * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
    358          * to your application, and surfaced to the user in battery stats.</p>
    359          * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
    360          *                           window.
    361          */
    362         public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
    363             mRequiresDeviceIdle = requiresDeviceIdle;
    364             return this;
    365         }
    366 
    367         /**
    368          * Specify that this job should recur with the provided interval, not more than once per
    369          * period. You have no control over when within this interval this job will be executed,
    370          * only the guarantee that it will be executed at most once within this interval.
    371          * Setting this function on the builder with {@link #setMinimumLatency(long)} or
    372          * {@link #setOverrideDeadline(long)} will result in an error.
    373          * @param intervalMillis Millisecond interval for which this job will repeat.
    374          */
    375         public Builder setPeriodic(long intervalMillis) {
    376             mIsPeriodic = true;
    377             mIntervalMillis = intervalMillis;
    378             mHasEarlyConstraint = mHasLateConstraint = true;
    379             return this;
    380         }
    381 
    382         /**
    383          * Specify that this job should be delayed by the provided amount of time.
    384          * Because it doesn't make sense setting this property on a periodic job, doing so will
    385          * throw an {@link java.lang.IllegalArgumentException} when
    386          * {@link android.app.job.JobInfo.Builder#build()} is called.
    387          * @param minLatencyMillis Milliseconds before which this job will not be considered for
    388          *                         execution.
    389          */
    390         public Builder setMinimumLatency(long minLatencyMillis) {
    391             mMinLatencyMillis = minLatencyMillis;
    392             mHasEarlyConstraint = true;
    393             return this;
    394         }
    395 
    396         /**
    397          * Set deadline which is the maximum scheduling latency. The job will be run by this
    398          * deadline even if other requirements are not met. Because it doesn't make sense setting
    399          * this property on a periodic job, doing so will throw an
    400          * {@link java.lang.IllegalArgumentException} when
    401          * {@link android.app.job.JobInfo.Builder#build()} is called.
    402          */
    403         public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
    404             mMaxExecutionDelayMillis = maxExecutionDelayMillis;
    405             mHasLateConstraint = true;
    406             return this;
    407         }
    408 
    409         /**
    410          * Set up the back-off/retry policy.
    411          * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at
    412          * 5hrs.
    413          * Note that trying to set a backoff criteria for a job with
    414          * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
    415          * This is because back-off typically does not make sense for these types of jobs. See
    416          * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
    417          * for more description of the return value for the case of a job executing while in idle
    418          * mode.
    419          * @param initialBackoffMillis Millisecond time interval to wait initially when job has
    420          *                             failed.
    421          * @param backoffPolicy is one of {@link #BACKOFF_POLICY_LINEAR} or
    422          * {@link #BACKOFF_POLICY_EXPONENTIAL}
    423          */
    424         public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
    425             mBackoffPolicySet = true;
    426             mInitialBackoffMillis = initialBackoffMillis;
    427             mBackoffPolicy = backoffPolicy;
    428             return this;
    429         }
    430 
    431         /**
    432          * Set whether or not to persist this job across device reboots. This will only have an
    433          * effect if your application holds the permission
    434          * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}. Otherwise an exception will
    435          * be thrown.
    436          * @param isPersisted True to indicate that the job will be written to disk and loaded at
    437          *                    boot.
    438          */
    439         public Builder setPersisted(boolean isPersisted) {
    440             mIsPersisted = isPersisted;
    441             return this;
    442         }
    443 
    444         /**
    445          * @return The job object to hand to the JobScheduler. This object is immutable.
    446          */
    447         public JobInfo build() {
    448             // Allow jobs with no constraints - What am I, a database?
    449             if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
    450                     !mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE) {
    451                 throw new IllegalArgumentException("You're trying to build a job with no " +
    452                         "constraints, this is not allowed.");
    453             }
    454             mExtras = new PersistableBundle(mExtras);  // Make our own copy.
    455             // Check that a deadline was not set on a periodic job.
    456             if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
    457                 throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
    458                         "periodic job.");
    459             }
    460             if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
    461                 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
    462                         "periodic job");
    463             }
    464             if (mBackoffPolicySet && mRequiresDeviceIdle) {
    465                 throw new IllegalArgumentException("An idle mode job will not respect any" +
    466                         " back-off policy, so calling setBackoffCriteria with" +
    467                         " setRequiresDeviceIdle is an error.");
    468             }
    469             return new JobInfo(this);
    470         }
    471     }
    472 
    473 }
    474