blob: 23caa8cfa7017f1d69077c31d524c5faea68ce61 [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
Shreyas Basarge968ac752016-01-11 23:09:26 +000019import android.app.AppGlobals;
Dianne Hackborna47223f2017-03-30 13:49:13 -070020import android.app.IActivityManager;
Christopher Tate7060b042014-06-09 19:50:00 -070021import android.app.job.JobInfo;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070022import android.app.job.JobWorkItem;
Dianne Hackborna47223f2017-03-30 13:49:13 -070023import android.content.ClipData;
Christopher Tate7060b042014-06-09 19:50:00 -070024import android.content.ComponentName;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080025import android.net.Uri;
Shreyas Basarge968ac752016-01-11 23:09:26 +000026import android.os.RemoteException;
Christopher Tate7060b042014-06-09 19:50:00 -070027import android.os.SystemClock;
28import android.os.UserHandle;
Makoto Onukiab8a67f2017-06-20 12:20:34 -070029import android.text.format.Time;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080030import android.util.ArraySet;
Christopher Tate616541d2017-07-26 14:27:38 -070031import android.util.Pair;
Dianne Hackborna47223f2017-03-30 13:49:13 -070032import android.util.Slog;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080033import android.util.TimeUtils;
Christopher Tate7060b042014-06-09 19:50:00 -070034
Dianne Hackborn342e6032017-04-13 18:04:31 -070035import com.android.server.job.GrantedUriPermissions;
Christopher Tate616541d2017-07-26 14:27:38 -070036import com.android.server.job.JobSchedulerService;
Dianne Hackborn342e6032017-04-13 18:04:31 -070037
Christopher Tate7060b042014-06-09 19:50:00 -070038import java.io.PrintWriter;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070039import java.util.ArrayList;
Dianne Hackborna47223f2017-03-30 13:49:13 -070040import java.util.Arrays;
Christopher Tate7060b042014-06-09 19:50:00 -070041
42/**
43 * Uniquely identifies a job internally.
44 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
45 * Contains current state of the requirements of the job, as well as a function to evaluate
46 * whether it's ready to run.
47 * This object is shared among the various controllers - hence why the different fields are atomic.
48 * This isn't strictly necessary because each controller is only interested in a specific field,
49 * and the receivers that are listening for global state change will all run on the main looper,
50 * but we don't enforce that so this is safer.
51 * @hide
52 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -080053public final class JobStatus {
Dianne Hackborna47223f2017-03-30 13:49:13 -070054 static final String TAG = "JobSchedulerService";
Christopher Tate616541d2017-07-26 14:27:38 -070055 static final boolean DEBUG = JobSchedulerService.DEBUG;
Dianne Hackborna47223f2017-03-30 13:49:13 -070056
Christopher Tate7060b042014-06-09 19:50:00 -070057 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
58 public static final long NO_EARLIEST_RUNTIME = 0L;
59
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080060 static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING;
61 static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;
62 static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW;
Dianne Hackborn532ea262017-03-17 17:50:55 -070063 static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080064 static final int CONSTRAINT_TIMING_DELAY = 1<<31;
65 static final int CONSTRAINT_DEADLINE = 1<<30;
66 static final int CONSTRAINT_UNMETERED = 1<<29;
67 static final int CONSTRAINT_CONNECTIVITY = 1<<28;
68 static final int CONSTRAINT_APP_NOT_IDLE = 1<<27;
69 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
70 static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
71 static final int CONSTRAINT_NOT_ROAMING = 1<<24;
Christopher Tate60977f42017-04-13 13:48:46 -070072 static final int CONSTRAINT_METERED = 1<<23;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070073 static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
Christopher Tate60977f42017-04-13 13:48:46 -070074
75 static final int CONNECTIVITY_MASK =
76 CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY |
77 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED;
Dianne Hackbornb0001f62016-02-16 10:30:33 -080078
Christopher Tate5d346052016-03-08 12:56:08 -080079 // Soft override: ignore constraints like time that don't affect API availability
80 public static final int OVERRIDE_SOFT = 1;
81 // Full override: ignore all constraints including API-affecting like connectivity
82 public static final int OVERRIDE_FULL = 2;
83
Dianne Hackborn8db0fc12016-04-12 13:48:25 -070084 /** If not specified, trigger update delay is 10 seconds. */
85 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
86
87 /** The minimum possible update delay is 1/2 second. */
88 public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
89
90 /** If not specified, trigger maxumum delay is 2 minutes. */
91 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
92
93 /** The minimum possible update delay is 1 second. */
94 public static final long MIN_TRIGGER_MAX_DELAY = 1000;
95
Christopher Tate7060b042014-06-09 19:50:00 -070096 final JobInfo job;
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070097 /** Uid of the package requesting this job. */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000098 final int callingUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080099 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -0700100
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000101 final String sourcePackageName;
102 final int sourceUserId;
103 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800104 final String sourceTag;
105
106 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000107
Dianne Hackborn342e6032017-04-13 18:04:31 -0700108 private GrantedUriPermissions uriPerms;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700109 private boolean prepared;
110
Christopher Tateb164f012017-04-26 15:41:37 -0700111 static final boolean DEBUG_PREPARE = true;
112 private Throwable unpreparedPoint = null;
113
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800114 /**
115 * Earliest point in the future at which this job will be eligible to run. A value of 0
116 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
117 */
118 private final long earliestRunTimeElapsedMillis;
119 /**
120 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
121 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
122 */
123 private final long latestRunTimeElapsedMillis;
124
125 /** How many times this job has failed, used to compute back-off. */
126 private final int numFailures;
127
Christopher Tate7060b042014-06-09 19:50:00 -0700128 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800129 final int requiredConstraints;
130 int satisfiedConstraints = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800131
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700132 // Set to true if doze constraint was satisfied due to app being whitelisted.
133 public boolean dozeWhitelisted;
134
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700135 /**
136 * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
137 */
138 public static final int TRACKING_BATTERY = 1<<0;
139 /**
140 * Flag for {@link #trackingControllers}: the network connectivity controller is currently
141 * tracking this job.
142 */
143 public static final int TRACKING_CONNECTIVITY = 1<<1;
144 /**
145 * Flag for {@link #trackingControllers}: the content observer controller is currently
146 * tracking this job.
147 */
148 public static final int TRACKING_CONTENT = 1<<2;
149 /**
150 * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job.
151 */
152 public static final int TRACKING_IDLE = 1<<3;
153 /**
154 * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job.
155 */
156 public static final int TRACKING_STORAGE = 1<<4;
157 /**
158 * Flag for {@link #trackingControllers}: the time controller is currently tracking this job.
159 */
160 public static final int TRACKING_TIME = 1<<5;
161
162 /**
163 * Bit mask of controllers that are currently tracking the job.
164 */
165 private int trackingControllers;
166
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800167 // These are filled in by controllers when preparing for execution.
168 public ArraySet<Uri> changedUris;
169 public ArraySet<String> changedAuthorities;
170
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800171 public int lastEvaluatedPriority;
172
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700173 // If non-null, this is work that has been enqueued for the job.
174 public ArrayList<JobWorkItem> pendingWork;
175
176 // If non-null, this is work that is currently being executed.
177 public ArrayList<JobWorkItem> executingWork;
178
179 public int nextPendingWorkId = 1;
180
Christopher Tate5d346052016-03-08 12:56:08 -0800181 // Used by shell commands
182 public int overrideState = 0;
183
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700184 // When this job was enqueued, for ordering. (in elapsedRealtimeMillis)
185 public long enqueueTime;
186
187 // Metrics about queue latency. (in uptimeMillis)
Christopher Tate7234fc62017-04-03 17:36:07 -0700188 public long madePending;
189 public long madeActive;
190
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800191 /**
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700192 * Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
193 * for dumpsys.
194 */
195 private long mLastSuccessfulRunTime;
196
197 /**
198 * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
199 */
200 private long mLastFailedRunTime;
201
202 /**
Christopher Tate616541d2017-07-26 14:27:38 -0700203 * Transient: when a job is inflated from disk before we have a reliable RTC clock time,
204 * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent
205 * store in UTC so that we can fix up the job's scheduling criteria once we get a good
206 * wall-clock time. If we have to persist the job again before the clock has been updated,
207 * we record these times again rather than calculating based on the earliest/latest elapsed
208 * time base figures.
209 *
210 * 'first' is the earliest/delay time, and 'second' is the latest/deadline time.
211 */
212 private Pair<Long, Long> mPersistedUtcTimes;
213
214 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800215 * For use only by ContentObserverController: state it is maintaining about content URIs
216 * being observed.
217 */
218 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -0700219
Christopher Tate7060b042014-06-09 19:50:00 -0700220 /** Provide a handle to the service that this job will be run on. */
221 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000222 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700223 }
224
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800225 private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800226 int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700227 long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime) {
Christopher Tate7060b042014-06-09 19:50:00 -0700228 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000229 this.callingUid = callingUid;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000230
231 int tempSourceUid = -1;
232 if (sourceUserId != -1 && sourcePackageName != null) {
233 try {
234 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
235 sourceUserId);
236 } catch (RemoteException ex) {
237 // Can't happen, PackageManager runs in the same process.
238 }
239 }
240 if (tempSourceUid == -1) {
241 this.sourceUid = callingUid;
242 this.sourceUserId = UserHandle.getUserId(callingUid);
243 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800244 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000245 } else {
246 this.sourceUid = tempSourceUid;
247 this.sourceUserId = sourceUserId;
248 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800249 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000250 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800251
Shreyas Basargeeda34e42016-04-26 00:14:02 +0100252 this.batteryName = this.sourceTag != null
253 ? this.sourceTag + ":" + job.getService().getPackageName()
254 : job.getService().flattenToShortString();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800255 this.tag = "*job*/" + this.batteryName;
256
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800257 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
258 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
259 this.numFailures = numFailures;
260
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800261 int requiredConstraints = job.getConstraintFlags();
Christopher Tate60977f42017-04-13 13:48:46 -0700262
263 switch (job.getNetworkType()) {
264 case JobInfo.NETWORK_TYPE_NONE:
265 // No constraint.
266 break;
267 case JobInfo.NETWORK_TYPE_ANY:
268 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
269 break;
270 case JobInfo.NETWORK_TYPE_UNMETERED:
271 requiredConstraints |= CONSTRAINT_UNMETERED;
272 break;
273 case JobInfo.NETWORK_TYPE_NOT_ROAMING:
274 requiredConstraints |= CONSTRAINT_NOT_ROAMING;
275 break;
276 case JobInfo.NETWORK_TYPE_METERED:
277 requiredConstraints |= CONSTRAINT_METERED;
278 break;
279 default:
280 Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType());
281 break;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800282 }
Christopher Tate60977f42017-04-13 13:48:46 -0700283
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800284 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
285 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
286 }
287 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
288 requiredConstraints |= CONSTRAINT_DEADLINE;
289 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800290 if (job.getTriggerContentUris() != null) {
291 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
292 }
293 this.requiredConstraints = requiredConstraints;
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700294
295 mLastSuccessfulRunTime = lastSuccessfulRunTime;
296 mLastFailedRunTime = lastFailedRunTime;
Christopher Tate7060b042014-06-09 19:50:00 -0700297 }
298
Christopher Tate616541d2017-07-26 14:27:38 -0700299 /** Copy constructor: used specifically when cloning JobStatus objects for persistence,
300 * so we preserve RTC window bounds if the source object has them. */
Matthew Williams0cc76542015-10-16 21:04:51 -0700301 public JobStatus(JobStatus jobStatus) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800302 this(jobStatus.getJob(), jobStatus.getUid(),
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800303 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800304 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700305 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
306 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime());
Christopher Tate616541d2017-07-26 14:27:38 -0700307 mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
308 if (jobStatus.mPersistedUtcTimes != null) {
309 if (DEBUG) {
310 Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here"));
311 }
312 }
Christopher Tate7060b042014-06-09 19:50:00 -0700313 }
314
315 /**
316 * Create a new JobStatus that was loaded from disk. We ignore the provided
317 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
318 * from the {@link com.android.server.job.JobStore} and still want to respect its
319 * wallclock runtime rather than resetting it on every boot.
320 * We consider a freshly loaded job to no longer be in back-off.
321 */
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800322 public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700323 String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
Christopher Tate616541d2017-07-26 14:27:38 -0700324 long lastSuccessfulRunTime, long lastFailedRunTime,
325 Pair<Long, Long> persistedExecutionTimesUTC) {
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800326 this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700327 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
328 lastSuccessfulRunTime, lastFailedRunTime);
Christopher Tate616541d2017-07-26 14:27:38 -0700329
330 // Only during initial inflation do we record the UTC-timebase execution bounds
331 // read from the persistent store. If we ever have to recreate the JobStatus on
332 // the fly, it means we're rescheduling the job; and this means that the calculated
333 // elapsed timebase bounds intrinsically become correct.
334 this.mPersistedUtcTimes = persistedExecutionTimesUTC;
335 if (persistedExecutionTimesUTC != null) {
336 if (DEBUG) {
337 Slog.i(TAG, "+ restored job with RTC times because of bad boot clock");
338 }
339 }
Christopher Tate7060b042014-06-09 19:50:00 -0700340 }
341
342 /** Create a new job to be rescheduled with the provided parameters. */
343 public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700344 long newLatestRuntimeElapsedMillis, int backoffAttempt,
345 long lastSuccessfulRunTime, long lastFailedRunTime) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800346 this(rescheduling.job, rescheduling.getUid(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800347 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
348 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700349 newLatestRuntimeElapsedMillis,
350 lastSuccessfulRunTime, lastFailedRunTime);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800351 }
Christopher Tate7060b042014-06-09 19:50:00 -0700352
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800353 /**
354 * Create a newly scheduled job.
355 * @param callingUid Uid of the package that scheduled this job.
356 * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
357 * the calling package is the source.
358 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
359 */
360 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800361 int sourceUserId, String tag) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800362 final long elapsedNow = SystemClock.elapsedRealtime();
363 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
364 if (job.isPeriodic()) {
365 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
366 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
367 } else {
368 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
369 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
370 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
371 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
372 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800373 return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700374 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
375 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
Christopher Tate7060b042014-06-09 19:50:00 -0700376 }
377
Dianne Hackborn342e6032017-04-13 18:04:31 -0700378 public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700379 if (pendingWork == null) {
380 pendingWork = new ArrayList<>();
381 }
382 work.setWorkId(nextPendingWorkId);
383 nextPendingWorkId++;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700384 if (work.getIntent() != null
385 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) {
386 work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid,
387 sourcePackageName, sourceUserId, toShortString()));
388 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700389 pendingWork.add(work);
390 }
391
392 public JobWorkItem dequeueWorkLocked() {
393 if (pendingWork != null && pendingWork.size() > 0) {
394 JobWorkItem work = pendingWork.remove(0);
395 if (work != null) {
396 if (executingWork == null) {
397 executingWork = new ArrayList<>();
398 }
399 executingWork.add(work);
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700400 work.bumpDeliveryCount();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700401 }
402 return work;
403 }
404 return null;
405 }
406
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700407 public boolean hasWorkLocked() {
408 return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
409 }
410
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700411 public boolean hasExecutingWorkLocked() {
412 return executingWork != null && executingWork.size() > 0;
413 }
414
Dianne Hackborn342e6032017-04-13 18:04:31 -0700415 private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) {
416 if (work.getGrants() != null) {
417 ((GrantedUriPermissions)work.getGrants()).revoke(am);
418 }
419 }
420
421 public boolean completeWorkLocked(IActivityManager am, int workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700422 if (executingWork != null) {
423 final int N = executingWork.size();
424 for (int i = 0; i < N; i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700425 JobWorkItem work = executingWork.get(i);
426 if (work.getWorkId() == workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700427 executingWork.remove(i);
Dianne Hackborn342e6032017-04-13 18:04:31 -0700428 ungrantWorkItem(am, work);
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700429 return true;
430 }
431 }
432 }
433 return false;
434 }
435
Dianne Hackborn342e6032017-04-13 18:04:31 -0700436 private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) {
437 if (list != null) {
438 final int N = list.size();
439 for (int i = 0; i < N; i++) {
440 ungrantWorkItem(am, list.get(i));
441 }
442 }
443 }
444
445 public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700446 if (incomingJob != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700447 // We are replacing with a new job -- transfer the work! We do any executing
448 // work first, since that was originally at the front of the pending work.
449 if (executingWork != null && executingWork.size() > 0) {
450 incomingJob.pendingWork = executingWork;
451 }
452 if (incomingJob.pendingWork == null) {
453 incomingJob.pendingWork = pendingWork;
454 } else if (pendingWork != null && pendingWork.size() > 0) {
455 incomingJob.pendingWork.addAll(pendingWork);
456 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700457 pendingWork = null;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700458 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700459 incomingJob.nextPendingWorkId = nextPendingWorkId;
460 } else {
461 // We are completely stopping the job... need to clean up work.
Dianne Hackborn342e6032017-04-13 18:04:31 -0700462 ungrantWorkList(am, pendingWork);
463 pendingWork = null;
464 ungrantWorkList(am, executingWork);
465 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700466 }
467 }
468
469 public void prepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700470 if (prepared) {
471 Slog.wtf(TAG, "Already prepared: " + this);
472 return;
473 }
474 prepared = true;
Christopher Tateb164f012017-04-26 15:41:37 -0700475 if (DEBUG_PREPARE) {
476 unpreparedPoint = null;
477 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700478 final ClipData clip = job.getClipData();
479 if (clip != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700480 uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName,
481 sourceUserId, job.getClipGrantFlags(), toShortString());
Dianne Hackborna47223f2017-03-30 13:49:13 -0700482 }
483 }
484
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700485 public void unprepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700486 if (!prepared) {
487 Slog.wtf(TAG, "Hasn't been prepared: " + this);
Christopher Tateb164f012017-04-26 15:41:37 -0700488 if (DEBUG_PREPARE && unpreparedPoint != null) {
489 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint);
490 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700491 return;
492 }
493 prepared = false;
Christopher Tateb164f012017-04-26 15:41:37 -0700494 if (DEBUG_PREPARE) {
495 unpreparedPoint = new Throwable().fillInStackTrace();
496 }
Dianne Hackborn342e6032017-04-13 18:04:31 -0700497 if (uriPerms != null) {
498 uriPerms.revoke(am);
499 uriPerms = null;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700500 }
501 }
502
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700503 public boolean isPreparedLocked() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700504 return prepared;
505 }
506
Christopher Tate7060b042014-06-09 19:50:00 -0700507 public JobInfo getJob() {
508 return job;
509 }
510
511 public int getJobId() {
512 return job.getId();
513 }
514
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700515 public void printUniqueId(PrintWriter pw) {
516 UserHandle.formatUid(pw, callingUid);
517 pw.print("/");
518 pw.print(job.getId());
519 }
520
Christopher Tate7060b042014-06-09 19:50:00 -0700521 public int getNumFailures() {
522 return numFailures;
523 }
524
525 public ComponentName getServiceComponent() {
526 return job.getService();
527 }
528
Shreyas Basarge968ac752016-01-11 23:09:26 +0000529 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000530 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000531 }
532
533 public int getSourceUid() {
534 return sourceUid;
535 }
536
537 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000538 return sourceUserId;
539 }
540
Christopher Tate7060b042014-06-09 19:50:00 -0700541 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000542 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700543 }
544
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800545 public String getSourceTag() {
546 return sourceTag;
547 }
548
Christopher Tate7060b042014-06-09 19:50:00 -0700549 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000550 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700551 }
552
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800553 public String getBatteryName() {
554 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700555 }
556
557 public String getTag() {
558 return tag;
559 }
560
Shreyas Basarge5db09082016-01-07 13:38:29 +0000561 public int getPriority() {
562 return job.getPriority();
563 }
Christopher Tate7060b042014-06-09 19:50:00 -0700564
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600565 public int getFlags() {
566 return job.getFlags();
567 }
568
Christopher Tate60977f42017-04-13 13:48:46 -0700569 /** Does this job have any sort of networking constraint? */
Christopher Tate7060b042014-06-09 19:50:00 -0700570 public boolean hasConnectivityConstraint() {
Christopher Tate60977f42017-04-13 13:48:46 -0700571 return (requiredConstraints&CONNECTIVITY_MASK) != 0;
572 }
573
574 public boolean needsAnyConnectivity() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800575 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700576 }
577
Christopher Tate60977f42017-04-13 13:48:46 -0700578 public boolean needsUnmeteredConnectivity() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800579 return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700580 }
581
Christopher Tate60977f42017-04-13 13:48:46 -0700582 public boolean needsMeteredConnectivity() {
583 return (requiredConstraints&CONSTRAINT_METERED) != 0;
584 }
585
586 public boolean needsNonRoamingConnectivity() {
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600587 return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0;
588 }
589
Christopher Tate7060b042014-06-09 19:50:00 -0700590 public boolean hasChargingConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800591 return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700592 }
593
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800594 public boolean hasBatteryNotLowConstraint() {
595 return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0;
596 }
597
598 public boolean hasPowerConstraint() {
599 return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0;
600 }
601
Dianne Hackborn532ea262017-03-17 17:50:55 -0700602 public boolean hasStorageNotLowConstraint() {
603 return (requiredConstraints&CONSTRAINT_STORAGE_NOT_LOW) != 0;
604 }
605
Christopher Tate7060b042014-06-09 19:50:00 -0700606 public boolean hasTimingDelayConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800607 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700608 }
609
610 public boolean hasDeadlineConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800611 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700612 }
613
614 public boolean hasIdleConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800615 return (requiredConstraints&CONSTRAINT_IDLE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700616 }
617
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800618 public boolean hasContentTriggerConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800619 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800620 }
621
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700622 public long getTriggerContentUpdateDelay() {
623 long time = job.getTriggerContentUpdateDelay();
624 if (time < 0) {
625 return DEFAULT_TRIGGER_UPDATE_DELAY;
626 }
627 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
628 }
629
630 public long getTriggerContentMaxDelay() {
631 long time = job.getTriggerContentMaxDelay();
632 if (time < 0) {
633 return DEFAULT_TRIGGER_MAX_DELAY;
634 }
635 return Math.max(time, MIN_TRIGGER_MAX_DELAY);
636 }
637
Matthew Williams900c67f2014-07-09 12:46:53 -0700638 public boolean isPersisted() {
639 return job.isPersisted();
640 }
641
Christopher Tate7060b042014-06-09 19:50:00 -0700642 public long getEarliestRunTime() {
643 return earliestRunTimeElapsedMillis;
644 }
645
646 public long getLatestRunTimeElapsed() {
647 return latestRunTimeElapsedMillis;
648 }
649
Christopher Tate616541d2017-07-26 14:27:38 -0700650 public Pair<Long, Long> getPersistedUtcTimes() {
651 return mPersistedUtcTimes;
652 }
653
654 public void clearPersistedUtcTimes() {
655 mPersistedUtcTimes = null;
656 }
657
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800658 boolean setChargingConstraintSatisfied(boolean state) {
659 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
660 }
661
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800662 boolean setBatteryNotLowConstraintSatisfied(boolean state) {
663 return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
664 }
665
Dianne Hackborn532ea262017-03-17 17:50:55 -0700666 boolean setStorageNotLowConstraintSatisfied(boolean state) {
667 return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
668 }
669
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800670 boolean setTimingDelayConstraintSatisfied(boolean state) {
671 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
672 }
673
674 boolean setDeadlineConstraintSatisfied(boolean state) {
675 return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
676 }
677
678 boolean setIdleConstraintSatisfied(boolean state) {
679 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
680 }
681
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600682 boolean setConnectivityConstraintSatisfied(boolean state) {
683 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
684 }
685
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800686 boolean setUnmeteredConstraintSatisfied(boolean state) {
687 return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
688 }
689
Christopher Tate60977f42017-04-13 13:48:46 -0700690 boolean setMeteredConstraintSatisfied(boolean state) {
691 return setConstraintSatisfied(CONSTRAINT_METERED, state);
692 }
693
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600694 boolean setNotRoamingConstraintSatisfied(boolean state) {
695 return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800696 }
697
698 boolean setAppNotIdleConstraintSatisfied(boolean state) {
699 return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
700 }
701
702 boolean setContentTriggerConstraintSatisfied(boolean state) {
703 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
704 }
705
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700706 boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
707 dozeWhitelisted = whitelisted;
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700708 return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
709 }
710
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700711 boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) {
712 return setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state);
713 }
714
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800715 boolean setConstraintSatisfied(int constraint, boolean state) {
716 boolean old = (satisfiedConstraints&constraint) != 0;
717 if (old == state) {
718 return false;
719 }
720 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
721 return true;
722 }
723
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700724 boolean isConstraintSatisfied(int constraint) {
725 return (satisfiedConstraints&constraint) != 0;
726 }
727
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700728 boolean clearTrackingController(int which) {
729 if ((trackingControllers&which) != 0) {
730 trackingControllers &= ~which;
731 return true;
732 }
733 return false;
734 }
735
736 void setTrackingController(int which) {
737 trackingControllers |= which;
738 }
739
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700740 public long getLastSuccessfulRunTime() {
741 return mLastSuccessfulRunTime;
742 }
743
744 public long getLastFailedRunTime() {
745 return mLastFailedRunTime;
746 }
747
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700748 public boolean shouldDump(int filterUid) {
749 return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
750 || UserHandle.getAppId(getSourceUid()) == filterUid;
751 }
752
Christopher Tate7060b042014-06-09 19:50:00 -0700753 /**
Matthew Williams03a4da62014-09-10 17:32:18 -0700754 * @return Whether or not this job is ready to run, based on its requirements. This is true if
755 * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700756 * TODO: This function is called a *lot*. We should probably just have it check an
757 * already-computed boolean, which we updated whenever we see one of the states it depends
758 * on here change.
Christopher Tate7060b042014-06-09 19:50:00 -0700759 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800760 public boolean isReady() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800761 // Deadline constraint trumps other constraints (except for periodic jobs where deadline
Christopher Tate5d346052016-03-08 12:56:08 -0800762 // is an implementation detail. A periodic job should only run if its constraints are
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800763 // satisfied).
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700764 // AppNotIdle implicit constraint must be satisfied
765 // DeviceNotDozing implicit constraint must be satisfied
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700766 // NotRestrictedInBackground implicit constraint must be satisfied
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600767 final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
768 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
769 final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
770 final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
771 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700772 final boolean notRestrictedInBg =
773 (satisfiedConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0;
774 return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing
775 && notRestrictedInBg;
Matthew Williams03a4da62014-09-10 17:32:18 -0700776 }
777
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800778 static final int CONSTRAINTS_OF_INTEREST =
Dianne Hackborn532ea262017-03-17 17:50:55 -0700779 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW |
780 CONSTRAINT_TIMING_DELAY |
Christopher Tate06f08522017-06-13 12:12:09 -0700781 CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
782 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED |
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800783 CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
784
Christopher Tate5d346052016-03-08 12:56:08 -0800785 // Soft override covers all non-"functional" constraints
786 static final int SOFT_OVERRIDE_CONSTRAINTS =
Dianne Hackborn532ea262017-03-17 17:50:55 -0700787 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800788 | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
Christopher Tate5d346052016-03-08 12:56:08 -0800789
Matthew Williams03a4da62014-09-10 17:32:18 -0700790 /**
791 * @return Whether the constraints set on this job are satisfied.
792 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800793 public boolean isConstraintsSatisfied() {
Christopher Tate5d346052016-03-08 12:56:08 -0800794 if (overrideState == OVERRIDE_FULL) {
795 // force override: the job is always runnable
796 return true;
797 }
798
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800799 final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
Christopher Tate5d346052016-03-08 12:56:08 -0800800
801 int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
802 if (overrideState == OVERRIDE_SOFT) {
803 // override: pretend all 'soft' requirements are satisfied
804 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
805 }
806
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800807 return (sat & req) == req;
Christopher Tate7060b042014-06-09 19:50:00 -0700808 }
809
810 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000811 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -0700812 }
813
814 @Override
815 public String toString() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700816 StringBuilder sb = new StringBuilder(128);
817 sb.append("JobStatus{");
818 sb.append(Integer.toHexString(System.identityHashCode(this)));
819 sb.append(" #");
820 UserHandle.formatUid(sb, callingUid);
821 sb.append("/");
822 sb.append(job.getId());
823 sb.append(' ');
824 sb.append(batteryName);
825 sb.append(" u=");
826 sb.append(getUserId());
827 sb.append(" s=");
828 sb.append(getSourceUid());
829 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
830 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700831 long now = SystemClock.elapsedRealtime();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700832 sb.append(" TIME=");
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700833 formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
834 sb.append(":");
835 formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
Dianne Hackborna47223f2017-03-30 13:49:13 -0700836 }
837 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
838 sb.append(" NET=");
839 sb.append(job.getNetworkType());
840 }
841 if (job.isRequireCharging()) {
842 sb.append(" CHARGING");
843 }
844 if (job.isRequireBatteryNotLow()) {
845 sb.append(" BATNOTLOW");
846 }
847 if (job.isRequireStorageNotLow()) {
848 sb.append(" STORENOTLOW");
849 }
850 if (job.isRequireDeviceIdle()) {
851 sb.append(" IDLE");
852 }
Christopher Tate616541d2017-07-26 14:27:38 -0700853 if (job.isPeriodic()) {
854 sb.append(" PERIODIC");
855 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700856 if (job.isPersisted()) {
857 sb.append(" PERSISTED");
858 }
859 if ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) == 0) {
860 sb.append(" WAIT:APP_NOT_IDLE");
861 }
862 if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
863 sb.append(" WAIT:DEV_NOT_DOZING");
864 }
865 if (job.getTriggerContentUris() != null) {
866 sb.append(" URIS=");
867 sb.append(Arrays.toString(job.getTriggerContentUris()));
868 }
869 if (numFailures != 0) {
870 sb.append(" failures=");
871 sb.append(numFailures);
872 }
873 if (isReady()) {
874 sb.append(" READY");
875 }
876 sb.append("}");
877 return sb.toString();
Christopher Tate7060b042014-06-09 19:50:00 -0700878 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700879
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700880 private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700881 if (runtime == defaultValue) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700882 pw.print("none");
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700883 } else {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700884 TimeUtils.formatDuration(runtime - now, pw);
885 }
886 }
887
888 private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) {
889 if (runtime == defaultValue) {
890 sb.append("none");
891 } else {
892 TimeUtils.formatDuration(runtime - now, sb);
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700893 }
894 }
895
896 /**
897 * Convenience function to identify a job uniquely without pulling all the data that
898 * {@link #toString()} returns.
899 */
900 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800901 StringBuilder sb = new StringBuilder();
902 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700903 sb.append(" #");
904 UserHandle.formatUid(sb, callingUid);
905 sb.append("/");
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800906 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800907 sb.append(' ');
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700908 sb.append(batteryName);
909 return sb.toString();
910 }
911
912 /**
913 * Convenience function to identify a job uniquely without pulling all the data that
914 * {@link #toString()} returns.
915 */
916 public String toShortStringExceptUniqueId() {
917 StringBuilder sb = new StringBuilder();
918 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800919 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -0800920 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800921 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700922 }
923
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800924 void dumpConstraints(PrintWriter pw, int constraints) {
925 if ((constraints&CONSTRAINT_CHARGING) != 0) {
926 pw.print(" CHARGING");
927 }
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800928 if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
929 pw.print(" BATTERY_NOT_LOW");
930 }
Dianne Hackborn532ea262017-03-17 17:50:55 -0700931 if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) {
932 pw.print(" STORAGE_NOT_LOW");
933 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800934 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
935 pw.print(" TIMING_DELAY");
936 }
937 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
938 pw.print(" DEADLINE");
939 }
940 if ((constraints&CONSTRAINT_IDLE) != 0) {
941 pw.print(" IDLE");
942 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600943 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
944 pw.print(" CONNECTIVITY");
945 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800946 if ((constraints&CONSTRAINT_UNMETERED) != 0) {
947 pw.print(" UNMETERED");
948 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600949 if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
950 pw.print(" NOT_ROAMING");
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800951 }
Christopher Tate06f08522017-06-13 12:12:09 -0700952 if ((constraints&CONSTRAINT_METERED) != 0) {
953 pw.print(" METERED");
954 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800955 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
956 pw.print(" APP_NOT_IDLE");
957 }
958 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
959 pw.print(" CONTENT_TRIGGER");
960 }
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700961 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
962 pw.print(" DEVICE_NOT_DOZING");
963 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800964 }
965
Dianne Hackborn342e6032017-04-13 18:04:31 -0700966 private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
967 pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #");
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700968 pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
969 pw.print("x "); pw.println(work.getIntent());
Dianne Hackborn342e6032017-04-13 18:04:31 -0700970 if (work.getGrants() != null) {
971 pw.print(prefix); pw.println(" URI grants:");
972 ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " ");
973 }
974 }
975
Christopher Tate7060b042014-06-09 19:50:00 -0700976 // Dumpsys infrastructure
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700977 public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000978 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800979 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -0700980 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000981 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
982 pw.print(" user="); pw.print(getSourceUserId());
983 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800984 if (full) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700985 pw.print(prefix); pw.println("JobInfo:");
986 pw.print(prefix); pw.print(" Service: ");
987 pw.println(job.getService().flattenToShortString());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800988 if (job.isPeriodic()) {
989 pw.print(prefix); pw.print(" PERIODIC: interval=");
990 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
991 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
992 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800993 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800994 if (job.isPersisted()) {
995 pw.print(prefix); pw.println(" PERSISTED");
996 }
997 if (job.getPriority() != 0) {
998 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
999 }
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001000 if (job.getFlags() != 0) {
1001 pw.print(prefix); pw.print(" Flags: ");
1002 pw.println(Integer.toHexString(job.getFlags()));
1003 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001004 pw.print(prefix); pw.print(" Requires: charging=");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001005 pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
1006 pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
Dianne Hackborn970510b2016-02-24 16:56:42 -08001007 pw.println(job.isRequireDeviceIdle());
1008 if (job.getTriggerContentUris() != null) {
1009 pw.print(prefix); pw.println(" Trigger content URIs:");
1010 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
1011 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
1012 pw.print(prefix); pw.print(" ");
1013 pw.print(Integer.toHexString(trig.getFlags()));
1014 pw.print(' '); pw.println(trig.getUri());
1015 }
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001016 if (job.getTriggerContentUpdateDelay() >= 0) {
1017 pw.print(prefix); pw.print(" Trigger update delay: ");
1018 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
1019 pw.println();
1020 }
1021 if (job.getTriggerContentMaxDelay() >= 0) {
1022 pw.print(prefix); pw.print(" Trigger max delay: ");
1023 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
1024 pw.println();
1025 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001026 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001027 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
1028 pw.print(prefix); pw.print(" Extras: ");
1029 pw.println(job.getExtras().toShortString());
1030 }
1031 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
1032 pw.print(prefix); pw.print(" Transient extras: ");
1033 pw.println(job.getTransientExtras().toShortString());
1034 }
1035 if (job.getClipData() != null) {
1036 pw.print(prefix); pw.print(" Clip data: ");
1037 StringBuilder b = new StringBuilder(128);
1038 job.getClipData().toShortString(b);
1039 pw.println(b);
1040 }
Dianne Hackborn342e6032017-04-13 18:04:31 -07001041 if (uriPerms != null) {
1042 pw.print(prefix); pw.println(" Granted URI permissions:");
1043 uriPerms.dump(pw, prefix + " ");
1044 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001045 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
1046 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
1047 }
1048 if (job.getMinLatencyMillis() != 0) {
1049 pw.print(prefix); pw.print(" Minimum latency: ");
1050 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
1051 pw.println();
1052 }
1053 if (job.getMaxExecutionDelayMillis() != 0) {
1054 pw.print(prefix); pw.print(" Max execution delay: ");
1055 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
1056 pw.println();
1057 }
1058 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
1059 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001060 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001061 if (job.hasEarlyConstraint()) {
1062 pw.print(prefix); pw.println(" Has early constraint");
1063 }
1064 if (job.hasLateConstraint()) {
1065 pw.print(prefix); pw.println(" Has late constraint");
1066 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001067 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001068 pw.print(prefix); pw.print("Required constraints:");
1069 dumpConstraints(pw, requiredConstraints);
1070 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001071 if (full) {
1072 pw.print(prefix); pw.print("Satisfied constraints:");
1073 dumpConstraints(pw, satisfiedConstraints);
1074 pw.println();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001075 pw.print(prefix); pw.print("Unsatisfied constraints:");
1076 dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
1077 pw.println();
Dianne Hackborn7ab40252016-06-15 17:30:24 -07001078 if (dozeWhitelisted) {
1079 pw.print(prefix); pw.println("Doze whitelisted: true");
1080 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001081 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001082 if (trackingControllers != 0) {
1083 pw.print(prefix); pw.print("Tracking:");
1084 if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY");
1085 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY");
1086 if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT");
1087 if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE");
1088 if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE");
1089 if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME");
1090 pw.println();
1091 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001092 if (changedAuthorities != null) {
1093 pw.print(prefix); pw.println("Changed authorities:");
1094 for (int i=0; i<changedAuthorities.size(); i++) {
1095 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
1096 }
1097 if (changedUris != null) {
1098 pw.print(prefix); pw.println("Changed URIs:");
1099 for (int i=0; i<changedUris.size(); i++) {
1100 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i));
1101 }
1102 }
1103 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001104 if (pendingWork != null && pendingWork.size() > 0) {
1105 pw.print(prefix); pw.println("Pending work:");
1106 for (int i = 0; i < pendingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001107 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001108 }
1109 }
1110 if (executingWork != null && executingWork.size() > 0) {
1111 pw.print(prefix); pw.println("Executing work:");
1112 for (int i = 0; i < executingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001113 dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001114 }
1115 }
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001116 pw.print(prefix); pw.print("Enqueue time: ");
1117 TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
1118 pw.println();
1119 pw.print(prefix); pw.print("Run time: earliest=");
1120 formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
1121 pw.print(", latest=");
1122 formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
1123 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001124 if (numFailures != 0) {
1125 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
1126 }
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001127 final Time t = new Time();
1128 final String format = "%Y-%m-%d %H:%M:%S";
1129 if (mLastSuccessfulRunTime != 0) {
1130 pw.print(prefix); pw.print("Last successful run: ");
1131 t.set(mLastSuccessfulRunTime);
1132 pw.println(t.format(format));
1133 }
1134 if (mLastFailedRunTime != 0) {
1135 pw.print(prefix); pw.print("Last failed run: ");
1136 t.set(mLastFailedRunTime);
1137 pw.println(t.format(format));
1138 }
Christopher Tate7060b042014-06-09 19:50:00 -07001139 }
1140}