blob: f706260edec24ad727ecbd9d349c6c06b82bb2cd [file] [log] [blame]
Christopher Tate7060b042014-06-09 19:50:00 -07001/*
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
17package com.android.server.job.controllers;
18
Kweku Adamsbbb04592019-08-05 15:17:23 -070019import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070020import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
21
Shreyas Basarge968ac752016-01-11 23:09:26 +000022import android.app.AppGlobals;
Christopher Tate7060b042014-06-09 19:50:00 -070023import android.app.job.JobInfo;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070024import android.app.job.JobWorkItem;
Dianne Hackborna47223f2017-03-30 13:49:13 -070025import android.content.ClipData;
Christopher Tate7060b042014-06-09 19:50:00 -070026import android.content.ComponentName;
Jeff Sharkey76a02412017-10-24 16:55:04 -060027import android.net.Network;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080028import android.net.Uri;
Shreyas Basarge968ac752016-01-11 23:09:26 +000029import android.os.RemoteException;
Christopher Tate7060b042014-06-09 19:50:00 -070030import android.os.UserHandle;
Makoto Onuki0e1ce972019-10-09 12:51:55 -070031import android.text.format.DateFormat;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080032import android.util.ArraySet;
Christopher Tate616541d2017-07-26 14:27:38 -070033import android.util.Pair;
Dianne Hackborna47223f2017-03-30 13:49:13 -070034import android.util.Slog;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080035import android.util.TimeUtils;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080036import android.util.proto.ProtoOutputStream;
Christopher Tate7060b042014-06-09 19:50:00 -070037
Muhammad Qureshie9aec322020-01-28 10:27:18 -080038import com.android.internal.util.FrameworkStatsLog;
Christopher Tatea732f012017-10-26 17:26:53 -070039import com.android.server.LocalServices;
Dianne Hackborn342e6032017-04-13 18:04:31 -070040import com.android.server.job.GrantedUriPermissions;
Christopher Tatea732f012017-10-26 17:26:53 -070041import com.android.server.job.JobSchedulerInternal;
Christopher Tate616541d2017-07-26 14:27:38 -070042import com.android.server.job.JobSchedulerService;
Kweku Adams8845d012018-12-11 20:06:45 -080043import com.android.server.job.JobServerProtoEnums;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080044import com.android.server.job.JobStatusDumpProto;
45import com.android.server.job.JobStatusShortInfoProto;
Dianne Hackborn342e6032017-04-13 18:04:31 -070046
Christopher Tate7060b042014-06-09 19:50:00 -070047import java.io.PrintWriter;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070048import java.util.ArrayList;
Dianne Hackborna47223f2017-03-30 13:49:13 -070049import java.util.Arrays;
Makoto Onuki15407842018-01-19 14:23:11 -080050import java.util.function.Predicate;
Christopher Tate7060b042014-06-09 19:50:00 -070051
52/**
53 * Uniquely identifies a job internally.
54 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
55 * Contains current state of the requirements of the job, as well as a function to evaluate
56 * whether it's ready to run.
57 * This object is shared among the various controllers - hence why the different fields are atomic.
58 * This isn't strictly necessary because each controller is only interested in a specific field,
59 * and the receivers that are listening for global state change will all run on the main looper,
60 * but we don't enforce that so this is safer.
Kweku Adamsd14ce4d2018-10-19 11:40:55 -070061 *
62 * Test: atest com.android.server.job.controllers.JobStatusTest
Christopher Tate7060b042014-06-09 19:50:00 -070063 * @hide
64 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -080065public final class JobStatus {
Dianne Hackborna47223f2017-03-30 13:49:13 -070066 static final String TAG = "JobSchedulerService";
Christopher Tate616541d2017-07-26 14:27:38 -070067 static final boolean DEBUG = JobSchedulerService.DEBUG;
Dianne Hackborna47223f2017-03-30 13:49:13 -070068
Christopher Tate7060b042014-06-09 19:50:00 -070069 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
70 public static final long NO_EARLIEST_RUNTIME = 0L;
71
Kweku Adamsae9d6be2020-01-14 16:10:14 -080072 public static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0
73 public static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2
74 public static final int CONSTRAINT_BATTERY_NOT_LOW =
75 JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1
Kweku Adams32f44762018-11-02 16:58:32 -070076 static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW; // 1 << 3
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080077 static final int CONSTRAINT_TIMING_DELAY = 1<<31;
78 static final int CONSTRAINT_DEADLINE = 1<<30;
Kweku Adamsae9d6be2020-01-14 16:10:14 -080079 public static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080080 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
Kweku Adamsab8a9012019-01-28 15:42:09 -080081 static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
82 static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint
83 static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
Christopher Tate60977f42017-04-13 13:48:46 -070084
Kweku Adams8845d012018-12-11 20:06:45 -080085 /**
86 * The constraints that we want to log to statsd.
87 *
88 * Constraints that can be inferred from other atoms have been excluded to avoid logging too
89 * much information and to reduce redundancy:
90 *
91 * * CONSTRAINT_CHARGING can be inferred with PluggedStateChanged (Atom #32)
92 * * CONSTRAINT_BATTERY_NOT_LOW can be inferred with BatteryLevelChanged (Atom #30)
93 * * CONSTRAINT_CONNECTIVITY can be partially inferred with ConnectivityStateChanged
94 * (Atom #98) and BatterySaverModeStateChanged (Atom #20).
95 * * CONSTRAINT_DEVICE_NOT_DOZING can be mostly inferred with DeviceIdleModeStateChanged
96 * (Atom #21)
97 * * CONSTRAINT_BACKGROUND_NOT_RESTRICTED can be inferred with BatterySaverModeStateChanged
98 * (Atom #20)
99 */
100 private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
101 | CONSTRAINT_DEADLINE
102 | CONSTRAINT_IDLE
103 | CONSTRAINT_STORAGE_NOT_LOW
104 | CONSTRAINT_TIMING_DELAY
105 | CONSTRAINT_WITHIN_QUOTA;
106
Yao Chen26217e32019-04-04 16:34:24 -0700107 // TODO(b/129954980)
108 private static final boolean STATS_LOG_ENABLED = false;
109
Christopher Tate5d346052016-03-08 12:56:08 -0800110 // Soft override: ignore constraints like time that don't affect API availability
111 public static final int OVERRIDE_SOFT = 1;
112 // Full override: ignore all constraints including API-affecting like connectivity
113 public static final int OVERRIDE_FULL = 2;
114
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700115 /** If not specified, trigger update delay is 10 seconds. */
116 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
117
118 /** The minimum possible update delay is 1/2 second. */
119 public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
120
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800121 /** If not specified, trigger maximum delay is 2 minutes. */
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700122 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
123
124 /** The minimum possible update delay is 1 second. */
125 public static final long MIN_TRIGGER_MAX_DELAY = 1000;
126
Christopher Tate7060b042014-06-09 19:50:00 -0700127 final JobInfo job;
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700128 /**
129 * Uid of the package requesting this job. This can differ from the "source"
130 * uid when the job was scheduled on the app's behalf, such as with the jobs
131 * that underly Sync Manager operation.
132 */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000133 final int callingUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800134 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -0700135
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700136 /**
137 * Identity of the app in which the job is hosted.
138 */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000139 final String sourcePackageName;
140 final int sourceUserId;
141 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800142 final String sourceTag;
143
144 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000145
Dianne Hackborn342e6032017-04-13 18:04:31 -0700146 private GrantedUriPermissions uriPerms;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700147 private boolean prepared;
148
Christopher Tateb164f012017-04-26 15:41:37 -0700149 static final boolean DEBUG_PREPARE = true;
150 private Throwable unpreparedPoint = null;
151
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800152 /**
153 * Earliest point in the future at which this job will be eligible to run. A value of 0
154 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
155 */
156 private final long earliestRunTimeElapsedMillis;
157 /**
158 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
159 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
160 */
161 private final long latestRunTimeElapsedMillis;
162
Kweku Adamsc9793092019-04-30 11:54:48 -0700163 /**
164 * Valid only for periodic jobs. The original latest point in the future at which this
165 * job was expected to run.
166 */
167 private long mOriginalLatestRunTimeElapsedMillis;
168
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800169 /** How many times this job has failed, used to compute back-off. */
170 private final int numFailures;
171
Christopher Tatea732f012017-10-26 17:26:53 -0700172 /**
Christopher Tatea732f012017-10-26 17:26:53 -0700173 * Which app standby bucket this job's app is in. Updated when the app is moved to a
174 * different bucket.
175 */
176 private int standbyBucket;
177
178 /**
179 * Debugging: timestamp if we ever defer this job based on standby bucketing, this
180 * is when we did so.
181 */
182 private long whenStandbyDeferred;
183
Kweku Adams41cb3322019-06-26 14:42:26 -0700184 /** The first time this job was force batched. */
185 private long mFirstForceBatchedTimeElapsed;
186
Christopher Tate7060b042014-06-09 19:50:00 -0700187 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800188 final int requiredConstraints;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700189 private final int mRequiredConstraintsOfInterest;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800190 int satisfiedConstraints = 0;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700191 private int mSatisfiedConstraintsOfInterest = 0;
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800192 /**
193 * Set of constraints that must be satisfied for the job if/because it's in the RESTRICTED
194 * bucket.
195 */
196 private int mDynamicConstraints = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800197
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700198 // Set to true if doze constraint was satisfied due to app being whitelisted.
199 public boolean dozeWhitelisted;
200
Christopher Tate20afddd2018-02-28 15:19:19 -0800201 // Set to true when the app is "active" per AppStateTracker
202 public boolean uidActive;
203
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700204 /**
205 * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
206 */
207 public static final int TRACKING_BATTERY = 1<<0;
208 /**
209 * Flag for {@link #trackingControllers}: the network connectivity controller is currently
210 * tracking this job.
211 */
212 public static final int TRACKING_CONNECTIVITY = 1<<1;
213 /**
214 * Flag for {@link #trackingControllers}: the content observer controller is currently
215 * tracking this job.
216 */
217 public static final int TRACKING_CONTENT = 1<<2;
218 /**
219 * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job.
220 */
221 public static final int TRACKING_IDLE = 1<<3;
222 /**
223 * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job.
224 */
225 public static final int TRACKING_STORAGE = 1<<4;
226 /**
227 * Flag for {@link #trackingControllers}: the time controller is currently tracking this job.
228 */
229 public static final int TRACKING_TIME = 1<<5;
Kweku Adams4836f9d2018-11-12 17:04:17 -0800230 /**
231 * Flag for {@link #trackingControllers}: the quota controller is currently tracking this job.
232 */
233 public static final int TRACKING_QUOTA = 1 << 6;
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700234
235 /**
236 * Bit mask of controllers that are currently tracking the job.
237 */
238 private int trackingControllers;
239
Makoto Onuki15407842018-01-19 14:23:11 -0800240 /**
241 * Flag for {@link #mInternalFlags}: this job was scheduled when the app that owns the job
242 * service (not necessarily the caller) was in the foreground and the job has no time
243 * constraints, which makes it exempted from the battery saver job restriction.
244 *
245 * @hide
246 */
247 public static final int INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION = 1 << 0;
248
249 /**
250 * Versatile, persistable flags for a job that's updated within the system server,
251 * as opposed to {@link JobInfo#flags} that's set by callers.
252 */
253 private int mInternalFlags;
254
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800255 // These are filled in by controllers when preparing for execution.
256 public ArraySet<Uri> changedUris;
257 public ArraySet<String> changedAuthorities;
Jeff Sharkey76a02412017-10-24 16:55:04 -0600258 public Network network;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800259
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800260 public int lastEvaluatedPriority;
261
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700262 // If non-null, this is work that has been enqueued for the job.
263 public ArrayList<JobWorkItem> pendingWork;
264
265 // If non-null, this is work that is currently being executed.
266 public ArrayList<JobWorkItem> executingWork;
267
268 public int nextPendingWorkId = 1;
269
Christopher Tate5d346052016-03-08 12:56:08 -0800270 // Used by shell commands
271 public int overrideState = 0;
272
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700273 // When this job was enqueued, for ordering. (in elapsedRealtimeMillis)
274 public long enqueueTime;
275
276 // Metrics about queue latency. (in uptimeMillis)
Christopher Tate7234fc62017-04-03 17:36:07 -0700277 public long madePending;
278 public long madeActive;
279
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800280 /**
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700281 * Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
282 * for dumpsys.
283 */
284 private long mLastSuccessfulRunTime;
285
286 /**
287 * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
288 */
289 private long mLastFailedRunTime;
290
291 /**
Christopher Tate616541d2017-07-26 14:27:38 -0700292 * Transient: when a job is inflated from disk before we have a reliable RTC clock time,
293 * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent
294 * store in UTC so that we can fix up the job's scheduling criteria once we get a good
295 * wall-clock time. If we have to persist the job again before the clock has been updated,
296 * we record these times again rather than calculating based on the earliest/latest elapsed
297 * time base figures.
298 *
299 * 'first' is the earliest/delay time, and 'second' is the latest/deadline time.
300 */
301 private Pair<Long, Long> mPersistedUtcTimes;
302
303 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800304 * For use only by ContentObserverController: state it is maintaining about content URIs
305 * being observed.
306 */
307 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -0700308
Kweku Adams316b1412019-06-14 11:34:37 -0700309 private long mTotalNetworkDownloadBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
310 private long mTotalNetworkUploadBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600311
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700312 /////// Booleans that track if a job is ready to run. They should be updated whenever dependent
313 /////// states change.
314
315 /**
316 * The deadline for the job has passed. This is only good for non-periodic jobs. A periodic job
317 * should only run if its constraints are satisfied.
318 * Computed as: NOT periodic AND has deadline constraint AND deadline constraint satisfied.
319 */
320 private boolean mReadyDeadlineSatisfied;
321
322 /**
323 * The device isn't Dozing or this job will be in the foreground. This implicit constraint must
324 * be satisfied.
325 */
326 private boolean mReadyNotDozing;
327
328 /**
329 * The job is not restricted from running in the background (due to Battery Saver). This
330 * implicit constraint must be satisfied.
331 */
332 private boolean mReadyNotRestrictedInBg;
333
Kweku Adams4836f9d2018-11-12 17:04:17 -0800334 /** The job is within its quota based on its standby bucket. */
335 private boolean mReadyWithinQuota;
336
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800337 /** The job's dynamic requirements have been satisfied. */
338 private boolean mReadyDynamicSatisfied;
339
Christopher Tate7060b042014-06-09 19:50:00 -0700340 /** Provide a handle to the service that this job will be run on. */
341 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000342 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700343 }
344
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700345 /**
346 * Core constructor for JobStatus instances. All other ctors funnel down to this one.
347 *
348 * @param job The actual requested parameters for the job
349 * @param callingUid Identity of the app that is scheduling the job. This may not be the
350 * app in which the job is implemented; such as with sync jobs.
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700351 * @param sourcePackageName The package name of the app in which the job will run.
352 * @param sourceUserId The user in which the job will run
353 * @param standbyBucket The standby bucket that the source package is currently assigned to,
354 * cached here for speed of handling during runnability evaluations (and updated when bucket
355 * assignments are changed)
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700356 * @param tag A string associated with the job for debugging/logging purposes.
357 * @param numFailures Count of how many times this job has requested a reschedule because
358 * its work was not yet finished.
359 * @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job
360 * is to be considered runnable
361 * @param latestRunTimeElapsedMillis Milestone: point in time at which the job will be
362 * considered overdue
363 * @param lastSuccessfulRunTime When did we last run this job to completion?
364 * @param lastFailedRunTime When did we last run this job only to have it stop incomplete?
365 * @param internalFlags Non-API property flags about this job
366 */
Kweku Adams8843a2812019-07-02 15:30:23 -0700367 private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
Kweku Adams6c5dc642019-07-25 10:29:38 -0700368 int sourceUserId, int standbyBucket, String tag, int numFailures,
Christopher Tatea732f012017-10-26 17:26:53 -0700369 long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800370 long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
Christopher Tate7060b042014-06-09 19:50:00 -0700371 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000372 this.callingUid = callingUid;
Christopher Tatea732f012017-10-26 17:26:53 -0700373 this.standbyBucket = standbyBucket;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000374
375 int tempSourceUid = -1;
376 if (sourceUserId != -1 && sourcePackageName != null) {
377 try {
378 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
379 sourceUserId);
380 } catch (RemoteException ex) {
381 // Can't happen, PackageManager runs in the same process.
382 }
383 }
384 if (tempSourceUid == -1) {
385 this.sourceUid = callingUid;
386 this.sourceUserId = UserHandle.getUserId(callingUid);
387 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800388 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000389 } else {
390 this.sourceUid = tempSourceUid;
391 this.sourceUserId = sourceUserId;
392 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800393 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000394 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800395
Shreyas Basargeeda34e42016-04-26 00:14:02 +0100396 this.batteryName = this.sourceTag != null
397 ? this.sourceTag + ":" + job.getService().getPackageName()
398 : job.getService().flattenToShortString();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800399 this.tag = "*job*/" + this.batteryName;
400
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800401 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
402 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
Kweku Adamsc9793092019-04-30 11:54:48 -0700403 this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800404 this.numFailures = numFailures;
405
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800406 int requiredConstraints = job.getConstraintFlags();
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700407 if (job.getRequiredNetwork() != null) {
408 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800409 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800410 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
411 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
412 }
413 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
414 requiredConstraints |= CONSTRAINT_DEADLINE;
415 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800416 if (job.getTriggerContentUris() != null) {
417 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
418 }
419 this.requiredConstraints = requiredConstraints;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700420 mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
421 mReadyNotDozing = (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800422 mReadyDynamicSatisfied = true;
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700423
424 mLastSuccessfulRunTime = lastSuccessfulRunTime;
425 mLastFailedRunTime = lastFailedRunTime;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600426
Makoto Onuki15407842018-01-19 14:23:11 -0800427 mInternalFlags = internalFlags;
428
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600429 updateEstimatedNetworkBytesLocked();
Jeff Sharkeyfb0f9712018-02-21 20:27:48 -0700430
431 if (job.getRequiredNetwork() != null) {
432 // Later, when we check if a given network satisfies the required
433 // network, we need to know the UID that is requesting it, so push
434 // our source UID into place.
435 job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
436 }
Christopher Tate7060b042014-06-09 19:50:00 -0700437 }
438
Christopher Tate616541d2017-07-26 14:27:38 -0700439 /** Copy constructor: used specifically when cloning JobStatus objects for persistence,
440 * so we preserve RTC window bounds if the source object has them. */
Matthew Williams0cc76542015-10-16 21:04:51 -0700441 public JobStatus(JobStatus jobStatus) {
Kweku Adams8843a2812019-07-02 15:30:23 -0700442 this(jobStatus.getJob(), jobStatus.getUid(),
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800443 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Kweku Adams6c5dc642019-07-25 10:29:38 -0700444 jobStatus.getStandbyBucket(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800445 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700446 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
Makoto Onuki15407842018-01-19 14:23:11 -0800447 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
448 jobStatus.getInternalFlags());
Christopher Tate616541d2017-07-26 14:27:38 -0700449 mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
450 if (jobStatus.mPersistedUtcTimes != null) {
451 if (DEBUG) {
452 Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here"));
453 }
454 }
Christopher Tate7060b042014-06-09 19:50:00 -0700455 }
456
457 /**
458 * Create a new JobStatus that was loaded from disk. We ignore the provided
459 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
460 * from the {@link com.android.server.job.JobStore} and still want to respect its
461 * wallclock runtime rather than resetting it on every boot.
Christopher Tatea732f012017-10-26 17:26:53 -0700462 * We consider a freshly loaded job to no longer be in back-off, and the associated
463 * standby bucket is whatever the OS thinks it should be at this moment.
Christopher Tate7060b042014-06-09 19:50:00 -0700464 */
Christopher Tatea732f012017-10-26 17:26:53 -0700465 public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId,
Kweku Adams6c5dc642019-07-25 10:29:38 -0700466 int standbyBucket, String sourceTag,
Christopher Tatea732f012017-10-26 17:26:53 -0700467 long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
Christopher Tate616541d2017-07-26 14:27:38 -0700468 long lastSuccessfulRunTime, long lastFailedRunTime,
Makoto Onuki15407842018-01-19 14:23:11 -0800469 Pair<Long, Long> persistedExecutionTimesUTC,
470 int innerFlags) {
Kweku Adams8843a2812019-07-02 15:30:23 -0700471 this(job, callingUid, sourcePkgName, sourceUserId,
Kweku Adams6c5dc642019-07-25 10:29:38 -0700472 standbyBucket,
Christopher Tatea732f012017-10-26 17:26:53 -0700473 sourceTag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700474 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800475 lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
Christopher Tate616541d2017-07-26 14:27:38 -0700476
477 // Only during initial inflation do we record the UTC-timebase execution bounds
478 // read from the persistent store. If we ever have to recreate the JobStatus on
479 // the fly, it means we're rescheduling the job; and this means that the calculated
480 // elapsed timebase bounds intrinsically become correct.
481 this.mPersistedUtcTimes = persistedExecutionTimesUTC;
482 if (persistedExecutionTimesUTC != null) {
483 if (DEBUG) {
484 Slog.i(TAG, "+ restored job with RTC times because of bad boot clock");
485 }
486 }
Christopher Tate7060b042014-06-09 19:50:00 -0700487 }
488
489 /** Create a new job to be rescheduled with the provided parameters. */
Kweku Adams6c5dc642019-07-25 10:29:38 -0700490 public JobStatus(JobStatus rescheduling,
Christopher Tatea732f012017-10-26 17:26:53 -0700491 long newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700492 long newLatestRuntimeElapsedMillis, int backoffAttempt,
493 long lastSuccessfulRunTime, long lastFailedRunTime) {
Kweku Adams8843a2812019-07-02 15:30:23 -0700494 this(rescheduling.job, rescheduling.getUid(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800495 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
Kweku Adams6c5dc642019-07-25 10:29:38 -0700496 rescheduling.getStandbyBucket(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800497 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700498 newLatestRuntimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800499 lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags());
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800500 }
Christopher Tate7060b042014-06-09 19:50:00 -0700501
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800502 /**
503 * Create a newly scheduled job.
504 * @param callingUid Uid of the package that scheduled this job.
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700505 * @param sourcePkg Package name of the app that will actually run the job. Null indicates
506 * that the calling package is the source.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800507 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
Christopher Tatea732f012017-10-26 17:26:53 -0700508 * caller.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800509 */
Christopher Tatea732f012017-10-26 17:26:53 -0700510 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePkg,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800511 int sourceUserId, String tag) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700512 final long elapsedNow = sElapsedRealtimeClock.millis();
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800513 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
514 if (job.isPeriodic()) {
Kweku Adams966e72b2019-05-30 14:45:39 -0700515 // Make sure period is in the interval [min_possible_period, max_possible_period].
516 final long period = Math.max(JobInfo.getMinPeriodMillis(),
517 Math.min(JobSchedulerService.MAX_ALLOWED_PERIOD_MS, job.getIntervalMillis()));
518 latestRunTimeElapsedMillis = elapsedNow + period;
519 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis
520 // Make sure flex is in the interval [min_possible_flex, period].
521 - Math.max(JobInfo.getMinFlexMillis(), Math.min(period, job.getFlexMillis()));
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800522 } else {
523 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
524 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
525 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
526 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
527 }
Christopher Tatea732f012017-10-26 17:26:53 -0700528 String jobPackage = (sourcePkg != null) ? sourcePkg : job.getService().getPackageName();
529
530 int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
531 sourceUserId, elapsedNow);
532 JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
Kweku Adams8843a2812019-07-02 15:30:23 -0700533 return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
Kweku Adams6c5dc642019-07-25 10:29:38 -0700534 standbyBucket, tag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700535 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800536 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
537 /*innerFlags=*/ 0);
Christopher Tate7060b042014-06-09 19:50:00 -0700538 }
539
Christopher Tate1b1fca82019-08-14 16:59:33 -0700540 public void enqueueWorkLocked(JobWorkItem work) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700541 if (pendingWork == null) {
542 pendingWork = new ArrayList<>();
543 }
544 work.setWorkId(nextPendingWorkId);
545 nextPendingWorkId++;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700546 if (work.getIntent() != null
547 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) {
Christopher Tate1b1fca82019-08-14 16:59:33 -0700548 work.setGrants(GrantedUriPermissions.createFromIntent(work.getIntent(), sourceUid,
Dianne Hackborn342e6032017-04-13 18:04:31 -0700549 sourcePackageName, sourceUserId, toShortString()));
550 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700551 pendingWork.add(work);
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600552 updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700553 }
554
555 public JobWorkItem dequeueWorkLocked() {
556 if (pendingWork != null && pendingWork.size() > 0) {
557 JobWorkItem work = pendingWork.remove(0);
558 if (work != null) {
559 if (executingWork == null) {
560 executingWork = new ArrayList<>();
561 }
562 executingWork.add(work);
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700563 work.bumpDeliveryCount();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700564 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600565 updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700566 return work;
567 }
568 return null;
569 }
570
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700571 public boolean hasWorkLocked() {
572 return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
573 }
574
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700575 public boolean hasExecutingWorkLocked() {
576 return executingWork != null && executingWork.size() > 0;
577 }
578
Christopher Tate1b1fca82019-08-14 16:59:33 -0700579 private static void ungrantWorkItem(JobWorkItem work) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700580 if (work.getGrants() != null) {
Christopher Tate1b1fca82019-08-14 16:59:33 -0700581 ((GrantedUriPermissions)work.getGrants()).revoke();
Dianne Hackborn342e6032017-04-13 18:04:31 -0700582 }
583 }
584
Christopher Tate1b1fca82019-08-14 16:59:33 -0700585 public boolean completeWorkLocked(int workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700586 if (executingWork != null) {
587 final int N = executingWork.size();
588 for (int i = 0; i < N; i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700589 JobWorkItem work = executingWork.get(i);
590 if (work.getWorkId() == workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700591 executingWork.remove(i);
Christopher Tate1b1fca82019-08-14 16:59:33 -0700592 ungrantWorkItem(work);
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700593 return true;
594 }
595 }
596 }
597 return false;
598 }
599
Christopher Tate1b1fca82019-08-14 16:59:33 -0700600 private static void ungrantWorkList(ArrayList<JobWorkItem> list) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700601 if (list != null) {
602 final int N = list.size();
603 for (int i = 0; i < N; i++) {
Christopher Tate1b1fca82019-08-14 16:59:33 -0700604 ungrantWorkItem(list.get(i));
Dianne Hackborn342e6032017-04-13 18:04:31 -0700605 }
606 }
607 }
608
Christopher Tate1b1fca82019-08-14 16:59:33 -0700609 public void stopTrackingJobLocked(JobStatus incomingJob) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700610 if (incomingJob != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700611 // We are replacing with a new job -- transfer the work! We do any executing
612 // work first, since that was originally at the front of the pending work.
613 if (executingWork != null && executingWork.size() > 0) {
614 incomingJob.pendingWork = executingWork;
615 }
616 if (incomingJob.pendingWork == null) {
617 incomingJob.pendingWork = pendingWork;
618 } else if (pendingWork != null && pendingWork.size() > 0) {
619 incomingJob.pendingWork.addAll(pendingWork);
620 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700621 pendingWork = null;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700622 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700623 incomingJob.nextPendingWorkId = nextPendingWorkId;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600624 incomingJob.updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700625 } else {
626 // We are completely stopping the job... need to clean up work.
Christopher Tate1b1fca82019-08-14 16:59:33 -0700627 ungrantWorkList(pendingWork);
Dianne Hackborn342e6032017-04-13 18:04:31 -0700628 pendingWork = null;
Christopher Tate1b1fca82019-08-14 16:59:33 -0700629 ungrantWorkList(executingWork);
Dianne Hackborn342e6032017-04-13 18:04:31 -0700630 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700631 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600632 updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700633 }
634
Christopher Tate1b1fca82019-08-14 16:59:33 -0700635 public void prepareLocked() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700636 if (prepared) {
637 Slog.wtf(TAG, "Already prepared: " + this);
638 return;
639 }
640 prepared = true;
Christopher Tateb164f012017-04-26 15:41:37 -0700641 if (DEBUG_PREPARE) {
642 unpreparedPoint = null;
643 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700644 final ClipData clip = job.getClipData();
645 if (clip != null) {
Christopher Tate1b1fca82019-08-14 16:59:33 -0700646 uriPerms = GrantedUriPermissions.createFromClip(clip, sourceUid, sourcePackageName,
Dianne Hackborn342e6032017-04-13 18:04:31 -0700647 sourceUserId, job.getClipGrantFlags(), toShortString());
Dianne Hackborna47223f2017-03-30 13:49:13 -0700648 }
649 }
650
Christopher Tate1b1fca82019-08-14 16:59:33 -0700651 public void unprepareLocked() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700652 if (!prepared) {
653 Slog.wtf(TAG, "Hasn't been prepared: " + this);
Christopher Tateb164f012017-04-26 15:41:37 -0700654 if (DEBUG_PREPARE && unpreparedPoint != null) {
655 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint);
656 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700657 return;
658 }
659 prepared = false;
Christopher Tateb164f012017-04-26 15:41:37 -0700660 if (DEBUG_PREPARE) {
661 unpreparedPoint = new Throwable().fillInStackTrace();
662 }
Dianne Hackborn342e6032017-04-13 18:04:31 -0700663 if (uriPerms != null) {
Christopher Tate1b1fca82019-08-14 16:59:33 -0700664 uriPerms.revoke();
Dianne Hackborn342e6032017-04-13 18:04:31 -0700665 uriPerms = null;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700666 }
667 }
668
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700669 public boolean isPreparedLocked() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700670 return prepared;
671 }
672
Christopher Tate7060b042014-06-09 19:50:00 -0700673 public JobInfo getJob() {
674 return job;
675 }
676
677 public int getJobId() {
678 return job.getId();
679 }
680
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700681 public void printUniqueId(PrintWriter pw) {
682 UserHandle.formatUid(pw, callingUid);
683 pw.print("/");
684 pw.print(job.getId());
685 }
686
Christopher Tate7060b042014-06-09 19:50:00 -0700687 public int getNumFailures() {
688 return numFailures;
689 }
690
691 public ComponentName getServiceComponent() {
692 return job.getService();
693 }
694
Shreyas Basarge968ac752016-01-11 23:09:26 +0000695 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000696 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000697 }
698
699 public int getSourceUid() {
700 return sourceUid;
701 }
702
703 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000704 return sourceUserId;
705 }
706
Christopher Tate7060b042014-06-09 19:50:00 -0700707 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000708 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700709 }
710
Kweku Adamsbbb04592019-08-05 15:17:23 -0700711 /**
712 * Returns an appropriate standby bucket for the job, taking into account any standby
713 * exemptions.
714 */
715 public int getEffectiveStandbyBucket() {
716 if (uidActive || getJob().isExemptedFromAppStandby()) {
717 // Treat these cases as if they're in the ACTIVE bucket so that they get throttled
718 // like other ACTIVE apps.
719 return ACTIVE_INDEX;
720 }
721 return getStandbyBucket();
722 }
723
724 /** Returns the real standby bucket of the job. */
Christopher Tatea732f012017-10-26 17:26:53 -0700725 public int getStandbyBucket() {
726 return standbyBucket;
727 }
728
Christopher Tatea732f012017-10-26 17:26:53 -0700729 public void setStandbyBucket(int newBucket) {
730 standbyBucket = newBucket;
731 }
732
733 // Called only by the standby monitoring code
734 public long getWhenStandbyDeferred() {
735 return whenStandbyDeferred;
736 }
737
738 // Called only by the standby monitoring code
739 public void setWhenStandbyDeferred(long now) {
740 whenStandbyDeferred = now;
741 }
742
Kweku Adams41cb3322019-06-26 14:42:26 -0700743 /**
744 * Returns the first time this job was force batched, in the elapsed realtime timebase. Will be
745 * 0 if this job was never force batched.
746 */
747 public long getFirstForceBatchedTimeElapsed() {
748 return mFirstForceBatchedTimeElapsed;
749 }
750
751 public void setFirstForceBatchedTimeElapsed(long now) {
752 mFirstForceBatchedTimeElapsed = now;
753 }
754
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800755 public String getSourceTag() {
756 return sourceTag;
757 }
758
Christopher Tate7060b042014-06-09 19:50:00 -0700759 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000760 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700761 }
762
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800763 public String getBatteryName() {
764 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700765 }
766
767 public String getTag() {
768 return tag;
769 }
770
Shreyas Basarge5db09082016-01-07 13:38:29 +0000771 public int getPriority() {
772 return job.getPriority();
773 }
Christopher Tate7060b042014-06-09 19:50:00 -0700774
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600775 public int getFlags() {
776 return job.getFlags();
777 }
778
Makoto Onuki15407842018-01-19 14:23:11 -0800779 public int getInternalFlags() {
780 return mInternalFlags;
781 }
782
783 public void addInternalFlags(int flags) {
784 mInternalFlags |= flags;
785 }
786
Serik Beketayev75915d12018-08-01 16:56:59 -0700787 public int getSatisfiedConstraintFlags() {
788 return satisfiedConstraints;
789 }
790
Makoto Onuki15407842018-01-19 14:23:11 -0800791 public void maybeAddForegroundExemption(Predicate<Integer> uidForegroundChecker) {
792 // Jobs with time constraints shouldn't be exempted.
793 if (job.hasEarlyConstraint() || job.hasLateConstraint()) {
794 return;
795 }
796 // Already exempted, skip the foreground check.
797 if ((mInternalFlags & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
798 return;
799 }
800 if (uidForegroundChecker.test(getSourceUid())) {
801 addInternalFlags(INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION);
802 }
803 }
804
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600805 private void updateEstimatedNetworkBytesLocked() {
Kweku Adams316b1412019-06-14 11:34:37 -0700806 mTotalNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes();
807 mTotalNetworkUploadBytes = job.getEstimatedNetworkUploadBytes();
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600808
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600809 if (pendingWork != null) {
810 for (int i = 0; i < pendingWork.size(); i++) {
Kweku Adams316b1412019-06-14 11:34:37 -0700811 if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
812 // If any component of the job has unknown usage, we don't have a
813 // complete picture of what data will be used, and we have to treat the
814 // entire up/download as unknown.
815 long downloadBytes = pendingWork.get(i).getEstimatedNetworkDownloadBytes();
816 if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
817 mTotalNetworkDownloadBytes += downloadBytes;
818 }
819 }
820 if (mTotalNetworkUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
821 // If any component of the job has unknown usage, we don't have a
822 // complete picture of what data will be used, and we have to treat the
823 // entire up/download as unknown.
824 long uploadBytes = pendingWork.get(i).getEstimatedNetworkUploadBytes();
825 if (uploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
826 mTotalNetworkUploadBytes += uploadBytes;
827 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600828 }
829 }
830 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600831 }
832
Kweku Adams316b1412019-06-14 11:34:37 -0700833 public long getEstimatedNetworkDownloadBytes() {
834 return mTotalNetworkDownloadBytes;
835 }
836
837 public long getEstimatedNetworkUploadBytes() {
838 return mTotalNetworkUploadBytes;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600839 }
840
Christopher Tate60977f42017-04-13 13:48:46 -0700841 /** Does this job have any sort of networking constraint? */
Christopher Tate7060b042014-06-09 19:50:00 -0700842 public boolean hasConnectivityConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800843 // No need to check mDynamicConstraints since connectivity will only be in that list if
844 // it's already in the requiredConstraints list.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800845 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700846 }
847
Christopher Tate7060b042014-06-09 19:50:00 -0700848 public boolean hasChargingConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800849 return hasConstraint(CONSTRAINT_CHARGING);
Christopher Tate7060b042014-06-09 19:50:00 -0700850 }
851
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800852 public boolean hasBatteryNotLowConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800853 return hasConstraint(CONSTRAINT_BATTERY_NOT_LOW);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800854 }
855
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800856 /** Returns true if the job requires charging OR battery not low. */
857 boolean hasPowerConstraint() {
858 return hasConstraint(CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800859 }
860
Dianne Hackborn532ea262017-03-17 17:50:55 -0700861 public boolean hasStorageNotLowConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800862 return hasConstraint(CONSTRAINT_STORAGE_NOT_LOW);
Dianne Hackborn532ea262017-03-17 17:50:55 -0700863 }
864
Christopher Tate7060b042014-06-09 19:50:00 -0700865 public boolean hasTimingDelayConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800866 return hasConstraint(CONSTRAINT_TIMING_DELAY);
Christopher Tate7060b042014-06-09 19:50:00 -0700867 }
868
869 public boolean hasDeadlineConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800870 return hasConstraint(CONSTRAINT_DEADLINE);
Christopher Tate7060b042014-06-09 19:50:00 -0700871 }
872
873 public boolean hasIdleConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800874 return hasConstraint(CONSTRAINT_IDLE);
Christopher Tate7060b042014-06-09 19:50:00 -0700875 }
876
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800877 public boolean hasContentTriggerConstraint() {
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800878 // No need to check mDynamicConstraints since content trigger will only be in that list if
879 // it's already in the requiredConstraints list.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800880 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800881 }
882
Kweku Adamsae9d6be2020-01-14 16:10:14 -0800883 /**
884 * Checks both {@link #requiredConstraints} and {@link #mDynamicConstraints} to see if this job
885 * requires the specified constraint.
886 */
887 private boolean hasConstraint(int constraint) {
888 return (requiredConstraints & constraint) != 0 || (mDynamicConstraints & constraint) != 0;
889 }
890
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700891 public long getTriggerContentUpdateDelay() {
892 long time = job.getTriggerContentUpdateDelay();
893 if (time < 0) {
894 return DEFAULT_TRIGGER_UPDATE_DELAY;
895 }
896 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
897 }
898
899 public long getTriggerContentMaxDelay() {
900 long time = job.getTriggerContentMaxDelay();
901 if (time < 0) {
902 return DEFAULT_TRIGGER_MAX_DELAY;
903 }
904 return Math.max(time, MIN_TRIGGER_MAX_DELAY);
905 }
906
Matthew Williams900c67f2014-07-09 12:46:53 -0700907 public boolean isPersisted() {
908 return job.isPersisted();
909 }
910
Christopher Tate7060b042014-06-09 19:50:00 -0700911 public long getEarliestRunTime() {
912 return earliestRunTimeElapsedMillis;
913 }
914
915 public long getLatestRunTimeElapsed() {
916 return latestRunTimeElapsedMillis;
917 }
918
Kweku Adamsc9793092019-04-30 11:54:48 -0700919 public long getOriginalLatestRunTimeElapsed() {
920 return mOriginalLatestRunTimeElapsedMillis;
921 }
922
923 public void setOriginalLatestRunTimeElapsed(long latestRunTimeElapsed) {
924 mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsed;
925 }
926
Jeff Sharkey9252b342018-01-19 07:58:35 +0900927 /**
928 * Return the fractional position of "now" within the "run time" window of
929 * this job.
930 * <p>
931 * For example, if the earliest run time was 10 minutes ago, and the latest
932 * run time is 30 minutes from now, this would return 0.25.
933 * <p>
934 * If the job has no window defined, returns 1. When only an earliest or
935 * latest time is defined, it's treated as an infinitely small window at
936 * that time.
937 */
938 public float getFractionRunTime() {
939 final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
940 if (earliestRunTimeElapsedMillis == 0 && latestRunTimeElapsedMillis == Long.MAX_VALUE) {
941 return 1;
942 } else if (earliestRunTimeElapsedMillis == 0) {
943 return now >= latestRunTimeElapsedMillis ? 1 : 0;
944 } else if (latestRunTimeElapsedMillis == Long.MAX_VALUE) {
945 return now >= earliestRunTimeElapsedMillis ? 1 : 0;
946 } else {
947 if (now <= earliestRunTimeElapsedMillis) {
948 return 0;
949 } else if (now >= latestRunTimeElapsedMillis) {
950 return 1;
951 } else {
952 return (float) (now - earliestRunTimeElapsedMillis)
953 / (float) (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis);
954 }
955 }
956 }
957
Christopher Tate616541d2017-07-26 14:27:38 -0700958 public Pair<Long, Long> getPersistedUtcTimes() {
959 return mPersistedUtcTimes;
960 }
961
962 public void clearPersistedUtcTimes() {
963 mPersistedUtcTimes = null;
964 }
965
Kweku Adams4836f9d2018-11-12 17:04:17 -0800966 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800967 boolean setChargingConstraintSatisfied(boolean state) {
968 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
969 }
970
Kweku Adams4836f9d2018-11-12 17:04:17 -0800971 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800972 boolean setBatteryNotLowConstraintSatisfied(boolean state) {
973 return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
974 }
975
Kweku Adams4836f9d2018-11-12 17:04:17 -0800976 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackborn532ea262017-03-17 17:50:55 -0700977 boolean setStorageNotLowConstraintSatisfied(boolean state) {
978 return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
979 }
980
Kweku Adams4836f9d2018-11-12 17:04:17 -0800981 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800982 boolean setTimingDelayConstraintSatisfied(boolean state) {
983 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
984 }
985
Kweku Adams4836f9d2018-11-12 17:04:17 -0800986 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800987 boolean setDeadlineConstraintSatisfied(boolean state) {
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700988 if (setConstraintSatisfied(CONSTRAINT_DEADLINE, state)) {
989 // The constraint was changed. Update the ready flag.
990 mReadyDeadlineSatisfied = !job.isPeriodic() && hasDeadlineConstraint() && state;
991 return true;
992 }
993 return false;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800994 }
995
Kweku Adams4836f9d2018-11-12 17:04:17 -0800996 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800997 boolean setIdleConstraintSatisfied(boolean state) {
998 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
999 }
1000
Kweku Adams4836f9d2018-11-12 17:04:17 -08001001 /** @return true if the constraint was changed, false otherwise. */
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -06001002 boolean setConnectivityConstraintSatisfied(boolean state) {
1003 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
1004 }
1005
Kweku Adams4836f9d2018-11-12 17:04:17 -08001006 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001007 boolean setContentTriggerConstraintSatisfied(boolean state) {
1008 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
1009 }
1010
Kweku Adams4836f9d2018-11-12 17:04:17 -08001011 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackborn7ab40252016-06-15 17:30:24 -07001012 boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
1013 dozeWhitelisted = whitelisted;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001014 if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state)) {
1015 // The constraint was changed. Update the ready flag.
1016 mReadyNotDozing = state || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
1017 return true;
1018 }
1019 return false;
Amith Yamasanicb926fc2016-03-14 17:15:20 -07001020 }
1021
Kweku Adams4836f9d2018-11-12 17:04:17 -08001022 /** @return true if the constraint was changed, false otherwise. */
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001023 boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) {
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001024 if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state)) {
1025 // The constraint was changed. Update the ready flag.
1026 mReadyNotRestrictedInBg = state;
1027 return true;
1028 }
1029 return false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001030 }
1031
Kweku Adams4836f9d2018-11-12 17:04:17 -08001032 /** @return true if the constraint was changed, false otherwise. */
1033 boolean setQuotaConstraintSatisfied(boolean state) {
1034 if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, state)) {
1035 // The constraint was changed. Update the ready flag.
1036 mReadyWithinQuota = state;
1037 return true;
1038 }
1039 return false;
1040 }
1041
1042 /** @return true if the state was changed, false otherwise. */
Christopher Tate20afddd2018-02-28 15:19:19 -08001043 boolean setUidActive(final boolean newActiveState) {
1044 if (newActiveState != uidActive) {
1045 uidActive = newActiveState;
1046 return true;
1047 }
1048 return false; /* unchanged */
1049 }
1050
Kweku Adams4836f9d2018-11-12 17:04:17 -08001051 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001052 boolean setConstraintSatisfied(int constraint, boolean state) {
1053 boolean old = (satisfiedConstraints&constraint) != 0;
1054 if (old == state) {
1055 return false;
1056 }
1057 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001058 mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001059 mReadyDynamicSatisfied =
1060 mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
Yao Chen26217e32019-04-04 16:34:24 -07001061 if (STATS_LOG_ENABLED && (STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
Muhammad Qureshie9aec322020-01-28 10:27:18 -08001062 FrameworkStatsLog.write_non_chained(
1063 FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
Kweku Adams8845d012018-12-11 20:06:45 -08001064 sourceUid, null, getBatteryName(), getProtoConstraint(constraint),
Muhammad Qureshie9aec322020-01-28 10:27:18 -08001065 state ? FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
1066 : FrameworkStatsLog
1067 .SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
Kweku Adams8845d012018-12-11 20:06:45 -08001068 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001069 return true;
1070 }
1071
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001072 boolean isConstraintSatisfied(int constraint) {
1073 return (satisfiedConstraints&constraint) != 0;
1074 }
1075
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001076 boolean clearTrackingController(int which) {
1077 if ((trackingControllers&which) != 0) {
1078 trackingControllers &= ~which;
1079 return true;
1080 }
1081 return false;
1082 }
1083
1084 void setTrackingController(int which) {
1085 trackingControllers |= which;
1086 }
1087
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001088 /**
1089 * Indicates that this job cannot run without the specified constraint. This is evaluated
1090 * separately from the job's explicitly requested constraints and MUST be satisfied before
1091 * the job can run if the app doesn't have quota.
1092 *
1093 */
1094 public void addDynamicConstraint(int constraint) {
1095 if (constraint == CONSTRAINT_WITHIN_QUOTA) {
1096 Slog.wtf(TAG, "Tried to set quota as a dynamic constraint");
1097 return;
1098 }
1099
1100 // Connectivity and content trigger are special since they're only valid to add if the
1101 // job has requested network or specific content URIs. Adding these constraints to jobs
1102 // that don't need them doesn't make sense.
1103 if ((constraint == CONSTRAINT_CONNECTIVITY && !hasConnectivityConstraint())
1104 || (constraint == CONSTRAINT_CONTENT_TRIGGER && !hasContentTriggerConstraint())) {
1105 return;
1106 }
1107
1108 mDynamicConstraints |= constraint;
1109 mReadyDynamicSatisfied =
1110 mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
1111 }
1112
1113 /**
1114 * Removes a dynamic constraint from a job, meaning that the requirement is not required for
1115 * the job to run (if the job itself hasn't requested the constraint. This is separate from
1116 * the job's explicitly requested constraints and does not remove those requested constraints.
1117 *
1118 */
1119 public void removeDynamicConstraint(int constraint) {
1120 mDynamicConstraints &= ~constraint;
1121 mReadyDynamicSatisfied =
1122 mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
1123 }
1124
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001125 public long getLastSuccessfulRunTime() {
1126 return mLastSuccessfulRunTime;
1127 }
1128
1129 public long getLastFailedRunTime() {
1130 return mLastFailedRunTime;
1131 }
1132
Christopher Tate7060b042014-06-09 19:50:00 -07001133 /**
Kweku Adams32f44762018-11-02 16:58:32 -07001134 * @return Whether or not this job is ready to run, based on its requirements.
Christopher Tate7060b042014-06-09 19:50:00 -07001135 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -08001136 public boolean isReady() {
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001137 return isReady(mSatisfiedConstraintsOfInterest);
1138 }
1139
1140 /**
1141 * @return Whether or not this job would be ready to run if it had the specified constraint
1142 * granted, based on its requirements.
1143 */
Kweku Adamsab8a9012019-01-28 15:42:09 -08001144 boolean wouldBeReadyWithConstraint(int constraint) {
1145 boolean oldValue = false;
1146 int satisfied = mSatisfiedConstraintsOfInterest;
1147 switch (constraint) {
1148 case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
1149 oldValue = mReadyNotRestrictedInBg;
1150 mReadyNotRestrictedInBg = true;
1151 break;
1152 case CONSTRAINT_DEADLINE:
1153 oldValue = mReadyDeadlineSatisfied;
1154 mReadyDeadlineSatisfied = true;
1155 break;
1156 case CONSTRAINT_DEVICE_NOT_DOZING:
1157 oldValue = mReadyNotDozing;
1158 mReadyNotDozing = true;
1159 break;
1160 case CONSTRAINT_WITHIN_QUOTA:
1161 oldValue = mReadyWithinQuota;
1162 mReadyWithinQuota = true;
1163 break;
1164 default:
1165 satisfied |= constraint;
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001166 mReadyDynamicSatisfied =
1167 mDynamicConstraints == (satisfied & mDynamicConstraints);
Kweku Adamsab8a9012019-01-28 15:42:09 -08001168 break;
1169 }
1170
1171 boolean toReturn = isReady(satisfied);
1172
1173 switch (constraint) {
1174 case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
1175 mReadyNotRestrictedInBg = oldValue;
1176 break;
1177 case CONSTRAINT_DEADLINE:
1178 mReadyDeadlineSatisfied = oldValue;
1179 break;
1180 case CONSTRAINT_DEVICE_NOT_DOZING:
1181 mReadyNotDozing = oldValue;
1182 break;
1183 case CONSTRAINT_WITHIN_QUOTA:
1184 mReadyWithinQuota = oldValue;
1185 break;
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001186 default:
1187 mReadyDynamicSatisfied =
1188 mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
1189 break;
Kweku Adamsab8a9012019-01-28 15:42:09 -08001190 }
1191 return toReturn;
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001192 }
1193
1194 private boolean isReady(int satisfiedConstraints) {
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001195 // Quota and dynamic constraints trump all other constraints.
1196 if (!mReadyWithinQuota && !mReadyDynamicSatisfied) {
Kweku Adams4836f9d2018-11-12 17:04:17 -08001197 return false;
1198 }
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001199 // Deadline constraint trumps other constraints besides quota and dynamic (except for
1200 // periodic jobs where deadline is an implementation detail. A periodic job should only
1201 // run if its constraints are satisfied).
Amith Yamasanicb926fc2016-03-14 17:15:20 -07001202 // DeviceNotDozing implicit constraint must be satisfied
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001203 // NotRestrictedInBackground implicit constraint must be satisfied
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001204 return mReadyNotDozing && mReadyNotRestrictedInBg && (mReadyDeadlineSatisfied
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001205 || isConstraintsSatisfied(satisfiedConstraints));
Matthew Williams03a4da62014-09-10 17:32:18 -07001206 }
1207
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001208 /** All constraints besides implicit and deadline. */
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001209 static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
1210 | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_CONNECTIVITY
1211 | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001212
Christopher Tate5d346052016-03-08 12:56:08 -08001213 // Soft override covers all non-"functional" constraints
1214 static final int SOFT_OVERRIDE_CONSTRAINTS =
Dianne Hackborn532ea262017-03-17 17:50:55 -07001215 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001216 | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
Christopher Tate5d346052016-03-08 12:56:08 -08001217
Matthew Williams03a4da62014-09-10 17:32:18 -07001218 /**
1219 * @return Whether the constraints set on this job are satisfied.
1220 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -08001221 public boolean isConstraintsSatisfied() {
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001222 return isConstraintsSatisfied(mSatisfiedConstraintsOfInterest);
1223 }
1224
1225 private boolean isConstraintsSatisfied(int satisfiedConstraints) {
Christopher Tate5d346052016-03-08 12:56:08 -08001226 if (overrideState == OVERRIDE_FULL) {
1227 // force override: the job is always runnable
1228 return true;
1229 }
1230
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001231 int sat = satisfiedConstraints;
Christopher Tate5d346052016-03-08 12:56:08 -08001232 if (overrideState == OVERRIDE_SOFT) {
1233 // override: pretend all 'soft' requirements are satisfied
1234 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
1235 }
1236
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001237 return (sat & mRequiredConstraintsOfInterest) == mRequiredConstraintsOfInterest;
Christopher Tate7060b042014-06-09 19:50:00 -07001238 }
1239
1240 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +00001241 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -07001242 }
1243
1244 @Override
1245 public String toString() {
Dianne Hackborna47223f2017-03-30 13:49:13 -07001246 StringBuilder sb = new StringBuilder(128);
1247 sb.append("JobStatus{");
1248 sb.append(Integer.toHexString(System.identityHashCode(this)));
1249 sb.append(" #");
1250 UserHandle.formatUid(sb, callingUid);
1251 sb.append("/");
1252 sb.append(job.getId());
1253 sb.append(' ');
1254 sb.append(batteryName);
1255 sb.append(" u=");
1256 sb.append(getUserId());
1257 sb.append(" s=");
1258 sb.append(getSourceUid());
1259 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
1260 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001261 long now = sElapsedRealtimeClock.millis();
Dianne Hackborna47223f2017-03-30 13:49:13 -07001262 sb.append(" TIME=");
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001263 formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
1264 sb.append(":");
1265 formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
Dianne Hackborna47223f2017-03-30 13:49:13 -07001266 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001267 if (job.getRequiredNetwork() != null) {
1268 sb.append(" NET");
Dianne Hackborna47223f2017-03-30 13:49:13 -07001269 }
1270 if (job.isRequireCharging()) {
1271 sb.append(" CHARGING");
1272 }
1273 if (job.isRequireBatteryNotLow()) {
1274 sb.append(" BATNOTLOW");
1275 }
1276 if (job.isRequireStorageNotLow()) {
1277 sb.append(" STORENOTLOW");
1278 }
1279 if (job.isRequireDeviceIdle()) {
1280 sb.append(" IDLE");
1281 }
Christopher Tate616541d2017-07-26 14:27:38 -07001282 if (job.isPeriodic()) {
1283 sb.append(" PERIODIC");
1284 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001285 if (job.isPersisted()) {
1286 sb.append(" PERSISTED");
1287 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001288 if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
1289 sb.append(" WAIT:DEV_NOT_DOZING");
1290 }
1291 if (job.getTriggerContentUris() != null) {
1292 sb.append(" URIS=");
1293 sb.append(Arrays.toString(job.getTriggerContentUris()));
1294 }
1295 if (numFailures != 0) {
1296 sb.append(" failures=");
1297 sb.append(numFailures);
1298 }
1299 if (isReady()) {
1300 sb.append(" READY");
1301 }
1302 sb.append("}");
1303 return sb.toString();
Christopher Tate7060b042014-06-09 19:50:00 -07001304 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001305
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001306 private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001307 if (runtime == defaultValue) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001308 pw.print("none");
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001309 } else {
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001310 TimeUtils.formatDuration(runtime - now, pw);
1311 }
1312 }
1313
1314 private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) {
1315 if (runtime == defaultValue) {
1316 sb.append("none");
1317 } else {
1318 TimeUtils.formatDuration(runtime - now, sb);
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001319 }
1320 }
1321
1322 /**
1323 * Convenience function to identify a job uniquely without pulling all the data that
1324 * {@link #toString()} returns.
1325 */
1326 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001327 StringBuilder sb = new StringBuilder();
1328 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001329 sb.append(" #");
1330 UserHandle.formatUid(sb, callingUid);
1331 sb.append("/");
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001332 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001333 sb.append(' ');
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001334 sb.append(batteryName);
1335 return sb.toString();
1336 }
1337
1338 /**
1339 * Convenience function to identify a job uniquely without pulling all the data that
1340 * {@link #toString()} returns.
1341 */
1342 public String toShortStringExceptUniqueId() {
1343 StringBuilder sb = new StringBuilder();
1344 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001345 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -08001346 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001347 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001348 }
1349
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001350 /**
1351 * Convenience function to dump data that identifies a job uniquely to proto. This is intended
1352 * to mimic {@link #toShortString}.
1353 */
1354 public void writeToShortProto(ProtoOutputStream proto, long fieldId) {
1355 final long token = proto.start(fieldId);
1356
1357 proto.write(JobStatusShortInfoProto.CALLING_UID, callingUid);
1358 proto.write(JobStatusShortInfoProto.JOB_ID, job.getId());
1359 proto.write(JobStatusShortInfoProto.BATTERY_NAME, batteryName);
1360
1361 proto.end(token);
1362 }
1363
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001364 void dumpConstraints(PrintWriter pw, int constraints) {
1365 if ((constraints&CONSTRAINT_CHARGING) != 0) {
1366 pw.print(" CHARGING");
1367 }
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001368 if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
1369 pw.print(" BATTERY_NOT_LOW");
1370 }
Dianne Hackborn532ea262017-03-17 17:50:55 -07001371 if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) {
1372 pw.print(" STORAGE_NOT_LOW");
1373 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001374 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
1375 pw.print(" TIMING_DELAY");
1376 }
1377 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
1378 pw.print(" DEADLINE");
1379 }
1380 if ((constraints&CONSTRAINT_IDLE) != 0) {
1381 pw.print(" IDLE");
1382 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -06001383 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
1384 pw.print(" CONNECTIVITY");
1385 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001386 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
1387 pw.print(" CONTENT_TRIGGER");
1388 }
Amith Yamasanicb926fc2016-03-14 17:15:20 -07001389 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
1390 pw.print(" DEVICE_NOT_DOZING");
1391 }
Makoto Onukidfede0a2018-01-22 15:11:34 -08001392 if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
1393 pw.print(" BACKGROUND_NOT_RESTRICTED");
1394 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001395 if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
1396 pw.print(" WITHIN_QUOTA");
1397 }
Makoto Onukidfede0a2018-01-22 15:11:34 -08001398 if (constraints != 0) {
1399 pw.print(" [0x");
1400 pw.print(Integer.toHexString(constraints));
1401 pw.print("]");
1402 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001403 }
1404
Kweku Adams8845d012018-12-11 20:06:45 -08001405 /** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */
1406 private int getProtoConstraint(int constraint) {
1407 switch (constraint) {
1408 case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
1409 return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
1410 case CONSTRAINT_BATTERY_NOT_LOW:
1411 return JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW;
1412 case CONSTRAINT_CHARGING:
1413 return JobServerProtoEnums.CONSTRAINT_CHARGING;
1414 case CONSTRAINT_CONNECTIVITY:
1415 return JobServerProtoEnums.CONSTRAINT_CONNECTIVITY;
1416 case CONSTRAINT_CONTENT_TRIGGER:
1417 return JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER;
1418 case CONSTRAINT_DEADLINE:
1419 return JobServerProtoEnums.CONSTRAINT_DEADLINE;
1420 case CONSTRAINT_DEVICE_NOT_DOZING:
1421 return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING;
1422 case CONSTRAINT_IDLE:
1423 return JobServerProtoEnums.CONSTRAINT_IDLE;
1424 case CONSTRAINT_STORAGE_NOT_LOW:
1425 return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
1426 case CONSTRAINT_TIMING_DELAY:
1427 return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
1428 case CONSTRAINT_WITHIN_QUOTA:
1429 return JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA;
1430 default:
1431 return JobServerProtoEnums.CONSTRAINT_UNKNOWN;
1432 }
1433 }
1434
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001435 /** Writes constraints to the given repeating proto field. */
1436 void dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints) {
1437 if ((constraints & CONSTRAINT_CHARGING) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001438 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CHARGING);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001439 }
1440 if ((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001441 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001442 }
1443 if ((constraints & CONSTRAINT_STORAGE_NOT_LOW) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001444 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001445 }
1446 if ((constraints & CONSTRAINT_TIMING_DELAY) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001447 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_TIMING_DELAY);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001448 }
1449 if ((constraints & CONSTRAINT_DEADLINE) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001450 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEADLINE);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001451 }
1452 if ((constraints & CONSTRAINT_IDLE) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001453 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_IDLE);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001454 }
1455 if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001456 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONNECTIVITY);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001457 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001458 if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001459 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001460 }
1461 if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001462 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001463 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001464 if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001465 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA);
1466 }
1467 if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
1468 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED);
Kweku Adams4836f9d2018-11-12 17:04:17 -08001469 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001470 }
1471
Dianne Hackborn342e6032017-04-13 18:04:31 -07001472 private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
1473 pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #");
Dianne Hackborn28d1b662017-04-21 14:17:23 -07001474 pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
1475 pw.print("x "); pw.println(work.getIntent());
Dianne Hackborn342e6032017-04-13 18:04:31 -07001476 if (work.getGrants() != null) {
1477 pw.print(prefix); pw.println(" URI grants:");
1478 ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " ");
1479 }
1480 }
1481
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001482 private void dumpJobWorkItem(ProtoOutputStream proto, long fieldId, JobWorkItem work) {
1483 final long token = proto.start(fieldId);
1484
1485 proto.write(JobStatusDumpProto.JobWorkItem.WORK_ID, work.getWorkId());
1486 proto.write(JobStatusDumpProto.JobWorkItem.DELIVERY_COUNT, work.getDeliveryCount());
1487 if (work.getIntent() != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -08001488 work.getIntent().dumpDebug(proto, JobStatusDumpProto.JobWorkItem.INTENT);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001489 }
1490 Object grants = work.getGrants();
1491 if (grants != null) {
1492 ((GrantedUriPermissions) grants).dump(proto, JobStatusDumpProto.JobWorkItem.URI_GRANTS);
1493 }
1494
1495 proto.end(token);
1496 }
1497
Kweku Adams32f44762018-11-02 16:58:32 -07001498 /**
1499 * Returns a bucket name based on the normalized bucket indices, not the AppStandby constants.
1500 */
1501 String getBucketName() {
Kweku Adams4836f9d2018-11-12 17:04:17 -08001502 return bucketName(standbyBucket);
1503 }
1504
1505 /**
1506 * Returns a bucket name based on the normalized bucket indices, not the AppStandby constants.
1507 */
1508 static String bucketName(int standbyBucket) {
Kweku Adams32f44762018-11-02 16:58:32 -07001509 switch (standbyBucket) {
Christopher Tatea732f012017-10-26 17:26:53 -07001510 case 0: return "ACTIVE";
1511 case 1: return "WORKING_SET";
1512 case 2: return "FREQUENT";
1513 case 3: return "RARE";
1514 case 4: return "NEVER";
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001515 case 5:
1516 return "RESTRICTED";
Christopher Tatea732f012017-10-26 17:26:53 -07001517 default:
Kweku Adams32f44762018-11-02 16:58:32 -07001518 return "Unknown: " + standbyBucket;
Christopher Tatea732f012017-10-26 17:26:53 -07001519 }
1520 }
1521
Christopher Tate7060b042014-06-09 19:50:00 -07001522 // Dumpsys infrastructure
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001523 public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +00001524 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001525 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -07001526 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +00001527 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
1528 pw.print(" user="); pw.print(getSourceUserId());
1529 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001530 if (full) {
Dianne Hackborna47223f2017-03-30 13:49:13 -07001531 pw.print(prefix); pw.println("JobInfo:");
1532 pw.print(prefix); pw.print(" Service: ");
1533 pw.println(job.getService().flattenToShortString());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001534 if (job.isPeriodic()) {
1535 pw.print(prefix); pw.print(" PERIODIC: interval=");
1536 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
1537 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
1538 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001539 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001540 if (job.isPersisted()) {
1541 pw.print(prefix); pw.println(" PERSISTED");
1542 }
1543 if (job.getPriority() != 0) {
Makoto Onukiec8b14d2018-12-05 13:22:24 -08001544 pw.print(prefix); pw.print(" Priority: ");
1545 pw.println(JobInfo.getPriorityString(job.getPriority()));
Dianne Hackborn970510b2016-02-24 16:56:42 -08001546 }
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001547 if (job.getFlags() != 0) {
1548 pw.print(prefix); pw.print(" Flags: ");
1549 pw.println(Integer.toHexString(job.getFlags()));
1550 }
Makoto Onuki15407842018-01-19 14:23:11 -08001551 if (getInternalFlags() != 0) {
1552 pw.print(prefix); pw.print(" Internal flags: ");
1553 pw.print(Integer.toHexString(getInternalFlags()));
1554
1555 if ((getInternalFlags()&INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
1556 pw.print(" HAS_FOREGROUND_EXEMPTION");
1557 }
1558 pw.println();
1559 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001560 pw.print(prefix); pw.print(" Requires: charging=");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001561 pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
1562 pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
Dianne Hackborn970510b2016-02-24 16:56:42 -08001563 pw.println(job.isRequireDeviceIdle());
1564 if (job.getTriggerContentUris() != null) {
1565 pw.print(prefix); pw.println(" Trigger content URIs:");
1566 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
1567 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
1568 pw.print(prefix); pw.print(" ");
1569 pw.print(Integer.toHexString(trig.getFlags()));
1570 pw.print(' '); pw.println(trig.getUri());
1571 }
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001572 if (job.getTriggerContentUpdateDelay() >= 0) {
1573 pw.print(prefix); pw.print(" Trigger update delay: ");
1574 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
1575 pw.println();
1576 }
1577 if (job.getTriggerContentMaxDelay() >= 0) {
1578 pw.print(prefix); pw.print(" Trigger max delay: ");
1579 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
1580 pw.println();
1581 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001582 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001583 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
1584 pw.print(prefix); pw.print(" Extras: ");
1585 pw.println(job.getExtras().toShortString());
1586 }
1587 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
1588 pw.print(prefix); pw.print(" Transient extras: ");
1589 pw.println(job.getTransientExtras().toShortString());
1590 }
1591 if (job.getClipData() != null) {
1592 pw.print(prefix); pw.print(" Clip data: ");
1593 StringBuilder b = new StringBuilder(128);
Makoto Onuki0e1ce972019-10-09 12:51:55 -07001594 b.append(job.getClipData());
Dianne Hackborna47223f2017-03-30 13:49:13 -07001595 pw.println(b);
1596 }
Dianne Hackborn342e6032017-04-13 18:04:31 -07001597 if (uriPerms != null) {
1598 pw.print(prefix); pw.println(" Granted URI permissions:");
1599 uriPerms.dump(pw, prefix + " ");
1600 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001601 if (job.getRequiredNetwork() != null) {
1602 pw.print(prefix); pw.print(" Network type: ");
1603 pw.println(job.getRequiredNetwork());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001604 }
Kweku Adams316b1412019-06-14 11:34:37 -07001605 if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
1606 pw.print(prefix); pw.print(" Network download bytes: ");
1607 pw.println(mTotalNetworkDownloadBytes);
1608 }
1609 if (mTotalNetworkUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
1610 pw.print(prefix); pw.print(" Network upload bytes: ");
1611 pw.println(mTotalNetworkUploadBytes);
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001612 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001613 if (job.getMinLatencyMillis() != 0) {
1614 pw.print(prefix); pw.print(" Minimum latency: ");
1615 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
1616 pw.println();
1617 }
1618 if (job.getMaxExecutionDelayMillis() != 0) {
1619 pw.print(prefix); pw.print(" Max execution delay: ");
1620 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
1621 pw.println();
1622 }
1623 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
1624 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001625 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001626 if (job.hasEarlyConstraint()) {
1627 pw.print(prefix); pw.println(" Has early constraint");
1628 }
1629 if (job.hasLateConstraint()) {
1630 pw.print(prefix); pw.println(" Has late constraint");
1631 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001632 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001633 pw.print(prefix); pw.print("Required constraints:");
1634 dumpConstraints(pw, requiredConstraints);
1635 pw.println();
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001636 pw.print(prefix);
1637 pw.print("Dynamic constraints:");
1638 dumpConstraints(pw, mDynamicConstraints);
1639 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001640 if (full) {
1641 pw.print(prefix); pw.print("Satisfied constraints:");
1642 dumpConstraints(pw, satisfiedConstraints);
1643 pw.println();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001644 pw.print(prefix); pw.print("Unsatisfied constraints:");
Kweku Adams4836f9d2018-11-12 17:04:17 -08001645 dumpConstraints(pw,
1646 ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001647 pw.println();
Dianne Hackborn7ab40252016-06-15 17:30:24 -07001648 if (dozeWhitelisted) {
1649 pw.print(prefix); pw.println("Doze whitelisted: true");
1650 }
Christopher Tate20afddd2018-02-28 15:19:19 -08001651 if (uidActive) {
1652 pw.print(prefix); pw.println("Uid: active");
1653 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001654 if (job.isExemptedFromAppStandby()) {
1655 pw.print(prefix); pw.println("Is exempted from app standby");
1656 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001657 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001658 if (trackingControllers != 0) {
1659 pw.print(prefix); pw.print("Tracking:");
1660 if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY");
1661 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY");
1662 if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT");
1663 if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE");
1664 if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE");
1665 if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME");
Kweku Adams4836f9d2018-11-12 17:04:17 -08001666 if ((trackingControllers & TRACKING_QUOTA) != 0) pw.print(" QUOTA");
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001667 pw.println();
1668 }
Kweku Adams32f44762018-11-02 16:58:32 -07001669
1670 pw.print(prefix); pw.println("Implicit constraints:");
1671 pw.print(prefix); pw.print(" readyNotDozing: ");
1672 pw.println(mReadyNotDozing);
1673 pw.print(prefix); pw.print(" readyNotRestrictedInBg: ");
1674 pw.println(mReadyNotRestrictedInBg);
1675 if (!job.isPeriodic() && hasDeadlineConstraint()) {
1676 pw.print(prefix); pw.print(" readyDeadlineSatisfied: ");
1677 pw.println(mReadyDeadlineSatisfied);
1678 }
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001679 pw.print(prefix);
1680 pw.print(" readyDynamicSatisfied: ");
1681 pw.println(mReadyDynamicSatisfied);
Kweku Adams32f44762018-11-02 16:58:32 -07001682
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001683 if (changedAuthorities != null) {
1684 pw.print(prefix); pw.println("Changed authorities:");
1685 for (int i=0; i<changedAuthorities.size(); i++) {
1686 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
1687 }
Kweku Adamsc3f9ba62019-08-01 12:14:55 -07001688 }
1689 if (changedUris != null) {
1690 pw.print(prefix);
1691 pw.println("Changed URIs:");
1692 for (int i = 0; i < changedUris.size(); i++) {
1693 pw.print(prefix);
1694 pw.print(" ");
1695 pw.println(changedUris.valueAt(i));
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001696 }
1697 }
Jeff Sharkey76a02412017-10-24 16:55:04 -06001698 if (network != null) {
1699 pw.print(prefix); pw.print("Network: "); pw.println(network);
1700 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001701 if (pendingWork != null && pendingWork.size() > 0) {
1702 pw.print(prefix); pw.println("Pending work:");
1703 for (int i = 0; i < pendingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001704 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001705 }
1706 }
1707 if (executingWork != null && executingWork.size() > 0) {
1708 pw.print(prefix); pw.println("Executing work:");
1709 for (int i = 0; i < executingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001710 dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001711 }
1712 }
Christopher Tatea732f012017-10-26 17:26:53 -07001713 pw.print(prefix); pw.print("Standby bucket: ");
Kweku Adams32f44762018-11-02 16:58:32 -07001714 pw.println(getBucketName());
Christopher Tated1aebb32018-01-31 13:24:14 -08001715 if (whenStandbyDeferred != 0) {
1716 pw.print(prefix); pw.print(" Deferred since: ");
1717 TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
1718 pw.println();
1719 }
Kweku Adams41cb3322019-06-26 14:42:26 -07001720 if (mFirstForceBatchedTimeElapsed != 0) {
1721 pw.print(prefix);
1722 pw.print(" Time since first force batch attempt: ");
1723 TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, elapsedRealtimeMillis, pw);
1724 pw.println();
1725 }
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001726 pw.print(prefix); pw.print("Enqueue time: ");
1727 TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
1728 pw.println();
1729 pw.print(prefix); pw.print("Run time: earliest=");
1730 formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
1731 pw.print(", latest=");
1732 formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
Kweku Adams966e72b2019-05-30 14:45:39 -07001733 pw.print(", original latest=");
1734 formatRunTime(pw, mOriginalLatestRunTimeElapsedMillis,
1735 NO_LATEST_RUNTIME, elapsedRealtimeMillis);
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001736 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001737 if (numFailures != 0) {
1738 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
1739 }
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001740 if (mLastSuccessfulRunTime != 0) {
1741 pw.print(prefix); pw.print("Last successful run: ");
Makoto Onuki0e1ce972019-10-09 12:51:55 -07001742 pw.println(formatTime(mLastSuccessfulRunTime));
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001743 }
1744 if (mLastFailedRunTime != 0) {
1745 pw.print(prefix); pw.print("Last failed run: ");
Makoto Onuki0e1ce972019-10-09 12:51:55 -07001746 pw.println(formatTime(mLastFailedRunTime));
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001747 }
Christopher Tate7060b042014-06-09 19:50:00 -07001748 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001749
Makoto Onuki0e1ce972019-10-09 12:51:55 -07001750 private static CharSequence formatTime(long time) {
1751 return DateFormat.format("yyyy-MM-dd HH:mm:ss", time);
1752 }
1753
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001754 public void dump(ProtoOutputStream proto, long fieldId, boolean full, long elapsedRealtimeMillis) {
1755 final long token = proto.start(fieldId);
1756
1757 proto.write(JobStatusDumpProto.CALLING_UID, callingUid);
1758 proto.write(JobStatusDumpProto.TAG, tag);
1759 proto.write(JobStatusDumpProto.SOURCE_UID, getSourceUid());
1760 proto.write(JobStatusDumpProto.SOURCE_USER_ID, getSourceUserId());
1761 proto.write(JobStatusDumpProto.SOURCE_PACKAGE_NAME, getSourcePackageName());
1762
1763 if (full) {
1764 final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO);
1765
Jeffrey Huangcb782852019-12-05 11:28:11 -08001766 job.getService().dumpDebug(proto, JobStatusDumpProto.JobInfo.SERVICE);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001767
1768 proto.write(JobStatusDumpProto.JobInfo.IS_PERIODIC, job.isPeriodic());
1769 proto.write(JobStatusDumpProto.JobInfo.PERIOD_INTERVAL_MS, job.getIntervalMillis());
1770 proto.write(JobStatusDumpProto.JobInfo.PERIOD_FLEX_MS, job.getFlexMillis());
1771
1772 proto.write(JobStatusDumpProto.JobInfo.IS_PERSISTED, job.isPersisted());
1773 proto.write(JobStatusDumpProto.JobInfo.PRIORITY, job.getPriority());
1774 proto.write(JobStatusDumpProto.JobInfo.FLAGS, job.getFlags());
Kweku Adamsc3f9ba62019-08-01 12:14:55 -07001775 proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
1776 // Foreground exemption can be determined from internal flags value.
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001777
1778 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_CHARGING, job.isRequireCharging());
1779 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_BATTERY_NOT_LOW, job.isRequireBatteryNotLow());
1780 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_DEVICE_IDLE, job.isRequireDeviceIdle());
1781
1782 if (job.getTriggerContentUris() != null) {
1783 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
1784 final long tcuToken = proto.start(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_URIS);
1785 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
1786
1787 proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.FLAGS, trig.getFlags());
1788 Uri u = trig.getUri();
1789 if (u != null) {
1790 proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.URI, u.toString());
1791 }
1792
1793 proto.end(tcuToken);
1794 }
1795 if (job.getTriggerContentUpdateDelay() >= 0) {
1796 proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_UPDATE_DELAY_MS,
1797 job.getTriggerContentUpdateDelay());
1798 }
1799 if (job.getTriggerContentMaxDelay() >= 0) {
1800 proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_MAX_DELAY_MS,
1801 job.getTriggerContentMaxDelay());
1802 }
1803 }
1804 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
Jeffrey Huangcb782852019-12-05 11:28:11 -08001805 job.getExtras().dumpDebug(proto, JobStatusDumpProto.JobInfo.EXTRAS);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001806 }
1807 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
Jeffrey Huangcb782852019-12-05 11:28:11 -08001808 job.getTransientExtras().dumpDebug(proto, JobStatusDumpProto.JobInfo.TRANSIENT_EXTRAS);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001809 }
1810 if (job.getClipData() != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -08001811 job.getClipData().dumpDebug(proto, JobStatusDumpProto.JobInfo.CLIP_DATA);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001812 }
1813 if (uriPerms != null) {
1814 uriPerms.dump(proto, JobStatusDumpProto.JobInfo.GRANTED_URI_PERMISSIONS);
1815 }
1816 if (job.getRequiredNetwork() != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -08001817 job.getRequiredNetwork().dumpDebug(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001818 }
Kweku Adams316b1412019-06-14 11:34:37 -07001819 if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
1820 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_DOWNLOAD_BYTES,
1821 mTotalNetworkDownloadBytes);
1822 }
1823 if (mTotalNetworkUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
1824 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_UPLOAD_BYTES,
1825 mTotalNetworkUploadBytes);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001826 }
1827 proto.write(JobStatusDumpProto.JobInfo.MIN_LATENCY_MS, job.getMinLatencyMillis());
1828 proto.write(JobStatusDumpProto.JobInfo.MAX_EXECUTION_DELAY_MS, job.getMaxExecutionDelayMillis());
1829
1830 final long bpToken = proto.start(JobStatusDumpProto.JobInfo.BACKOFF_POLICY);
1831 proto.write(JobStatusDumpProto.JobInfo.Backoff.POLICY, job.getBackoffPolicy());
1832 proto.write(JobStatusDumpProto.JobInfo.Backoff.INITIAL_BACKOFF_MS,
1833 job.getInitialBackoffMillis());
1834 proto.end(bpToken);
1835
1836 proto.write(JobStatusDumpProto.JobInfo.HAS_EARLY_CONSTRAINT, job.hasEarlyConstraint());
1837 proto.write(JobStatusDumpProto.JobInfo.HAS_LATE_CONSTRAINT, job.hasLateConstraint());
1838
1839 proto.end(jiToken);
1840 }
1841
1842 dumpConstraints(proto, JobStatusDumpProto.REQUIRED_CONSTRAINTS, requiredConstraints);
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001843 dumpConstraints(proto, JobStatusDumpProto.DYNAMIC_CONSTRAINTS, mDynamicConstraints);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001844 if (full) {
1845 dumpConstraints(proto, JobStatusDumpProto.SATISFIED_CONSTRAINTS, satisfiedConstraints);
1846 dumpConstraints(proto, JobStatusDumpProto.UNSATISFIED_CONSTRAINTS,
Kweku Adams4836f9d2018-11-12 17:04:17 -08001847 ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001848 proto.write(JobStatusDumpProto.IS_DOZE_WHITELISTED, dozeWhitelisted);
Kweku Adams4836f9d2018-11-12 17:04:17 -08001849 proto.write(JobStatusDumpProto.IS_UID_ACTIVE, uidActive);
1850 proto.write(JobStatusDumpProto.IS_EXEMPTED_FROM_APP_STANDBY,
1851 job.isExemptedFromAppStandby());
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001852 }
1853
1854 // Tracking controllers
1855 if ((trackingControllers&TRACKING_BATTERY) != 0) {
1856 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1857 JobStatusDumpProto.TRACKING_BATTERY);
1858 }
1859 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) {
1860 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1861 JobStatusDumpProto.TRACKING_CONNECTIVITY);
1862 }
1863 if ((trackingControllers&TRACKING_CONTENT) != 0) {
1864 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1865 JobStatusDumpProto.TRACKING_CONTENT);
1866 }
1867 if ((trackingControllers&TRACKING_IDLE) != 0) {
1868 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1869 JobStatusDumpProto.TRACKING_IDLE);
1870 }
1871 if ((trackingControllers&TRACKING_STORAGE) != 0) {
1872 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1873 JobStatusDumpProto.TRACKING_STORAGE);
1874 }
1875 if ((trackingControllers&TRACKING_TIME) != 0) {
1876 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1877 JobStatusDumpProto.TRACKING_TIME);
1878 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001879 if ((trackingControllers & TRACKING_QUOTA) != 0) {
1880 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1881 JobStatusDumpProto.TRACKING_QUOTA);
1882 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001883
Kweku Adams32f44762018-11-02 16:58:32 -07001884 // Implicit constraints
1885 final long icToken = proto.start(JobStatusDumpProto.IMPLICIT_CONSTRAINTS);
1886 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_DOZING, mReadyNotDozing);
1887 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_RESTRICTED_IN_BG,
1888 mReadyNotRestrictedInBg);
Kweku Adamsc3f9ba62019-08-01 12:14:55 -07001889 // mReadyDeadlineSatisfied isn't an implicit constraint...and can be determined from other
1890 // field values.
Kweku Adamsae9d6be2020-01-14 16:10:14 -08001891 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_DYNAMIC_SATISFIED,
1892 mReadyDynamicSatisfied);
Kweku Adams32f44762018-11-02 16:58:32 -07001893 proto.end(icToken);
1894
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001895 if (changedAuthorities != null) {
1896 for (int k = 0; k < changedAuthorities.size(); k++) {
1897 proto.write(JobStatusDumpProto.CHANGED_AUTHORITIES, changedAuthorities.valueAt(k));
1898 }
1899 }
1900 if (changedUris != null) {
1901 for (int i = 0; i < changedUris.size(); i++) {
1902 Uri u = changedUris.valueAt(i);
1903 proto.write(JobStatusDumpProto.CHANGED_URIS, u.toString());
1904 }
1905 }
1906
1907 if (network != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -08001908 network.dumpDebug(proto, JobStatusDumpProto.NETWORK);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001909 }
1910
Kweku Adamsc3f9ba62019-08-01 12:14:55 -07001911 if (pendingWork != null) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001912 for (int i = 0; i < pendingWork.size(); i++) {
1913 dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i));
1914 }
1915 }
Kweku Adamsc3f9ba62019-08-01 12:14:55 -07001916 if (executingWork != null) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001917 for (int i = 0; i < executingWork.size(); i++) {
1918 dumpJobWorkItem(proto, JobStatusDumpProto.EXECUTING_WORK, executingWork.get(i));
1919 }
1920 }
1921
1922 proto.write(JobStatusDumpProto.STANDBY_BUCKET, standbyBucket);
1923 proto.write(JobStatusDumpProto.ENQUEUE_DURATION_MS, elapsedRealtimeMillis - enqueueTime);
Kweku Adams41cb3322019-06-26 14:42:26 -07001924 proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_DEFERRAL_MS,
1925 whenStandbyDeferred == 0 ? 0 : elapsedRealtimeMillis - whenStandbyDeferred);
1926 proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_FORCE_BATCH_ATTEMPT_MS,
1927 mFirstForceBatchedTimeElapsed == 0
1928 ? 0 : elapsedRealtimeMillis - mFirstForceBatchedTimeElapsed);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001929 if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) {
1930 proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS, 0);
1931 } else {
1932 proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS,
1933 earliestRunTimeElapsedMillis - elapsedRealtimeMillis);
1934 }
1935 if (latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) {
1936 proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS, 0);
1937 } else {
1938 proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS,
1939 latestRunTimeElapsedMillis - elapsedRealtimeMillis);
1940 }
Kweku Adamsc3f9ba62019-08-01 12:14:55 -07001941 proto.write(JobStatusDumpProto.ORIGINAL_LATEST_RUNTIME_ELAPSED,
1942 mOriginalLatestRunTimeElapsedMillis);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001943
1944 proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures);
1945 proto.write(JobStatusDumpProto.LAST_SUCCESSFUL_RUN_TIME, mLastSuccessfulRunTime);
1946 proto.write(JobStatusDumpProto.LAST_FAILED_RUN_TIME, mLastFailedRunTime);
1947
1948 proto.end(token);
1949 }
Christopher Tate7060b042014-06-09 19:50:00 -07001950}