• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.app.ActivityManager;
23 import android.app.usage.UsageStatsManager;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.content.ClipData;
26 import android.content.pm.PackageManager;
27 import android.net.Network;
28 import android.net.NetworkRequest;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.os.IBinder;
32 import android.os.Parcel;
33 import android.os.Parcelable;
34 import android.os.PersistableBundle;
35 import android.os.RemoteException;
36 
37 import java.lang.annotation.Retention;
38 import java.lang.annotation.RetentionPolicy;
39 
40 /**
41  * Contains the parameters used to configure/identify your job. You do not create this object
42  * yourself, instead it is handed in to your application by the System.
43  */
44 public class JobParameters implements Parcelable {
45 
46     /** @hide */
47     public static final int INTERNAL_STOP_REASON_UNKNOWN = -1;
48 
49     /** @hide */
50     public static final int INTERNAL_STOP_REASON_CANCELED =
51             JobProtoEnums.INTERNAL_STOP_REASON_CANCELLED; // 0.
52     /** @hide */
53     public static final int INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED =
54             JobProtoEnums.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED; // 1.
55     /** @hide */
56     public static final int INTERNAL_STOP_REASON_PREEMPT =
57             JobProtoEnums.INTERNAL_STOP_REASON_PREEMPT; // 2.
58     /**
59      * The job ran for at least its minimum execution limit.
60      * @hide
61      */
62     public static final int INTERNAL_STOP_REASON_TIMEOUT =
63             JobProtoEnums.INTERNAL_STOP_REASON_TIMEOUT; // 3.
64     /** @hide */
65     public static final int INTERNAL_STOP_REASON_DEVICE_IDLE =
66             JobProtoEnums.INTERNAL_STOP_REASON_DEVICE_IDLE; // 4.
67     /** @hide */
68     public static final int INTERNAL_STOP_REASON_DEVICE_THERMAL =
69             JobProtoEnums.INTERNAL_STOP_REASON_DEVICE_THERMAL; // 5.
70     /**
71      * The job is in the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED}
72      * bucket.
73      *
74      * @hide
75      */
76     public static final int INTERNAL_STOP_REASON_RESTRICTED_BUCKET =
77             JobProtoEnums.INTERNAL_STOP_REASON_RESTRICTED_BUCKET; // 6.
78     /**
79      * The app was uninstalled.
80      * @hide
81      */
82     public static final int INTERNAL_STOP_REASON_UNINSTALL =
83             JobProtoEnums.INTERNAL_STOP_REASON_UNINSTALL; // 7.
84     /**
85      * The app's data was cleared.
86      * @hide
87      */
88     public static final int INTERNAL_STOP_REASON_DATA_CLEARED =
89             JobProtoEnums.INTERNAL_STOP_REASON_DATA_CLEARED; // 8.
90     /**
91      * @hide
92      */
93     public static final int INTERNAL_STOP_REASON_RTC_UPDATED =
94             JobProtoEnums.INTERNAL_STOP_REASON_RTC_UPDATED; // 9.
95     /**
96      * The app called jobFinished() on its own.
97      * @hide
98      */
99     public static final int INTERNAL_STOP_REASON_SUCCESSFUL_FINISH =
100             JobProtoEnums.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH; // 10.
101 
102     /**
103      * All the stop reason codes. This should be regarded as an immutable array at runtime.
104      *
105      * Note the order of these values will affect "dumpsys batterystats", and we do not want to
106      * change the order of existing fields, so adding new fields is okay but do not remove or
107      * change existing fields. When deprecating a field, just replace that with "-1" in this array.
108      *
109      * @hide
110      */
111     public static final int[] JOB_STOP_REASON_CODES = {
112             INTERNAL_STOP_REASON_UNKNOWN,
113             INTERNAL_STOP_REASON_CANCELED,
114             INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
115             INTERNAL_STOP_REASON_PREEMPT,
116             INTERNAL_STOP_REASON_TIMEOUT,
117             INTERNAL_STOP_REASON_DEVICE_IDLE,
118             INTERNAL_STOP_REASON_DEVICE_THERMAL,
119             INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
120             INTERNAL_STOP_REASON_UNINSTALL,
121             INTERNAL_STOP_REASON_DATA_CLEARED,
122             INTERNAL_STOP_REASON_RTC_UPDATED,
123             INTERNAL_STOP_REASON_SUCCESSFUL_FINISH,
124     };
125 
126     /**
127      * @hide
128      */
129     // TODO(142420609): make it @SystemApi for mainline
130     @NonNull
getInternalReasonCodeDescription(int reasonCode)131     public static String getInternalReasonCodeDescription(int reasonCode) {
132         switch (reasonCode) {
133             case INTERNAL_STOP_REASON_CANCELED: return "canceled";
134             case INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
135             case INTERNAL_STOP_REASON_PREEMPT: return "preempt";
136             case INTERNAL_STOP_REASON_TIMEOUT: return "timeout";
137             case INTERNAL_STOP_REASON_DEVICE_IDLE: return "device_idle";
138             case INTERNAL_STOP_REASON_DEVICE_THERMAL: return "thermal";
139             case INTERNAL_STOP_REASON_RESTRICTED_BUCKET: return "restricted_bucket";
140             case INTERNAL_STOP_REASON_UNINSTALL: return "uninstall";
141             case INTERNAL_STOP_REASON_DATA_CLEARED: return "data_cleared";
142             case INTERNAL_STOP_REASON_RTC_UPDATED: return "rtc_updated";
143             case INTERNAL_STOP_REASON_SUCCESSFUL_FINISH: return "successful_finish";
144             default: return "unknown:" + reasonCode;
145         }
146     }
147 
148     /** @hide */
149     @NonNull
getJobStopReasonCodes()150     public static int[] getJobStopReasonCodes() {
151         return JOB_STOP_REASON_CODES;
152     }
153 
154     /**
155      * There is no reason the job is stopped. This is the value returned from the JobParameters
156      * object passed to {@link JobService#onStartJob(JobParameters)}.
157      */
158     public static final int STOP_REASON_UNDEFINED = 0;
159     /**
160      * The job was cancelled directly by the app, either by calling
161      * {@link JobScheduler#cancel(int)}, {@link JobScheduler#cancelAll()}, or by scheduling a
162      * new job with the same job ID.
163      */
164     public static final int STOP_REASON_CANCELLED_BY_APP = 1;
165     /** The job was stopped to run a higher priority job of the app. */
166     public static final int STOP_REASON_PREEMPT = 2;
167     /**
168      * The job used up its maximum execution time and timed out. Each individual job has a maximum
169      * execution time limit, regardless of how much total quota the app has. See the note on
170      * {@link JobScheduler} and {@link JobInfo} for the execution time limits.
171      */
172     public static final int STOP_REASON_TIMEOUT = 3;
173     /**
174      * The device state (eg. Doze, battery saver, memory usage, etc) requires JobScheduler stop this
175      * job.
176      */
177     public static final int STOP_REASON_DEVICE_STATE = 4;
178     /**
179      * The requested battery-not-low constraint is no longer satisfied.
180      *
181      * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
182      */
183     public static final int STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW = 5;
184     /**
185      * The requested charging constraint is no longer satisfied.
186      *
187      * @see JobInfo.Builder#setRequiresCharging(boolean)
188      */
189     public static final int STOP_REASON_CONSTRAINT_CHARGING = 6;
190     /**
191      * The requested connectivity constraint is no longer satisfied.
192      *
193      * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest)
194      * @see JobInfo.Builder#setRequiredNetworkType(int)
195      */
196     public static final int STOP_REASON_CONSTRAINT_CONNECTIVITY = 7;
197     /**
198      * The requested idle constraint is no longer satisfied.
199      *
200      * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
201      */
202     public static final int STOP_REASON_CONSTRAINT_DEVICE_IDLE = 8;
203     /**
204      * The requested storage-not-low constraint is no longer satisfied.
205      *
206      * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
207      */
208     public static final int STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW = 9;
209     /**
210      * The app has consumed all of its current quota. Each app is assigned a quota of how much
211      * it can run jobs within a certain time frame. The quota is informed, in part, by app standby
212      * buckets. Once an app has used up all of its quota, it won't be able to start jobs until
213      * quota is replenished, is changed, or is temporarily not applied.
214      *
215      * @see UsageStatsManager#getAppStandbyBucket()
216      */
217     public static final int STOP_REASON_QUOTA = 10;
218     /**
219      * The app is restricted from running in the background.
220      *
221      * @see ActivityManager#isBackgroundRestricted()
222      * @see PackageManager#isInstantApp()
223      */
224     public static final int STOP_REASON_BACKGROUND_RESTRICTION = 11;
225     /**
226      * The current standby bucket requires that the job stop now.
227      *
228      * @see UsageStatsManager#STANDBY_BUCKET_RESTRICTED
229      */
230     public static final int STOP_REASON_APP_STANDBY = 12;
231     /**
232      * The user stopped the job. This can happen either through force-stop, adb shell commands,
233      * or uninstalling.
234      */
235     public static final int STOP_REASON_USER = 13;
236     /** The system is doing some processing that requires stopping this job. */
237     public static final int STOP_REASON_SYSTEM_PROCESSING = 14;
238     /**
239      * The system's estimate of when the app will be launched changed significantly enough to
240      * decide this job shouldn't be running right now. This will mostly apply to prefetch jobs.
241      *
242      * @see JobInfo#isPrefetch()
243      * @see JobInfo.Builder#setPrefetch(boolean)
244      */
245     public static final int STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED = 15;
246 
247     /** @hide */
248     @IntDef(prefix = {"STOP_REASON_"}, value = {
249             STOP_REASON_UNDEFINED,
250             STOP_REASON_CANCELLED_BY_APP,
251             STOP_REASON_PREEMPT,
252             STOP_REASON_TIMEOUT,
253             STOP_REASON_DEVICE_STATE,
254             STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW,
255             STOP_REASON_CONSTRAINT_CHARGING,
256             STOP_REASON_CONSTRAINT_CONNECTIVITY,
257             STOP_REASON_CONSTRAINT_DEVICE_IDLE,
258             STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW,
259             STOP_REASON_QUOTA,
260             STOP_REASON_BACKGROUND_RESTRICTION,
261             STOP_REASON_APP_STANDBY,
262             STOP_REASON_USER,
263             STOP_REASON_SYSTEM_PROCESSING,
264             STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED,
265     })
266     @Retention(RetentionPolicy.SOURCE)
267     public @interface StopReason {
268     }
269 
270     @UnsupportedAppUsage
271     private final int jobId;
272     private final PersistableBundle extras;
273     private final Bundle transientExtras;
274     private final ClipData clipData;
275     private final int clipGrantFlags;
276     @UnsupportedAppUsage
277     private final IBinder callback;
278     private final boolean overrideDeadlineExpired;
279     private final boolean mIsExpedited;
280     private final Uri[] mTriggeredContentUris;
281     private final String[] mTriggeredContentAuthorities;
282     private final Network network;
283 
284     private int mStopReason = STOP_REASON_UNDEFINED;
285     private int mInternalStopReason = INTERNAL_STOP_REASON_UNKNOWN;
286     private String debugStopReason; // Human readable stop reason for debugging.
287 
288     /** @hide */
JobParameters(IBinder callback, int jobId, PersistableBundle extras, Bundle transientExtras, ClipData clipData, int clipGrantFlags, boolean overrideDeadlineExpired, boolean isExpedited, Uri[] triggeredContentUris, String[] triggeredContentAuthorities, Network network)289     public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
290             Bundle transientExtras, ClipData clipData, int clipGrantFlags,
291             boolean overrideDeadlineExpired, boolean isExpedited, Uri[] triggeredContentUris,
292             String[] triggeredContentAuthorities, Network network) {
293         this.jobId = jobId;
294         this.extras = extras;
295         this.transientExtras = transientExtras;
296         this.clipData = clipData;
297         this.clipGrantFlags = clipGrantFlags;
298         this.callback = callback;
299         this.overrideDeadlineExpired = overrideDeadlineExpired;
300         this.mIsExpedited = isExpedited;
301         this.mTriggeredContentUris = triggeredContentUris;
302         this.mTriggeredContentAuthorities = triggeredContentAuthorities;
303         this.network = network;
304     }
305 
306     /**
307      * @return The unique id of this job, specified at creation time.
308      */
getJobId()309     public int getJobId() {
310         return jobId;
311     }
312 
313     /**
314      * @return The reason {@link JobService#onStopJob(JobParameters)} was called on this job. Will
315      * be {@link #STOP_REASON_UNDEFINED} if {@link JobService#onStopJob(JobParameters)} has not
316      * yet been called.
317      */
318     @StopReason
getStopReason()319     public int getStopReason() {
320         return mStopReason;
321     }
322 
323     /** @hide */
getInternalStopReasonCode()324     public int getInternalStopReasonCode() {
325         return mInternalStopReason;
326     }
327 
328     /**
329      * Reason onStopJob() was called on this job.
330      *
331      * @hide
332      */
getDebugStopReason()333     public String getDebugStopReason() {
334         return debugStopReason;
335     }
336 
337     /**
338      * @return The extras you passed in when constructing this job with
339      * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
340      * never be null. If you did not set any extras this will be an empty bundle.
341      */
getExtras()342     public @NonNull PersistableBundle getExtras() {
343         return extras;
344     }
345 
346     /**
347      * @return The transient extras you passed in when constructing this job with
348      * {@link android.app.job.JobInfo.Builder#setTransientExtras(android.os.Bundle)}. This will
349      * never be null. If you did not set any extras this will be an empty bundle.
350      */
getTransientExtras()351     public @NonNull Bundle getTransientExtras() {
352         return transientExtras;
353     }
354 
355     /**
356      * @return The clip you passed in when constructing this job with
357      * {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be null
358      * if it was not set.
359      */
getClipData()360     public @Nullable ClipData getClipData() {
361         return clipData;
362     }
363 
364     /**
365      * @return The clip grant flags you passed in when constructing this job with
366      * {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be 0
367      * if it was not set.
368      */
getClipGrantFlags()369     public int getClipGrantFlags() {
370         return clipGrantFlags;
371     }
372 
373     /**
374      * @return Whether this job is running as an expedited job or not. A job is guaranteed to have
375      * all expedited job guarantees for the duration of the job execution if this returns
376      * {@code true}. This will return {@code false} if the job that wasn't requested to run as a
377      * expedited job, or if it was requested to run as an expedited job but the app didn't have
378      * any remaining expedited job quota at the time of execution.
379      *
380      * @see JobInfo.Builder#setExpedited(boolean)
381      */
isExpeditedJob()382     public boolean isExpeditedJob() {
383         return mIsExpedited;
384     }
385 
386     /**
387      * For jobs with {@link android.app.job.JobInfo.Builder#setOverrideDeadline(long)} set, this
388      * provides an easy way to tell whether the job is being executed due to the deadline
389      * expiring. Note: If the job is running because its deadline expired, it implies that its
390      * constraints will not be met.
391      */
isOverrideDeadlineExpired()392     public boolean isOverrideDeadlineExpired() {
393         return overrideDeadlineExpired;
394     }
395 
396     /**
397      * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
398      * reports which URIs have triggered the job.  This will be null if either no URIs have
399      * triggered it (it went off due to a deadline or other reason), or the number of changed
400      * URIs is too large to report.  Whether or not the number of URIs is too large, you can
401      * always use {@link #getTriggeredContentAuthorities()} to determine whether the job was
402      * triggered due to any content changes and the authorities they are associated with.
403      */
getTriggeredContentUris()404     public @Nullable Uri[] getTriggeredContentUris() {
405         return mTriggeredContentUris;
406     }
407 
408     /**
409      * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
410      * reports which content authorities have triggered the job.  It will only be null if no
411      * authorities have triggered it -- that is, the job executed for some other reason, such
412      * as a deadline expiring.  If this is non-null, you can use {@link #getTriggeredContentUris()}
413      * to retrieve the details of which URIs changed (as long as that has not exceeded the maximum
414      * number it can reported).
415      */
getTriggeredContentAuthorities()416     public @Nullable String[] getTriggeredContentAuthorities() {
417         return mTriggeredContentAuthorities;
418     }
419 
420     /**
421      * Return the network that should be used to perform any network requests
422      * for this job.
423      * <p>
424      * Devices may have multiple active network connections simultaneously, or
425      * they may not have a default network route at all. To correctly handle all
426      * situations like this, your job should always use the network returned by
427      * this method instead of implicitly using the default network route.
428      * <p>
429      * Note that the system may relax the constraints you originally requested,
430      * such as allowing a {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over
431      * a metered network when there is a surplus of metered data available.
432      *
433      * @return the network that should be used to perform any network requests
434      *         for this job, or {@code null} if this job didn't set any required
435      *         network type or if the job executed when there was no available network to use.
436      * @see JobInfo.Builder#setRequiredNetworkType(int)
437      * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest)
438      */
getNetwork()439     public @Nullable Network getNetwork() {
440         return network;
441     }
442 
443     /**
444      * Dequeue the next pending {@link JobWorkItem} from these JobParameters associated with their
445      * currently running job.  Calling this method when there is no more work available and all
446      * previously dequeued work has been completed will result in the system taking care of
447      * stopping the job for you --
448      * you should not call {@link JobService#jobFinished(JobParameters, boolean)} yourself
449      * (otherwise you risk losing an upcoming JobWorkItem that is being enqueued at the same time).
450      *
451      * <p>Once you are done with the {@link JobWorkItem} returned by this method, you must call
452      * {@link #completeWork(JobWorkItem)} with it to inform the system that you are done
453      * executing the work.  The job will not be finished until all dequeued work has been
454      * completed.  You do not, however, have to complete each returned work item before deqeueing
455      * the next one -- you can use {@link #dequeueWork()} multiple times before completing
456      * previous work if you want to process work in parallel, and you can complete the work
457      * in whatever order you want.</p>
458      *
459      * <p>If the job runs to the end of its available time period before all work has been
460      * completed, it will stop as normal.  You should return true from
461      * {@link JobService#onStopJob(JobParameters)} in order to have the job rescheduled, and by
462      * doing so any pending as well as remaining uncompleted work will be re-queued
463      * for the next time the job runs.</p>
464      *
465      * <p>This example shows how to construct a JobService that will serially dequeue and
466      * process work that is available for it:</p>
467      *
468      * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/JobWorkService.java
469      *      service}
470      *
471      * @return Returns a new {@link JobWorkItem} if there is one pending, otherwise null.
472      * If null is returned, the system will also stop the job if all work has also been completed.
473      * (This means that for correct operation, you must always call dequeueWork() after you have
474      * completed other work, to check either for more work or allow the system to stop the job.)
475      */
dequeueWork()476     public @Nullable JobWorkItem dequeueWork() {
477         try {
478             return getCallback().dequeueWork(getJobId());
479         } catch (RemoteException e) {
480             throw e.rethrowFromSystemServer();
481         }
482     }
483 
484     /**
485      * Report the completion of executing a {@link JobWorkItem} previously returned by
486      * {@link #dequeueWork()}.  This tells the system you are done with the
487      * work associated with that item, so it will not be returned again.  Note that if this
488      * is the last work in the queue, completing it here will <em>not</em> finish the overall
489      * job -- for that to happen, you still need to call {@link #dequeueWork()}
490      * again.
491      *
492      * <p>If you are enqueueing work into a job, you must call this method for each piece
493      * of work you process.  Do <em>not</em> call
494      * {@link JobService#jobFinished(JobParameters, boolean)}
495      * or else you can lose work in your queue.</p>
496      *
497      * @param work The work you have completed processing, as previously returned by
498      * {@link #dequeueWork()}
499      */
completeWork(@onNull JobWorkItem work)500     public void completeWork(@NonNull JobWorkItem work) {
501         try {
502             if (!getCallback().completeWork(getJobId(), work.getWorkId())) {
503                 throw new IllegalArgumentException("Given work is not active: " + work);
504             }
505         } catch (RemoteException e) {
506             throw e.rethrowFromSystemServer();
507         }
508     }
509 
510     /** @hide */
511     @UnsupportedAppUsage
getCallback()512     public IJobCallback getCallback() {
513         return IJobCallback.Stub.asInterface(callback);
514     }
515 
JobParameters(Parcel in)516     private JobParameters(Parcel in) {
517         jobId = in.readInt();
518         extras = in.readPersistableBundle();
519         transientExtras = in.readBundle();
520         if (in.readInt() != 0) {
521             clipData = ClipData.CREATOR.createFromParcel(in);
522             clipGrantFlags = in.readInt();
523         } else {
524             clipData = null;
525             clipGrantFlags = 0;
526         }
527         callback = in.readStrongBinder();
528         overrideDeadlineExpired = in.readInt() == 1;
529         mIsExpedited = in.readBoolean();
530         mTriggeredContentUris = in.createTypedArray(Uri.CREATOR);
531         mTriggeredContentAuthorities = in.createStringArray();
532         if (in.readInt() != 0) {
533             network = Network.CREATOR.createFromParcel(in);
534         } else {
535             network = null;
536         }
537         mStopReason = in.readInt();
538         mInternalStopReason = in.readInt();
539         debugStopReason = in.readString();
540     }
541 
542     /** @hide */
setStopReason(@topReason int reason, int internalStopReason, String debugStopReason)543     public void setStopReason(@StopReason int reason, int internalStopReason,
544             String debugStopReason) {
545         mStopReason = reason;
546         mInternalStopReason = internalStopReason;
547         this.debugStopReason = debugStopReason;
548     }
549 
550     @Override
describeContents()551     public int describeContents() {
552         return 0;
553     }
554 
555     @Override
writeToParcel(Parcel dest, int flags)556     public void writeToParcel(Parcel dest, int flags) {
557         dest.writeInt(jobId);
558         dest.writePersistableBundle(extras);
559         dest.writeBundle(transientExtras);
560         if (clipData != null) {
561             dest.writeInt(1);
562             clipData.writeToParcel(dest, flags);
563             dest.writeInt(clipGrantFlags);
564         } else {
565             dest.writeInt(0);
566         }
567         dest.writeStrongBinder(callback);
568         dest.writeInt(overrideDeadlineExpired ? 1 : 0);
569         dest.writeBoolean(mIsExpedited);
570         dest.writeTypedArray(mTriggeredContentUris, flags);
571         dest.writeStringArray(mTriggeredContentAuthorities);
572         if (network != null) {
573             dest.writeInt(1);
574             network.writeToParcel(dest, flags);
575         } else {
576             dest.writeInt(0);
577         }
578         dest.writeInt(mStopReason);
579         dest.writeInt(mInternalStopReason);
580         dest.writeString(debugStopReason);
581     }
582 
583     public static final @android.annotation.NonNull Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
584         @Override
585         public JobParameters createFromParcel(Parcel in) {
586             return new JobParameters(in);
587         }
588 
589         @Override
590         public JobParameters[] newArray(int size) {
591             return new JobParameters[size];
592         }
593     };
594 }
595