blob: ed1a6d0beabf5ae7cf82d0c382d81da23f00ae6c [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
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070019import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
20
Shreyas Basarge968ac752016-01-11 23:09:26 +000021import android.app.AppGlobals;
Dianne Hackborna47223f2017-03-30 13:49:13 -070022import android.app.IActivityManager;
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 Sharkey9252b342018-01-19 07:58:35 +090027import android.content.pm.PackageManagerInternal;
Jeff Sharkey76a02412017-10-24 16:55:04 -060028import android.net.Network;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080029import android.net.Uri;
Shreyas Basarge968ac752016-01-11 23:09:26 +000030import android.os.RemoteException;
Christopher Tate7060b042014-06-09 19:50:00 -070031import android.os.UserHandle;
Makoto Onukiab8a67f2017-06-20 12:20:34 -070032import android.text.format.Time;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080033import android.util.ArraySet;
Christopher Tate616541d2017-07-26 14:27:38 -070034import android.util.Pair;
Dianne Hackborna47223f2017-03-30 13:49:13 -070035import android.util.Slog;
Kweku Adams8845d012018-12-11 20:06:45 -080036import android.util.StatsLog;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080037import android.util.TimeUtils;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080038import android.util.proto.ProtoOutputStream;
Christopher Tate7060b042014-06-09 19:50:00 -070039
Christopher Tatea732f012017-10-26 17:26:53 -070040import com.android.server.LocalServices;
Dianne Hackborn342e6032017-04-13 18:04:31 -070041import com.android.server.job.GrantedUriPermissions;
Christopher Tatea732f012017-10-26 17:26:53 -070042import com.android.server.job.JobSchedulerInternal;
Christopher Tate616541d2017-07-26 14:27:38 -070043import com.android.server.job.JobSchedulerService;
Kweku Adams8845d012018-12-11 20:06:45 -080044import com.android.server.job.JobServerProtoEnums;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080045import com.android.server.job.JobStatusDumpProto;
46import com.android.server.job.JobStatusShortInfoProto;
Dianne Hackborn342e6032017-04-13 18:04:31 -070047
Christopher Tate7060b042014-06-09 19:50:00 -070048import java.io.PrintWriter;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070049import java.util.ArrayList;
Dianne Hackborna47223f2017-03-30 13:49:13 -070050import java.util.Arrays;
Makoto Onuki15407842018-01-19 14:23:11 -080051import java.util.function.Predicate;
Christopher Tate7060b042014-06-09 19:50:00 -070052
53/**
54 * Uniquely identifies a job internally.
55 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
56 * Contains current state of the requirements of the job, as well as a function to evaluate
57 * whether it's ready to run.
58 * This object is shared among the various controllers - hence why the different fields are atomic.
59 * This isn't strictly necessary because each controller is only interested in a specific field,
60 * and the receivers that are listening for global state change will all run on the main looper,
61 * but we don't enforce that so this is safer.
Kweku Adamsd14ce4d2018-10-19 11:40:55 -070062 *
63 * Test: atest com.android.server.job.controllers.JobStatusTest
Christopher Tate7060b042014-06-09 19:50:00 -070064 * @hide
65 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -080066public final class JobStatus {
Dianne Hackborna47223f2017-03-30 13:49:13 -070067 static final String TAG = "JobSchedulerService";
Christopher Tate616541d2017-07-26 14:27:38 -070068 static final boolean DEBUG = JobSchedulerService.DEBUG;
Dianne Hackborna47223f2017-03-30 13:49:13 -070069
Christopher Tate7060b042014-06-09 19:50:00 -070070 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
71 public static final long NO_EARLIEST_RUNTIME = 0L;
72
Kweku Adams32f44762018-11-02 16:58:32 -070073 static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0
74 static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2
75 static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1
76 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;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080079 static final int CONSTRAINT_CONNECTIVITY = 1<<28;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080080 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
81 static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
Kweku Adams4836f9d2018-11-12 17:04:17 -080082 static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070083 static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
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
Christopher Tate5d346052016-03-08 12:56:08 -0800107 // Soft override: ignore constraints like time that don't affect API availability
108 public static final int OVERRIDE_SOFT = 1;
109 // Full override: ignore all constraints including API-affecting like connectivity
110 public static final int OVERRIDE_FULL = 2;
111
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700112 /** If not specified, trigger update delay is 10 seconds. */
113 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
114
115 /** The minimum possible update delay is 1/2 second. */
116 public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
117
118 /** If not specified, trigger maxumum delay is 2 minutes. */
119 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
120
121 /** The minimum possible update delay is 1 second. */
122 public static final long MIN_TRIGGER_MAX_DELAY = 1000;
123
Christopher Tate7060b042014-06-09 19:50:00 -0700124 final JobInfo job;
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700125 /**
126 * Uid of the package requesting this job. This can differ from the "source"
127 * uid when the job was scheduled on the app's behalf, such as with the jobs
128 * that underly Sync Manager operation.
129 */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000130 final int callingUid;
Jeff Sharkey9252b342018-01-19 07:58:35 +0900131 final int targetSdkVersion;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800132 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -0700133
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700134 /**
135 * Identity of the app in which the job is hosted.
136 */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000137 final String sourcePackageName;
138 final int sourceUserId;
139 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800140 final String sourceTag;
141
142 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000143
Dianne Hackborn342e6032017-04-13 18:04:31 -0700144 private GrantedUriPermissions uriPerms;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700145 private boolean prepared;
146
Christopher Tateb164f012017-04-26 15:41:37 -0700147 static final boolean DEBUG_PREPARE = true;
148 private Throwable unpreparedPoint = null;
149
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800150 /**
151 * Earliest point in the future at which this job will be eligible to run. A value of 0
152 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
153 */
154 private final long earliestRunTimeElapsedMillis;
155 /**
156 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
157 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
158 */
159 private final long latestRunTimeElapsedMillis;
160
161 /** How many times this job has failed, used to compute back-off. */
162 private final int numFailures;
163
Christopher Tatea732f012017-10-26 17:26:53 -0700164 /**
165 * Current standby heartbeat when this job was scheduled or last ran. Used to
166 * pin the runnability check regardless of the job's app moving between buckets.
167 */
168 private final long baseHeartbeat;
169
170 /**
171 * Which app standby bucket this job's app is in. Updated when the app is moved to a
172 * different bucket.
173 */
174 private int standbyBucket;
175
176 /**
177 * Debugging: timestamp if we ever defer this job based on standby bucketing, this
178 * is when we did so.
179 */
180 private long whenStandbyDeferred;
181
Christopher Tate7060b042014-06-09 19:50:00 -0700182 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800183 final int requiredConstraints;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700184 private final int mRequiredConstraintsOfInterest;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800185 int satisfiedConstraints = 0;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700186 private int mSatisfiedConstraintsOfInterest = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800187
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700188 // Set to true if doze constraint was satisfied due to app being whitelisted.
189 public boolean dozeWhitelisted;
190
Christopher Tate20afddd2018-02-28 15:19:19 -0800191 // Set to true when the app is "active" per AppStateTracker
192 public boolean uidActive;
193
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700194 /**
195 * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
196 */
197 public static final int TRACKING_BATTERY = 1<<0;
198 /**
199 * Flag for {@link #trackingControllers}: the network connectivity controller is currently
200 * tracking this job.
201 */
202 public static final int TRACKING_CONNECTIVITY = 1<<1;
203 /**
204 * Flag for {@link #trackingControllers}: the content observer controller is currently
205 * tracking this job.
206 */
207 public static final int TRACKING_CONTENT = 1<<2;
208 /**
209 * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job.
210 */
211 public static final int TRACKING_IDLE = 1<<3;
212 /**
213 * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job.
214 */
215 public static final int TRACKING_STORAGE = 1<<4;
216 /**
217 * Flag for {@link #trackingControllers}: the time controller is currently tracking this job.
218 */
219 public static final int TRACKING_TIME = 1<<5;
Kweku Adams4836f9d2018-11-12 17:04:17 -0800220 /**
221 * Flag for {@link #trackingControllers}: the quota controller is currently tracking this job.
222 */
223 public static final int TRACKING_QUOTA = 1 << 6;
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700224
225 /**
226 * Bit mask of controllers that are currently tracking the job.
227 */
228 private int trackingControllers;
229
Makoto Onuki15407842018-01-19 14:23:11 -0800230 /**
231 * Flag for {@link #mInternalFlags}: this job was scheduled when the app that owns the job
232 * service (not necessarily the caller) was in the foreground and the job has no time
233 * constraints, which makes it exempted from the battery saver job restriction.
234 *
235 * @hide
236 */
237 public static final int INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION = 1 << 0;
238
239 /**
240 * Versatile, persistable flags for a job that's updated within the system server,
241 * as opposed to {@link JobInfo#flags} that's set by callers.
242 */
243 private int mInternalFlags;
244
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800245 // These are filled in by controllers when preparing for execution.
246 public ArraySet<Uri> changedUris;
247 public ArraySet<String> changedAuthorities;
Jeff Sharkey76a02412017-10-24 16:55:04 -0600248 public Network network;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800249
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800250 public int lastEvaluatedPriority;
251
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700252 // If non-null, this is work that has been enqueued for the job.
253 public ArrayList<JobWorkItem> pendingWork;
254
255 // If non-null, this is work that is currently being executed.
256 public ArrayList<JobWorkItem> executingWork;
257
258 public int nextPendingWorkId = 1;
259
Christopher Tate5d346052016-03-08 12:56:08 -0800260 // Used by shell commands
261 public int overrideState = 0;
262
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700263 // When this job was enqueued, for ordering. (in elapsedRealtimeMillis)
264 public long enqueueTime;
265
266 // Metrics about queue latency. (in uptimeMillis)
Christopher Tate7234fc62017-04-03 17:36:07 -0700267 public long madePending;
268 public long madeActive;
269
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800270 /**
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700271 * Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
272 * for dumpsys.
273 */
274 private long mLastSuccessfulRunTime;
275
276 /**
277 * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
278 */
279 private long mLastFailedRunTime;
280
281 /**
Christopher Tate616541d2017-07-26 14:27:38 -0700282 * Transient: when a job is inflated from disk before we have a reliable RTC clock time,
283 * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent
284 * store in UTC so that we can fix up the job's scheduling criteria once we get a good
285 * wall-clock time. If we have to persist the job again before the clock has been updated,
286 * we record these times again rather than calculating based on the earliest/latest elapsed
287 * time base figures.
288 *
289 * 'first' is the earliest/delay time, and 'second' is the latest/deadline time.
290 */
291 private Pair<Long, Long> mPersistedUtcTimes;
292
293 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800294 * For use only by ContentObserverController: state it is maintaining about content URIs
295 * being observed.
296 */
297 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -0700298
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600299 private long totalNetworkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
300
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700301 /////// Booleans that track if a job is ready to run. They should be updated whenever dependent
302 /////// states change.
303
304 /**
305 * The deadline for the job has passed. This is only good for non-periodic jobs. A periodic job
306 * should only run if its constraints are satisfied.
307 * Computed as: NOT periodic AND has deadline constraint AND deadline constraint satisfied.
308 */
309 private boolean mReadyDeadlineSatisfied;
310
311 /**
312 * The device isn't Dozing or this job will be in the foreground. This implicit constraint must
313 * be satisfied.
314 */
315 private boolean mReadyNotDozing;
316
317 /**
318 * The job is not restricted from running in the background (due to Battery Saver). This
319 * implicit constraint must be satisfied.
320 */
321 private boolean mReadyNotRestrictedInBg;
322
Kweku Adams4836f9d2018-11-12 17:04:17 -0800323 /** The job is within its quota based on its standby bucket. */
324 private boolean mReadyWithinQuota;
325
Christopher Tate7060b042014-06-09 19:50:00 -0700326 /** Provide a handle to the service that this job will be run on. */
327 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000328 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700329 }
330
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700331 /**
332 * Core constructor for JobStatus instances. All other ctors funnel down to this one.
333 *
334 * @param job The actual requested parameters for the job
335 * @param callingUid Identity of the app that is scheduling the job. This may not be the
336 * app in which the job is implemented; such as with sync jobs.
337 * @param targetSdkVersion The targetSdkVersion of the app in which the job will run.
338 * @param sourcePackageName The package name of the app in which the job will run.
339 * @param sourceUserId The user in which the job will run
340 * @param standbyBucket The standby bucket that the source package is currently assigned to,
341 * cached here for speed of handling during runnability evaluations (and updated when bucket
342 * assignments are changed)
343 * @param heartbeat Timestamp of when the job was created, in the standby-related
344 * timebase.
345 * @param tag A string associated with the job for debugging/logging purposes.
346 * @param numFailures Count of how many times this job has requested a reschedule because
347 * its work was not yet finished.
348 * @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job
349 * is to be considered runnable
350 * @param latestRunTimeElapsedMillis Milestone: point in time at which the job will be
351 * considered overdue
352 * @param lastSuccessfulRunTime When did we last run this job to completion?
353 * @param lastFailedRunTime When did we last run this job only to have it stop incomplete?
354 * @param internalFlags Non-API property flags about this job
355 */
Jeff Sharkey9252b342018-01-19 07:58:35 +0900356 private JobStatus(JobInfo job, int callingUid, int targetSdkVersion, String sourcePackageName,
Christopher Tatea732f012017-10-26 17:26:53 -0700357 int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures,
358 long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800359 long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
Christopher Tate7060b042014-06-09 19:50:00 -0700360 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000361 this.callingUid = callingUid;
Jeff Sharkey9252b342018-01-19 07:58:35 +0900362 this.targetSdkVersion = targetSdkVersion;
Christopher Tatea732f012017-10-26 17:26:53 -0700363 this.standbyBucket = standbyBucket;
364 this.baseHeartbeat = heartbeat;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000365
366 int tempSourceUid = -1;
367 if (sourceUserId != -1 && sourcePackageName != null) {
368 try {
369 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
370 sourceUserId);
371 } catch (RemoteException ex) {
372 // Can't happen, PackageManager runs in the same process.
373 }
374 }
375 if (tempSourceUid == -1) {
376 this.sourceUid = callingUid;
377 this.sourceUserId = UserHandle.getUserId(callingUid);
378 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800379 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000380 } else {
381 this.sourceUid = tempSourceUid;
382 this.sourceUserId = sourceUserId;
383 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800384 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000385 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800386
Shreyas Basargeeda34e42016-04-26 00:14:02 +0100387 this.batteryName = this.sourceTag != null
388 ? this.sourceTag + ":" + job.getService().getPackageName()
389 : job.getService().flattenToShortString();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800390 this.tag = "*job*/" + this.batteryName;
391
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800392 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
393 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
394 this.numFailures = numFailures;
395
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800396 int requiredConstraints = job.getConstraintFlags();
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700397 if (job.getRequiredNetwork() != null) {
398 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800399 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800400 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
401 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
402 }
403 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
404 requiredConstraints |= CONSTRAINT_DEADLINE;
405 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800406 if (job.getTriggerContentUris() != null) {
407 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
408 }
409 this.requiredConstraints = requiredConstraints;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700410 mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
411 mReadyNotDozing = (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700412
413 mLastSuccessfulRunTime = lastSuccessfulRunTime;
414 mLastFailedRunTime = lastFailedRunTime;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600415
Makoto Onuki15407842018-01-19 14:23:11 -0800416 mInternalFlags = internalFlags;
417
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600418 updateEstimatedNetworkBytesLocked();
Jeff Sharkeyfb0f9712018-02-21 20:27:48 -0700419
420 if (job.getRequiredNetwork() != null) {
421 // Later, when we check if a given network satisfies the required
422 // network, we need to know the UID that is requesting it, so push
423 // our source UID into place.
424 job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
425 }
Christopher Tate7060b042014-06-09 19:50:00 -0700426 }
427
Christopher Tate616541d2017-07-26 14:27:38 -0700428 /** Copy constructor: used specifically when cloning JobStatus objects for persistence,
429 * so we preserve RTC window bounds if the source object has them. */
Matthew Williams0cc76542015-10-16 21:04:51 -0700430 public JobStatus(JobStatus jobStatus) {
Jeff Sharkey9252b342018-01-19 07:58:35 +0900431 this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.targetSdkVersion,
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800432 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Christopher Tatea732f012017-10-26 17:26:53 -0700433 jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800434 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700435 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
Makoto Onuki15407842018-01-19 14:23:11 -0800436 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
437 jobStatus.getInternalFlags());
Christopher Tate616541d2017-07-26 14:27:38 -0700438 mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
439 if (jobStatus.mPersistedUtcTimes != null) {
440 if (DEBUG) {
441 Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here"));
442 }
443 }
Christopher Tate7060b042014-06-09 19:50:00 -0700444 }
445
446 /**
447 * Create a new JobStatus that was loaded from disk. We ignore the provided
448 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
449 * from the {@link com.android.server.job.JobStore} and still want to respect its
450 * wallclock runtime rather than resetting it on every boot.
Christopher Tatea732f012017-10-26 17:26:53 -0700451 * We consider a freshly loaded job to no longer be in back-off, and the associated
452 * standby bucket is whatever the OS thinks it should be at this moment.
Christopher Tate7060b042014-06-09 19:50:00 -0700453 */
Christopher Tatea732f012017-10-26 17:26:53 -0700454 public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId,
455 int standbyBucket, long baseHeartbeat, String sourceTag,
456 long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
Christopher Tate616541d2017-07-26 14:27:38 -0700457 long lastSuccessfulRunTime, long lastFailedRunTime,
Makoto Onuki15407842018-01-19 14:23:11 -0800458 Pair<Long, Long> persistedExecutionTimesUTC,
459 int innerFlags) {
Jeff Sharkey9252b342018-01-19 07:58:35 +0900460 this(job, callingUid, resolveTargetSdkVersion(job), sourcePkgName, sourceUserId,
Christopher Tatea732f012017-10-26 17:26:53 -0700461 standbyBucket, baseHeartbeat,
462 sourceTag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700463 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800464 lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
Christopher Tate616541d2017-07-26 14:27:38 -0700465
466 // Only during initial inflation do we record the UTC-timebase execution bounds
467 // read from the persistent store. If we ever have to recreate the JobStatus on
468 // the fly, it means we're rescheduling the job; and this means that the calculated
469 // elapsed timebase bounds intrinsically become correct.
470 this.mPersistedUtcTimes = persistedExecutionTimesUTC;
471 if (persistedExecutionTimesUTC != null) {
472 if (DEBUG) {
473 Slog.i(TAG, "+ restored job with RTC times because of bad boot clock");
474 }
475 }
Christopher Tate7060b042014-06-09 19:50:00 -0700476 }
477
478 /** Create a new job to be rescheduled with the provided parameters. */
Christopher Tatea732f012017-10-26 17:26:53 -0700479 public JobStatus(JobStatus rescheduling, long newBaseHeartbeat,
480 long newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700481 long newLatestRuntimeElapsedMillis, int backoffAttempt,
482 long lastSuccessfulRunTime, long lastFailedRunTime) {
Jeff Sharkey9252b342018-01-19 07:58:35 +0900483 this(rescheduling.job, rescheduling.getUid(), resolveTargetSdkVersion(rescheduling.job),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800484 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
Christopher Tatea732f012017-10-26 17:26:53 -0700485 rescheduling.getStandbyBucket(), newBaseHeartbeat,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800486 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700487 newLatestRuntimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800488 lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags());
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800489 }
Christopher Tate7060b042014-06-09 19:50:00 -0700490
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800491 /**
492 * Create a newly scheduled job.
493 * @param callingUid Uid of the package that scheduled this job.
Christopher Tate72a0b2a2018-03-19 17:24:32 -0700494 * @param sourcePkg Package name of the app that will actually run the job. Null indicates
495 * that the calling package is the source.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800496 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
Christopher Tatea732f012017-10-26 17:26:53 -0700497 * caller.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800498 */
Christopher Tatea732f012017-10-26 17:26:53 -0700499 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePkg,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800500 int sourceUserId, String tag) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700501 final long elapsedNow = sElapsedRealtimeClock.millis();
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800502 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
503 if (job.isPeriodic()) {
504 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
505 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
506 } else {
507 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
508 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
509 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
510 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
511 }
Christopher Tatea732f012017-10-26 17:26:53 -0700512 String jobPackage = (sourcePkg != null) ? sourcePkg : job.getService().getPackageName();
513
514 int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
515 sourceUserId, elapsedNow);
516 JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
Christopher Tate435c2f42018-01-18 12:59:15 -0800517 long currentHeartbeat = js != null
518 ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket)
519 : 0;
Jeff Sharkey9252b342018-01-19 07:58:35 +0900520 return new JobStatus(job, callingUid, resolveTargetSdkVersion(job), sourcePkg, sourceUserId,
Christopher Tatea732f012017-10-26 17:26:53 -0700521 standbyBucket, currentHeartbeat, tag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700522 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
Makoto Onuki15407842018-01-19 14:23:11 -0800523 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
524 /*innerFlags=*/ 0);
Christopher Tate7060b042014-06-09 19:50:00 -0700525 }
526
Dianne Hackborn342e6032017-04-13 18:04:31 -0700527 public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700528 if (pendingWork == null) {
529 pendingWork = new ArrayList<>();
530 }
531 work.setWorkId(nextPendingWorkId);
532 nextPendingWorkId++;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700533 if (work.getIntent() != null
534 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) {
535 work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid,
536 sourcePackageName, sourceUserId, toShortString()));
537 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700538 pendingWork.add(work);
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600539 updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700540 }
541
542 public JobWorkItem dequeueWorkLocked() {
543 if (pendingWork != null && pendingWork.size() > 0) {
544 JobWorkItem work = pendingWork.remove(0);
545 if (work != null) {
546 if (executingWork == null) {
547 executingWork = new ArrayList<>();
548 }
549 executingWork.add(work);
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700550 work.bumpDeliveryCount();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700551 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600552 updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700553 return work;
554 }
555 return null;
556 }
557
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700558 public boolean hasWorkLocked() {
559 return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
560 }
561
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700562 public boolean hasExecutingWorkLocked() {
563 return executingWork != null && executingWork.size() > 0;
564 }
565
Dianne Hackborn342e6032017-04-13 18:04:31 -0700566 private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) {
567 if (work.getGrants() != null) {
568 ((GrantedUriPermissions)work.getGrants()).revoke(am);
569 }
570 }
571
572 public boolean completeWorkLocked(IActivityManager am, int workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700573 if (executingWork != null) {
574 final int N = executingWork.size();
575 for (int i = 0; i < N; i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700576 JobWorkItem work = executingWork.get(i);
577 if (work.getWorkId() == workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700578 executingWork.remove(i);
Dianne Hackborn342e6032017-04-13 18:04:31 -0700579 ungrantWorkItem(am, work);
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700580 return true;
581 }
582 }
583 }
584 return false;
585 }
586
Dianne Hackborn342e6032017-04-13 18:04:31 -0700587 private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) {
588 if (list != null) {
589 final int N = list.size();
590 for (int i = 0; i < N; i++) {
591 ungrantWorkItem(am, list.get(i));
592 }
593 }
594 }
595
596 public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700597 if (incomingJob != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700598 // We are replacing with a new job -- transfer the work! We do any executing
599 // work first, since that was originally at the front of the pending work.
600 if (executingWork != null && executingWork.size() > 0) {
601 incomingJob.pendingWork = executingWork;
602 }
603 if (incomingJob.pendingWork == null) {
604 incomingJob.pendingWork = pendingWork;
605 } else if (pendingWork != null && pendingWork.size() > 0) {
606 incomingJob.pendingWork.addAll(pendingWork);
607 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700608 pendingWork = null;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700609 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700610 incomingJob.nextPendingWorkId = nextPendingWorkId;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600611 incomingJob.updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700612 } else {
613 // We are completely stopping the job... need to clean up work.
Dianne Hackborn342e6032017-04-13 18:04:31 -0700614 ungrantWorkList(am, pendingWork);
615 pendingWork = null;
616 ungrantWorkList(am, executingWork);
617 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700618 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600619 updateEstimatedNetworkBytesLocked();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700620 }
621
622 public void prepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700623 if (prepared) {
624 Slog.wtf(TAG, "Already prepared: " + this);
625 return;
626 }
627 prepared = true;
Christopher Tateb164f012017-04-26 15:41:37 -0700628 if (DEBUG_PREPARE) {
629 unpreparedPoint = null;
630 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700631 final ClipData clip = job.getClipData();
632 if (clip != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700633 uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName,
634 sourceUserId, job.getClipGrantFlags(), toShortString());
Dianne Hackborna47223f2017-03-30 13:49:13 -0700635 }
636 }
637
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700638 public void unprepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700639 if (!prepared) {
640 Slog.wtf(TAG, "Hasn't been prepared: " + this);
Christopher Tateb164f012017-04-26 15:41:37 -0700641 if (DEBUG_PREPARE && unpreparedPoint != null) {
642 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint);
643 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700644 return;
645 }
646 prepared = false;
Christopher Tateb164f012017-04-26 15:41:37 -0700647 if (DEBUG_PREPARE) {
648 unpreparedPoint = new Throwable().fillInStackTrace();
649 }
Dianne Hackborn342e6032017-04-13 18:04:31 -0700650 if (uriPerms != null) {
651 uriPerms.revoke(am);
652 uriPerms = null;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700653 }
654 }
655
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700656 public boolean isPreparedLocked() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700657 return prepared;
658 }
659
Christopher Tate7060b042014-06-09 19:50:00 -0700660 public JobInfo getJob() {
661 return job;
662 }
663
664 public int getJobId() {
665 return job.getId();
666 }
667
Jeff Sharkey9252b342018-01-19 07:58:35 +0900668 public int getTargetSdkVersion() {
669 return targetSdkVersion;
670 }
671
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700672 public void printUniqueId(PrintWriter pw) {
673 UserHandle.formatUid(pw, callingUid);
674 pw.print("/");
675 pw.print(job.getId());
676 }
677
Christopher Tate7060b042014-06-09 19:50:00 -0700678 public int getNumFailures() {
679 return numFailures;
680 }
681
682 public ComponentName getServiceComponent() {
683 return job.getService();
684 }
685
Shreyas Basarge968ac752016-01-11 23:09:26 +0000686 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000687 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000688 }
689
690 public int getSourceUid() {
691 return sourceUid;
692 }
693
694 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000695 return sourceUserId;
696 }
697
Christopher Tate7060b042014-06-09 19:50:00 -0700698 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000699 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700700 }
701
Christopher Tatea732f012017-10-26 17:26:53 -0700702 public int getStandbyBucket() {
703 return standbyBucket;
704 }
705
706 public long getBaseHeartbeat() {
707 return baseHeartbeat;
708 }
709
Christopher Tatea732f012017-10-26 17:26:53 -0700710 public void setStandbyBucket(int newBucket) {
711 standbyBucket = newBucket;
712 }
713
714 // Called only by the standby monitoring code
715 public long getWhenStandbyDeferred() {
716 return whenStandbyDeferred;
717 }
718
719 // Called only by the standby monitoring code
720 public void setWhenStandbyDeferred(long now) {
721 whenStandbyDeferred = now;
722 }
723
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800724 public String getSourceTag() {
725 return sourceTag;
726 }
727
Christopher Tate7060b042014-06-09 19:50:00 -0700728 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000729 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700730 }
731
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800732 public String getBatteryName() {
733 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700734 }
735
736 public String getTag() {
737 return tag;
738 }
739
Shreyas Basarge5db09082016-01-07 13:38:29 +0000740 public int getPriority() {
741 return job.getPriority();
742 }
Christopher Tate7060b042014-06-09 19:50:00 -0700743
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600744 public int getFlags() {
745 return job.getFlags();
746 }
747
Makoto Onuki15407842018-01-19 14:23:11 -0800748 public int getInternalFlags() {
749 return mInternalFlags;
750 }
751
752 public void addInternalFlags(int flags) {
753 mInternalFlags |= flags;
754 }
755
Serik Beketayev75915d12018-08-01 16:56:59 -0700756 public int getSatisfiedConstraintFlags() {
757 return satisfiedConstraints;
758 }
759
Makoto Onuki15407842018-01-19 14:23:11 -0800760 public void maybeAddForegroundExemption(Predicate<Integer> uidForegroundChecker) {
761 // Jobs with time constraints shouldn't be exempted.
762 if (job.hasEarlyConstraint() || job.hasLateConstraint()) {
763 return;
764 }
765 // Already exempted, skip the foreground check.
766 if ((mInternalFlags & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
767 return;
768 }
769 if (uidForegroundChecker.test(getSourceUid())) {
770 addInternalFlags(INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION);
771 }
772 }
773
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600774 private void updateEstimatedNetworkBytesLocked() {
775 totalNetworkBytes = computeEstimatedNetworkBytesLocked();
776 }
777
778 private long computeEstimatedNetworkBytesLocked() {
779 // If any component of the job has unknown usage, we don't have a
780 // complete picture of what data will be used, and we have to treat the
781 // entire job as unknown.
782 long totalNetworkBytes = 0;
783 long networkBytes = job.getEstimatedNetworkBytes();
784 if (networkBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
785 return JobInfo.NETWORK_BYTES_UNKNOWN;
786 } else {
787 totalNetworkBytes += networkBytes;
788 }
789 if (pendingWork != null) {
790 for (int i = 0; i < pendingWork.size(); i++) {
791 networkBytes = pendingWork.get(i).getEstimatedNetworkBytes();
792 if (networkBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
793 return JobInfo.NETWORK_BYTES_UNKNOWN;
794 } else {
795 totalNetworkBytes += networkBytes;
796 }
797 }
798 }
799 return totalNetworkBytes;
800 }
801
802 public long getEstimatedNetworkBytes() {
803 return totalNetworkBytes;
804 }
805
Christopher Tate60977f42017-04-13 13:48:46 -0700806 /** Does this job have any sort of networking constraint? */
Christopher Tate7060b042014-06-09 19:50:00 -0700807 public boolean hasConnectivityConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800808 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700809 }
810
Christopher Tate7060b042014-06-09 19:50:00 -0700811 public boolean hasChargingConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800812 return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700813 }
814
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800815 public boolean hasBatteryNotLowConstraint() {
816 return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0;
817 }
818
819 public boolean hasPowerConstraint() {
820 return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0;
821 }
822
Dianne Hackborn532ea262017-03-17 17:50:55 -0700823 public boolean hasStorageNotLowConstraint() {
824 return (requiredConstraints&CONSTRAINT_STORAGE_NOT_LOW) != 0;
825 }
826
Christopher Tate7060b042014-06-09 19:50:00 -0700827 public boolean hasTimingDelayConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800828 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700829 }
830
831 public boolean hasDeadlineConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800832 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700833 }
834
835 public boolean hasIdleConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800836 return (requiredConstraints&CONSTRAINT_IDLE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700837 }
838
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800839 public boolean hasContentTriggerConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800840 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800841 }
842
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700843 public long getTriggerContentUpdateDelay() {
844 long time = job.getTriggerContentUpdateDelay();
845 if (time < 0) {
846 return DEFAULT_TRIGGER_UPDATE_DELAY;
847 }
848 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
849 }
850
851 public long getTriggerContentMaxDelay() {
852 long time = job.getTriggerContentMaxDelay();
853 if (time < 0) {
854 return DEFAULT_TRIGGER_MAX_DELAY;
855 }
856 return Math.max(time, MIN_TRIGGER_MAX_DELAY);
857 }
858
Matthew Williams900c67f2014-07-09 12:46:53 -0700859 public boolean isPersisted() {
860 return job.isPersisted();
861 }
862
Christopher Tate7060b042014-06-09 19:50:00 -0700863 public long getEarliestRunTime() {
864 return earliestRunTimeElapsedMillis;
865 }
866
867 public long getLatestRunTimeElapsed() {
868 return latestRunTimeElapsedMillis;
869 }
870
Jeff Sharkey9252b342018-01-19 07:58:35 +0900871 /**
872 * Return the fractional position of "now" within the "run time" window of
873 * this job.
874 * <p>
875 * For example, if the earliest run time was 10 minutes ago, and the latest
876 * run time is 30 minutes from now, this would return 0.25.
877 * <p>
878 * If the job has no window defined, returns 1. When only an earliest or
879 * latest time is defined, it's treated as an infinitely small window at
880 * that time.
881 */
882 public float getFractionRunTime() {
883 final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
884 if (earliestRunTimeElapsedMillis == 0 && latestRunTimeElapsedMillis == Long.MAX_VALUE) {
885 return 1;
886 } else if (earliestRunTimeElapsedMillis == 0) {
887 return now >= latestRunTimeElapsedMillis ? 1 : 0;
888 } else if (latestRunTimeElapsedMillis == Long.MAX_VALUE) {
889 return now >= earliestRunTimeElapsedMillis ? 1 : 0;
890 } else {
891 if (now <= earliestRunTimeElapsedMillis) {
892 return 0;
893 } else if (now >= latestRunTimeElapsedMillis) {
894 return 1;
895 } else {
896 return (float) (now - earliestRunTimeElapsedMillis)
897 / (float) (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis);
898 }
899 }
900 }
901
Christopher Tate616541d2017-07-26 14:27:38 -0700902 public Pair<Long, Long> getPersistedUtcTimes() {
903 return mPersistedUtcTimes;
904 }
905
906 public void clearPersistedUtcTimes() {
907 mPersistedUtcTimes = null;
908 }
909
Kweku Adams4836f9d2018-11-12 17:04:17 -0800910 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800911 boolean setChargingConstraintSatisfied(boolean state) {
912 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
913 }
914
Kweku Adams4836f9d2018-11-12 17:04:17 -0800915 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800916 boolean setBatteryNotLowConstraintSatisfied(boolean state) {
917 return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
918 }
919
Kweku Adams4836f9d2018-11-12 17:04:17 -0800920 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackborn532ea262017-03-17 17:50:55 -0700921 boolean setStorageNotLowConstraintSatisfied(boolean state) {
922 return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
923 }
924
Kweku Adams4836f9d2018-11-12 17:04:17 -0800925 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800926 boolean setTimingDelayConstraintSatisfied(boolean state) {
927 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
928 }
929
Kweku Adams4836f9d2018-11-12 17:04:17 -0800930 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800931 boolean setDeadlineConstraintSatisfied(boolean state) {
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700932 if (setConstraintSatisfied(CONSTRAINT_DEADLINE, state)) {
933 // The constraint was changed. Update the ready flag.
934 mReadyDeadlineSatisfied = !job.isPeriodic() && hasDeadlineConstraint() && state;
935 return true;
936 }
937 return false;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800938 }
939
Kweku Adams4836f9d2018-11-12 17:04:17 -0800940 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800941 boolean setIdleConstraintSatisfied(boolean state) {
942 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
943 }
944
Kweku Adams4836f9d2018-11-12 17:04:17 -0800945 /** @return true if the constraint was changed, false otherwise. */
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600946 boolean setConnectivityConstraintSatisfied(boolean state) {
947 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
948 }
949
Kweku Adams4836f9d2018-11-12 17:04:17 -0800950 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800951 boolean setContentTriggerConstraintSatisfied(boolean state) {
952 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
953 }
954
Kweku Adams4836f9d2018-11-12 17:04:17 -0800955 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700956 boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
957 dozeWhitelisted = whitelisted;
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700958 if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state)) {
959 // The constraint was changed. Update the ready flag.
960 mReadyNotDozing = state || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
961 return true;
962 }
963 return false;
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700964 }
965
Kweku Adams4836f9d2018-11-12 17:04:17 -0800966 /** @return true if the constraint was changed, false otherwise. */
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700967 boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) {
Kweku Adamsd14ce4d2018-10-19 11:40:55 -0700968 if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state)) {
969 // The constraint was changed. Update the ready flag.
970 mReadyNotRestrictedInBg = state;
971 return true;
972 }
973 return false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700974 }
975
Kweku Adams4836f9d2018-11-12 17:04:17 -0800976 /** @return true if the constraint was changed, false otherwise. */
977 boolean setQuotaConstraintSatisfied(boolean state) {
978 if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, state)) {
979 // The constraint was changed. Update the ready flag.
980 mReadyWithinQuota = state;
981 return true;
982 }
983 return false;
984 }
985
986 /** @return true if the state was changed, false otherwise. */
Christopher Tate20afddd2018-02-28 15:19:19 -0800987 boolean setUidActive(final boolean newActiveState) {
988 if (newActiveState != uidActive) {
989 uidActive = newActiveState;
990 return true;
991 }
992 return false; /* unchanged */
993 }
994
Kweku Adams4836f9d2018-11-12 17:04:17 -0800995 /** @return true if the constraint was changed, false otherwise. */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800996 boolean setConstraintSatisfied(int constraint, boolean state) {
997 boolean old = (satisfiedConstraints&constraint) != 0;
998 if (old == state) {
999 return false;
1000 }
1001 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001002 mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
Kweku Adams8845d012018-12-11 20:06:45 -08001003 if ((STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
1004 StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
1005 sourceUid, null, getBatteryName(), getProtoConstraint(constraint),
1006 state ? StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
1007 : StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
1008 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001009 return true;
1010 }
1011
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001012 boolean isConstraintSatisfied(int constraint) {
1013 return (satisfiedConstraints&constraint) != 0;
1014 }
1015
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001016 boolean clearTrackingController(int which) {
1017 if ((trackingControllers&which) != 0) {
1018 trackingControllers &= ~which;
1019 return true;
1020 }
1021 return false;
1022 }
1023
1024 void setTrackingController(int which) {
1025 trackingControllers |= which;
1026 }
1027
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001028 public long getLastSuccessfulRunTime() {
1029 return mLastSuccessfulRunTime;
1030 }
1031
1032 public long getLastFailedRunTime() {
1033 return mLastFailedRunTime;
1034 }
1035
Christopher Tate7060b042014-06-09 19:50:00 -07001036 /**
Kweku Adams32f44762018-11-02 16:58:32 -07001037 * @return Whether or not this job is ready to run, based on its requirements.
Christopher Tate7060b042014-06-09 19:50:00 -07001038 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -08001039 public boolean isReady() {
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001040 return isReady(mSatisfiedConstraintsOfInterest);
1041 }
1042
1043 /**
1044 * @return Whether or not this job would be ready to run if it had the specified constraint
1045 * granted, based on its requirements.
1046 */
1047 public boolean wouldBeReadyWithConstraint(int constraint) {
1048 return isReady(mSatisfiedConstraintsOfInterest | constraint);
1049 }
1050
1051 private boolean isReady(int satisfiedConstraints) {
Kweku Adams4836f9d2018-11-12 17:04:17 -08001052 // Quota constraints trumps all other constraints.
1053 if (!mReadyWithinQuota) {
1054 return false;
1055 }
1056 // Deadline constraint trumps other constraints besides quota (except for periodic jobs
1057 // where deadline is an implementation detail. A periodic job should only run if its
1058 // constraints are satisfied).
Amith Yamasanicb926fc2016-03-14 17:15:20 -07001059 // DeviceNotDozing implicit constraint must be satisfied
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001060 // NotRestrictedInBackground implicit constraint must be satisfied
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001061 return mReadyNotDozing && mReadyNotRestrictedInBg && (mReadyDeadlineSatisfied
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001062 || isConstraintsSatisfied(satisfiedConstraints));
Matthew Williams03a4da62014-09-10 17:32:18 -07001063 }
1064
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001065 static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
1066 | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_CONNECTIVITY
1067 | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001068
Christopher Tate5d346052016-03-08 12:56:08 -08001069 // Soft override covers all non-"functional" constraints
1070 static final int SOFT_OVERRIDE_CONSTRAINTS =
Dianne Hackborn532ea262017-03-17 17:50:55 -07001071 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001072 | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
Christopher Tate5d346052016-03-08 12:56:08 -08001073
Matthew Williams03a4da62014-09-10 17:32:18 -07001074 /**
1075 * @return Whether the constraints set on this job are satisfied.
1076 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -08001077 public boolean isConstraintsSatisfied() {
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001078 return isConstraintsSatisfied(mSatisfiedConstraintsOfInterest);
1079 }
1080
1081 private boolean isConstraintsSatisfied(int satisfiedConstraints) {
Christopher Tate5d346052016-03-08 12:56:08 -08001082 if (overrideState == OVERRIDE_FULL) {
1083 // force override: the job is always runnable
1084 return true;
1085 }
1086
Kweku Adamscdbfcb92018-12-06 17:05:15 -08001087 int sat = satisfiedConstraints;
Christopher Tate5d346052016-03-08 12:56:08 -08001088 if (overrideState == OVERRIDE_SOFT) {
1089 // override: pretend all 'soft' requirements are satisfied
1090 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
1091 }
1092
Kweku Adamsd14ce4d2018-10-19 11:40:55 -07001093 return (sat & mRequiredConstraintsOfInterest) == mRequiredConstraintsOfInterest;
Christopher Tate7060b042014-06-09 19:50:00 -07001094 }
1095
1096 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +00001097 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -07001098 }
1099
1100 @Override
1101 public String toString() {
Dianne Hackborna47223f2017-03-30 13:49:13 -07001102 StringBuilder sb = new StringBuilder(128);
1103 sb.append("JobStatus{");
1104 sb.append(Integer.toHexString(System.identityHashCode(this)));
1105 sb.append(" #");
1106 UserHandle.formatUid(sb, callingUid);
1107 sb.append("/");
1108 sb.append(job.getId());
1109 sb.append(' ');
1110 sb.append(batteryName);
1111 sb.append(" u=");
1112 sb.append(getUserId());
1113 sb.append(" s=");
1114 sb.append(getSourceUid());
1115 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
1116 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001117 long now = sElapsedRealtimeClock.millis();
Dianne Hackborna47223f2017-03-30 13:49:13 -07001118 sb.append(" TIME=");
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001119 formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
1120 sb.append(":");
1121 formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
Dianne Hackborna47223f2017-03-30 13:49:13 -07001122 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001123 if (job.getRequiredNetwork() != null) {
1124 sb.append(" NET");
Dianne Hackborna47223f2017-03-30 13:49:13 -07001125 }
1126 if (job.isRequireCharging()) {
1127 sb.append(" CHARGING");
1128 }
1129 if (job.isRequireBatteryNotLow()) {
1130 sb.append(" BATNOTLOW");
1131 }
1132 if (job.isRequireStorageNotLow()) {
1133 sb.append(" STORENOTLOW");
1134 }
1135 if (job.isRequireDeviceIdle()) {
1136 sb.append(" IDLE");
1137 }
Christopher Tate616541d2017-07-26 14:27:38 -07001138 if (job.isPeriodic()) {
1139 sb.append(" PERIODIC");
1140 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001141 if (job.isPersisted()) {
1142 sb.append(" PERSISTED");
1143 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001144 if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
1145 sb.append(" WAIT:DEV_NOT_DOZING");
1146 }
1147 if (job.getTriggerContentUris() != null) {
1148 sb.append(" URIS=");
1149 sb.append(Arrays.toString(job.getTriggerContentUris()));
1150 }
1151 if (numFailures != 0) {
1152 sb.append(" failures=");
1153 sb.append(numFailures);
1154 }
1155 if (isReady()) {
1156 sb.append(" READY");
1157 }
1158 sb.append("}");
1159 return sb.toString();
Christopher Tate7060b042014-06-09 19:50:00 -07001160 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001161
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001162 private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001163 if (runtime == defaultValue) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001164 pw.print("none");
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001165 } else {
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001166 TimeUtils.formatDuration(runtime - now, pw);
1167 }
1168 }
1169
1170 private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) {
1171 if (runtime == defaultValue) {
1172 sb.append("none");
1173 } else {
1174 TimeUtils.formatDuration(runtime - now, sb);
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001175 }
1176 }
1177
1178 /**
1179 * Convenience function to identify a job uniquely without pulling all the data that
1180 * {@link #toString()} returns.
1181 */
1182 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001183 StringBuilder sb = new StringBuilder();
1184 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001185 sb.append(" #");
1186 UserHandle.formatUid(sb, callingUid);
1187 sb.append("/");
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001188 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001189 sb.append(' ');
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001190 sb.append(batteryName);
1191 return sb.toString();
1192 }
1193
1194 /**
1195 * Convenience function to identify a job uniquely without pulling all the data that
1196 * {@link #toString()} returns.
1197 */
1198 public String toShortStringExceptUniqueId() {
1199 StringBuilder sb = new StringBuilder();
1200 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001201 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -08001202 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001203 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001204 }
1205
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001206 /**
1207 * Convenience function to dump data that identifies a job uniquely to proto. This is intended
1208 * to mimic {@link #toShortString}.
1209 */
1210 public void writeToShortProto(ProtoOutputStream proto, long fieldId) {
1211 final long token = proto.start(fieldId);
1212
1213 proto.write(JobStatusShortInfoProto.CALLING_UID, callingUid);
1214 proto.write(JobStatusShortInfoProto.JOB_ID, job.getId());
1215 proto.write(JobStatusShortInfoProto.BATTERY_NAME, batteryName);
1216
1217 proto.end(token);
1218 }
1219
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001220 void dumpConstraints(PrintWriter pw, int constraints) {
1221 if ((constraints&CONSTRAINT_CHARGING) != 0) {
1222 pw.print(" CHARGING");
1223 }
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001224 if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
1225 pw.print(" BATTERY_NOT_LOW");
1226 }
Dianne Hackborn532ea262017-03-17 17:50:55 -07001227 if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) {
1228 pw.print(" STORAGE_NOT_LOW");
1229 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001230 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
1231 pw.print(" TIMING_DELAY");
1232 }
1233 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
1234 pw.print(" DEADLINE");
1235 }
1236 if ((constraints&CONSTRAINT_IDLE) != 0) {
1237 pw.print(" IDLE");
1238 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -06001239 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
1240 pw.print(" CONNECTIVITY");
1241 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001242 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
1243 pw.print(" CONTENT_TRIGGER");
1244 }
Amith Yamasanicb926fc2016-03-14 17:15:20 -07001245 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
1246 pw.print(" DEVICE_NOT_DOZING");
1247 }
Makoto Onukidfede0a2018-01-22 15:11:34 -08001248 if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
1249 pw.print(" BACKGROUND_NOT_RESTRICTED");
1250 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001251 if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
1252 pw.print(" WITHIN_QUOTA");
1253 }
Makoto Onukidfede0a2018-01-22 15:11:34 -08001254 if (constraints != 0) {
1255 pw.print(" [0x");
1256 pw.print(Integer.toHexString(constraints));
1257 pw.print("]");
1258 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001259 }
1260
Kweku Adams8845d012018-12-11 20:06:45 -08001261 /** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */
1262 private int getProtoConstraint(int constraint) {
1263 switch (constraint) {
1264 case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
1265 return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
1266 case CONSTRAINT_BATTERY_NOT_LOW:
1267 return JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW;
1268 case CONSTRAINT_CHARGING:
1269 return JobServerProtoEnums.CONSTRAINT_CHARGING;
1270 case CONSTRAINT_CONNECTIVITY:
1271 return JobServerProtoEnums.CONSTRAINT_CONNECTIVITY;
1272 case CONSTRAINT_CONTENT_TRIGGER:
1273 return JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER;
1274 case CONSTRAINT_DEADLINE:
1275 return JobServerProtoEnums.CONSTRAINT_DEADLINE;
1276 case CONSTRAINT_DEVICE_NOT_DOZING:
1277 return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING;
1278 case CONSTRAINT_IDLE:
1279 return JobServerProtoEnums.CONSTRAINT_IDLE;
1280 case CONSTRAINT_STORAGE_NOT_LOW:
1281 return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
1282 case CONSTRAINT_TIMING_DELAY:
1283 return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
1284 case CONSTRAINT_WITHIN_QUOTA:
1285 return JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA;
1286 default:
1287 return JobServerProtoEnums.CONSTRAINT_UNKNOWN;
1288 }
1289 }
1290
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001291 /** Writes constraints to the given repeating proto field. */
1292 void dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints) {
1293 if ((constraints & CONSTRAINT_CHARGING) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001294 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CHARGING);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001295 }
1296 if ((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001297 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001298 }
1299 if ((constraints & CONSTRAINT_STORAGE_NOT_LOW) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001300 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001301 }
1302 if ((constraints & CONSTRAINT_TIMING_DELAY) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001303 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_TIMING_DELAY);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001304 }
1305 if ((constraints & CONSTRAINT_DEADLINE) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001306 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEADLINE);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001307 }
1308 if ((constraints & CONSTRAINT_IDLE) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001309 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_IDLE);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001310 }
1311 if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001312 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONNECTIVITY);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001313 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001314 if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001315 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001316 }
1317 if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001318 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001319 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001320 if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
Kweku Adams8845d012018-12-11 20:06:45 -08001321 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA);
1322 }
1323 if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
1324 proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED);
Kweku Adams4836f9d2018-11-12 17:04:17 -08001325 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001326 }
1327
Dianne Hackborn342e6032017-04-13 18:04:31 -07001328 private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
1329 pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #");
Dianne Hackborn28d1b662017-04-21 14:17:23 -07001330 pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
1331 pw.print("x "); pw.println(work.getIntent());
Dianne Hackborn342e6032017-04-13 18:04:31 -07001332 if (work.getGrants() != null) {
1333 pw.print(prefix); pw.println(" URI grants:");
1334 ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " ");
1335 }
1336 }
1337
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001338 private void dumpJobWorkItem(ProtoOutputStream proto, long fieldId, JobWorkItem work) {
1339 final long token = proto.start(fieldId);
1340
1341 proto.write(JobStatusDumpProto.JobWorkItem.WORK_ID, work.getWorkId());
1342 proto.write(JobStatusDumpProto.JobWorkItem.DELIVERY_COUNT, work.getDeliveryCount());
1343 if (work.getIntent() != null) {
1344 work.getIntent().writeToProto(proto, JobStatusDumpProto.JobWorkItem.INTENT);
1345 }
1346 Object grants = work.getGrants();
1347 if (grants != null) {
1348 ((GrantedUriPermissions) grants).dump(proto, JobStatusDumpProto.JobWorkItem.URI_GRANTS);
1349 }
1350
1351 proto.end(token);
1352 }
1353
Kweku Adams32f44762018-11-02 16:58:32 -07001354 /**
1355 * Returns a bucket name based on the normalized bucket indices, not the AppStandby constants.
1356 */
1357 String getBucketName() {
Kweku Adams4836f9d2018-11-12 17:04:17 -08001358 return bucketName(standbyBucket);
1359 }
1360
1361 /**
1362 * Returns a bucket name based on the normalized bucket indices, not the AppStandby constants.
1363 */
1364 static String bucketName(int standbyBucket) {
Kweku Adams32f44762018-11-02 16:58:32 -07001365 switch (standbyBucket) {
Christopher Tatea732f012017-10-26 17:26:53 -07001366 case 0: return "ACTIVE";
1367 case 1: return "WORKING_SET";
1368 case 2: return "FREQUENT";
1369 case 3: return "RARE";
1370 case 4: return "NEVER";
1371 default:
Kweku Adams32f44762018-11-02 16:58:32 -07001372 return "Unknown: " + standbyBucket;
Christopher Tatea732f012017-10-26 17:26:53 -07001373 }
1374 }
1375
Jeff Sharkey9252b342018-01-19 07:58:35 +09001376 private static int resolveTargetSdkVersion(JobInfo job) {
1377 return LocalServices.getService(PackageManagerInternal.class)
1378 .getPackageTargetSdkVersion(job.getService().getPackageName());
1379 }
1380
Christopher Tate7060b042014-06-09 19:50:00 -07001381 // Dumpsys infrastructure
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001382 public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +00001383 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001384 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -07001385 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +00001386 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
1387 pw.print(" user="); pw.print(getSourceUserId());
1388 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001389 if (full) {
Dianne Hackborna47223f2017-03-30 13:49:13 -07001390 pw.print(prefix); pw.println("JobInfo:");
1391 pw.print(prefix); pw.print(" Service: ");
1392 pw.println(job.getService().flattenToShortString());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001393 if (job.isPeriodic()) {
1394 pw.print(prefix); pw.print(" PERIODIC: interval=");
1395 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
1396 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
1397 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001398 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001399 if (job.isPersisted()) {
1400 pw.print(prefix); pw.println(" PERSISTED");
1401 }
1402 if (job.getPriority() != 0) {
Makoto Onukiec8b14d2018-12-05 13:22:24 -08001403 pw.print(prefix); pw.print(" Priority: ");
1404 pw.println(JobInfo.getPriorityString(job.getPriority()));
Dianne Hackborn970510b2016-02-24 16:56:42 -08001405 }
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001406 if (job.getFlags() != 0) {
1407 pw.print(prefix); pw.print(" Flags: ");
1408 pw.println(Integer.toHexString(job.getFlags()));
1409 }
Makoto Onuki15407842018-01-19 14:23:11 -08001410 if (getInternalFlags() != 0) {
1411 pw.print(prefix); pw.print(" Internal flags: ");
1412 pw.print(Integer.toHexString(getInternalFlags()));
1413
1414 if ((getInternalFlags()&INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
1415 pw.print(" HAS_FOREGROUND_EXEMPTION");
1416 }
1417 pw.println();
1418 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001419 pw.print(prefix); pw.print(" Requires: charging=");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001420 pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
1421 pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
Dianne Hackborn970510b2016-02-24 16:56:42 -08001422 pw.println(job.isRequireDeviceIdle());
1423 if (job.getTriggerContentUris() != null) {
1424 pw.print(prefix); pw.println(" Trigger content URIs:");
1425 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
1426 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
1427 pw.print(prefix); pw.print(" ");
1428 pw.print(Integer.toHexString(trig.getFlags()));
1429 pw.print(' '); pw.println(trig.getUri());
1430 }
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001431 if (job.getTriggerContentUpdateDelay() >= 0) {
1432 pw.print(prefix); pw.print(" Trigger update delay: ");
1433 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
1434 pw.println();
1435 }
1436 if (job.getTriggerContentMaxDelay() >= 0) {
1437 pw.print(prefix); pw.print(" Trigger max delay: ");
1438 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
1439 pw.println();
1440 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001441 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001442 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
1443 pw.print(prefix); pw.print(" Extras: ");
1444 pw.println(job.getExtras().toShortString());
1445 }
1446 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
1447 pw.print(prefix); pw.print(" Transient extras: ");
1448 pw.println(job.getTransientExtras().toShortString());
1449 }
1450 if (job.getClipData() != null) {
1451 pw.print(prefix); pw.print(" Clip data: ");
1452 StringBuilder b = new StringBuilder(128);
1453 job.getClipData().toShortString(b);
1454 pw.println(b);
1455 }
Dianne Hackborn342e6032017-04-13 18:04:31 -07001456 if (uriPerms != null) {
1457 pw.print(prefix); pw.println(" Granted URI permissions:");
1458 uriPerms.dump(pw, prefix + " ");
1459 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001460 if (job.getRequiredNetwork() != null) {
1461 pw.print(prefix); pw.print(" Network type: ");
1462 pw.println(job.getRequiredNetwork());
Dianne Hackborn970510b2016-02-24 16:56:42 -08001463 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001464 if (totalNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001465 pw.print(prefix); pw.print(" Network bytes: ");
1466 pw.println(totalNetworkBytes);
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001467 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001468 if (job.getMinLatencyMillis() != 0) {
1469 pw.print(prefix); pw.print(" Minimum latency: ");
1470 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
1471 pw.println();
1472 }
1473 if (job.getMaxExecutionDelayMillis() != 0) {
1474 pw.print(prefix); pw.print(" Max execution delay: ");
1475 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
1476 pw.println();
1477 }
1478 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
1479 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001480 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001481 if (job.hasEarlyConstraint()) {
1482 pw.print(prefix); pw.println(" Has early constraint");
1483 }
1484 if (job.hasLateConstraint()) {
1485 pw.print(prefix); pw.println(" Has late constraint");
1486 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001487 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001488 pw.print(prefix); pw.print("Required constraints:");
1489 dumpConstraints(pw, requiredConstraints);
1490 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001491 if (full) {
1492 pw.print(prefix); pw.print("Satisfied constraints:");
1493 dumpConstraints(pw, satisfiedConstraints);
1494 pw.println();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001495 pw.print(prefix); pw.print("Unsatisfied constraints:");
Kweku Adams4836f9d2018-11-12 17:04:17 -08001496 dumpConstraints(pw,
1497 ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001498 pw.println();
Dianne Hackborn7ab40252016-06-15 17:30:24 -07001499 if (dozeWhitelisted) {
1500 pw.print(prefix); pw.println("Doze whitelisted: true");
1501 }
Christopher Tate20afddd2018-02-28 15:19:19 -08001502 if (uidActive) {
1503 pw.print(prefix); pw.println("Uid: active");
1504 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001505 if (job.isExemptedFromAppStandby()) {
1506 pw.print(prefix); pw.println("Is exempted from app standby");
1507 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001508 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001509 if (trackingControllers != 0) {
1510 pw.print(prefix); pw.print("Tracking:");
1511 if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY");
1512 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY");
1513 if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT");
1514 if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE");
1515 if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE");
1516 if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME");
Kweku Adams4836f9d2018-11-12 17:04:17 -08001517 if ((trackingControllers & TRACKING_QUOTA) != 0) pw.print(" QUOTA");
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001518 pw.println();
1519 }
Kweku Adams32f44762018-11-02 16:58:32 -07001520
1521 pw.print(prefix); pw.println("Implicit constraints:");
1522 pw.print(prefix); pw.print(" readyNotDozing: ");
1523 pw.println(mReadyNotDozing);
1524 pw.print(prefix); pw.print(" readyNotRestrictedInBg: ");
1525 pw.println(mReadyNotRestrictedInBg);
1526 if (!job.isPeriodic() && hasDeadlineConstraint()) {
1527 pw.print(prefix); pw.print(" readyDeadlineSatisfied: ");
1528 pw.println(mReadyDeadlineSatisfied);
1529 }
1530
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001531 if (changedAuthorities != null) {
1532 pw.print(prefix); pw.println("Changed authorities:");
1533 for (int i=0; i<changedAuthorities.size(); i++) {
1534 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
1535 }
1536 if (changedUris != null) {
1537 pw.print(prefix); pw.println("Changed URIs:");
1538 for (int i=0; i<changedUris.size(); i++) {
1539 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i));
1540 }
1541 }
1542 }
Jeff Sharkey76a02412017-10-24 16:55:04 -06001543 if (network != null) {
1544 pw.print(prefix); pw.print("Network: "); pw.println(network);
1545 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001546 if (pendingWork != null && pendingWork.size() > 0) {
1547 pw.print(prefix); pw.println("Pending work:");
1548 for (int i = 0; i < pendingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001549 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001550 }
1551 }
1552 if (executingWork != null && executingWork.size() > 0) {
1553 pw.print(prefix); pw.println("Executing work:");
1554 for (int i = 0; i < executingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001555 dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001556 }
1557 }
Christopher Tatea732f012017-10-26 17:26:53 -07001558 pw.print(prefix); pw.print("Standby bucket: ");
Kweku Adams32f44762018-11-02 16:58:32 -07001559 pw.println(getBucketName());
Christopher Tated1aebb32018-01-31 13:24:14 -08001560 if (standbyBucket > 0) {
1561 pw.print(prefix); pw.print("Base heartbeat: ");
1562 pw.println(baseHeartbeat);
1563 }
1564 if (whenStandbyDeferred != 0) {
1565 pw.print(prefix); pw.print(" Deferred since: ");
1566 TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
1567 pw.println();
1568 }
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001569 pw.print(prefix); pw.print("Enqueue time: ");
1570 TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
1571 pw.println();
1572 pw.print(prefix); pw.print("Run time: earliest=");
1573 formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
1574 pw.print(", latest=");
1575 formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
1576 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001577 if (numFailures != 0) {
1578 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
1579 }
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001580 final Time t = new Time();
1581 final String format = "%Y-%m-%d %H:%M:%S";
1582 if (mLastSuccessfulRunTime != 0) {
1583 pw.print(prefix); pw.print("Last successful run: ");
1584 t.set(mLastSuccessfulRunTime);
1585 pw.println(t.format(format));
1586 }
1587 if (mLastFailedRunTime != 0) {
1588 pw.print(prefix); pw.print("Last failed run: ");
1589 t.set(mLastFailedRunTime);
1590 pw.println(t.format(format));
1591 }
Christopher Tate7060b042014-06-09 19:50:00 -07001592 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001593
1594 public void dump(ProtoOutputStream proto, long fieldId, boolean full, long elapsedRealtimeMillis) {
1595 final long token = proto.start(fieldId);
1596
1597 proto.write(JobStatusDumpProto.CALLING_UID, callingUid);
1598 proto.write(JobStatusDumpProto.TAG, tag);
1599 proto.write(JobStatusDumpProto.SOURCE_UID, getSourceUid());
1600 proto.write(JobStatusDumpProto.SOURCE_USER_ID, getSourceUserId());
1601 proto.write(JobStatusDumpProto.SOURCE_PACKAGE_NAME, getSourcePackageName());
Makoto Onuki15407842018-01-19 14:23:11 -08001602 proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001603
1604 if (full) {
1605 final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO);
1606
1607 job.getService().writeToProto(proto, JobStatusDumpProto.JobInfo.SERVICE);
1608
1609 proto.write(JobStatusDumpProto.JobInfo.IS_PERIODIC, job.isPeriodic());
1610 proto.write(JobStatusDumpProto.JobInfo.PERIOD_INTERVAL_MS, job.getIntervalMillis());
1611 proto.write(JobStatusDumpProto.JobInfo.PERIOD_FLEX_MS, job.getFlexMillis());
1612
1613 proto.write(JobStatusDumpProto.JobInfo.IS_PERSISTED, job.isPersisted());
1614 proto.write(JobStatusDumpProto.JobInfo.PRIORITY, job.getPriority());
1615 proto.write(JobStatusDumpProto.JobInfo.FLAGS, job.getFlags());
1616
1617 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_CHARGING, job.isRequireCharging());
1618 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_BATTERY_NOT_LOW, job.isRequireBatteryNotLow());
1619 proto.write(JobStatusDumpProto.JobInfo.REQUIRES_DEVICE_IDLE, job.isRequireDeviceIdle());
1620
1621 if (job.getTriggerContentUris() != null) {
1622 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
1623 final long tcuToken = proto.start(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_URIS);
1624 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
1625
1626 proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.FLAGS, trig.getFlags());
1627 Uri u = trig.getUri();
1628 if (u != null) {
1629 proto.write(JobStatusDumpProto.JobInfo.TriggerContentUri.URI, u.toString());
1630 }
1631
1632 proto.end(tcuToken);
1633 }
1634 if (job.getTriggerContentUpdateDelay() >= 0) {
1635 proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_UPDATE_DELAY_MS,
1636 job.getTriggerContentUpdateDelay());
1637 }
1638 if (job.getTriggerContentMaxDelay() >= 0) {
1639 proto.write(JobStatusDumpProto.JobInfo.TRIGGER_CONTENT_MAX_DELAY_MS,
1640 job.getTriggerContentMaxDelay());
1641 }
1642 }
1643 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
1644 job.getExtras().writeToProto(proto, JobStatusDumpProto.JobInfo.EXTRAS);
1645 }
1646 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
1647 job.getTransientExtras().writeToProto(proto, JobStatusDumpProto.JobInfo.TRANSIENT_EXTRAS);
1648 }
1649 if (job.getClipData() != null) {
1650 job.getClipData().writeToProto(proto, JobStatusDumpProto.JobInfo.CLIP_DATA);
1651 }
1652 if (uriPerms != null) {
1653 uriPerms.dump(proto, JobStatusDumpProto.JobInfo.GRANTED_URI_PERMISSIONS);
1654 }
1655 if (job.getRequiredNetwork() != null) {
1656 job.getRequiredNetwork().writeToProto(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK);
1657 }
1658 if (totalNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
1659 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_BYTES, totalNetworkBytes);
1660 }
1661 proto.write(JobStatusDumpProto.JobInfo.MIN_LATENCY_MS, job.getMinLatencyMillis());
1662 proto.write(JobStatusDumpProto.JobInfo.MAX_EXECUTION_DELAY_MS, job.getMaxExecutionDelayMillis());
1663
1664 final long bpToken = proto.start(JobStatusDumpProto.JobInfo.BACKOFF_POLICY);
1665 proto.write(JobStatusDumpProto.JobInfo.Backoff.POLICY, job.getBackoffPolicy());
1666 proto.write(JobStatusDumpProto.JobInfo.Backoff.INITIAL_BACKOFF_MS,
1667 job.getInitialBackoffMillis());
1668 proto.end(bpToken);
1669
1670 proto.write(JobStatusDumpProto.JobInfo.HAS_EARLY_CONSTRAINT, job.hasEarlyConstraint());
1671 proto.write(JobStatusDumpProto.JobInfo.HAS_LATE_CONSTRAINT, job.hasLateConstraint());
1672
1673 proto.end(jiToken);
1674 }
1675
1676 dumpConstraints(proto, JobStatusDumpProto.REQUIRED_CONSTRAINTS, requiredConstraints);
1677 if (full) {
1678 dumpConstraints(proto, JobStatusDumpProto.SATISFIED_CONSTRAINTS, satisfiedConstraints);
1679 dumpConstraints(proto, JobStatusDumpProto.UNSATISFIED_CONSTRAINTS,
Kweku Adams4836f9d2018-11-12 17:04:17 -08001680 ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001681 proto.write(JobStatusDumpProto.IS_DOZE_WHITELISTED, dozeWhitelisted);
Kweku Adams4836f9d2018-11-12 17:04:17 -08001682 proto.write(JobStatusDumpProto.IS_UID_ACTIVE, uidActive);
1683 proto.write(JobStatusDumpProto.IS_EXEMPTED_FROM_APP_STANDBY,
1684 job.isExemptedFromAppStandby());
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001685 }
1686
1687 // Tracking controllers
1688 if ((trackingControllers&TRACKING_BATTERY) != 0) {
1689 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1690 JobStatusDumpProto.TRACKING_BATTERY);
1691 }
1692 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) {
1693 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1694 JobStatusDumpProto.TRACKING_CONNECTIVITY);
1695 }
1696 if ((trackingControllers&TRACKING_CONTENT) != 0) {
1697 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1698 JobStatusDumpProto.TRACKING_CONTENT);
1699 }
1700 if ((trackingControllers&TRACKING_IDLE) != 0) {
1701 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1702 JobStatusDumpProto.TRACKING_IDLE);
1703 }
1704 if ((trackingControllers&TRACKING_STORAGE) != 0) {
1705 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1706 JobStatusDumpProto.TRACKING_STORAGE);
1707 }
1708 if ((trackingControllers&TRACKING_TIME) != 0) {
1709 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1710 JobStatusDumpProto.TRACKING_TIME);
1711 }
Kweku Adams4836f9d2018-11-12 17:04:17 -08001712 if ((trackingControllers & TRACKING_QUOTA) != 0) {
1713 proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
1714 JobStatusDumpProto.TRACKING_QUOTA);
1715 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001716
Kweku Adams32f44762018-11-02 16:58:32 -07001717 // Implicit constraints
1718 final long icToken = proto.start(JobStatusDumpProto.IMPLICIT_CONSTRAINTS);
1719 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_DOZING, mReadyNotDozing);
1720 proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_RESTRICTED_IN_BG,
1721 mReadyNotRestrictedInBg);
1722 proto.end(icToken);
1723
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001724 if (changedAuthorities != null) {
1725 for (int k = 0; k < changedAuthorities.size(); k++) {
1726 proto.write(JobStatusDumpProto.CHANGED_AUTHORITIES, changedAuthorities.valueAt(k));
1727 }
1728 }
1729 if (changedUris != null) {
1730 for (int i = 0; i < changedUris.size(); i++) {
1731 Uri u = changedUris.valueAt(i);
1732 proto.write(JobStatusDumpProto.CHANGED_URIS, u.toString());
1733 }
1734 }
1735
1736 if (network != null) {
1737 network.writeToProto(proto, JobStatusDumpProto.NETWORK);
1738 }
1739
1740 if (pendingWork != null && pendingWork.size() > 0) {
1741 for (int i = 0; i < pendingWork.size(); i++) {
1742 dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i));
1743 }
1744 }
1745 if (executingWork != null && executingWork.size() > 0) {
1746 for (int i = 0; i < executingWork.size(); i++) {
1747 dumpJobWorkItem(proto, JobStatusDumpProto.EXECUTING_WORK, executingWork.get(i));
1748 }
1749 }
1750
1751 proto.write(JobStatusDumpProto.STANDBY_BUCKET, standbyBucket);
1752 proto.write(JobStatusDumpProto.ENQUEUE_DURATION_MS, elapsedRealtimeMillis - enqueueTime);
1753 if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) {
1754 proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS, 0);
1755 } else {
1756 proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS,
1757 earliestRunTimeElapsedMillis - elapsedRealtimeMillis);
1758 }
1759 if (latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) {
1760 proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS, 0);
1761 } else {
1762 proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS,
1763 latestRunTimeElapsedMillis - elapsedRealtimeMillis);
1764 }
1765
1766 proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures);
1767 proto.write(JobStatusDumpProto.LAST_SUCCESSFUL_RUN_TIME, mLastSuccessfulRunTime);
1768 proto.write(JobStatusDumpProto.LAST_FAILED_RUN_TIME, mLastFailedRunTime);
1769
1770 proto.end(token);
1771 }
Christopher Tate7060b042014-06-09 19:50:00 -07001772}