blob: 303b0007e1f78a6151e0d6b14a3b248ce91aba49 [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;
73
74 static final int CONNECTIVITY_MASK =
75 CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY |
76 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED;
Dianne Hackbornb0001f62016-02-16 10:30:33 -080077
Christopher Tate5d346052016-03-08 12:56:08 -080078 // Soft override: ignore constraints like time that don't affect API availability
79 public static final int OVERRIDE_SOFT = 1;
80 // Full override: ignore all constraints including API-affecting like connectivity
81 public static final int OVERRIDE_FULL = 2;
82
Dianne Hackborn8db0fc12016-04-12 13:48:25 -070083 /** If not specified, trigger update delay is 10 seconds. */
84 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
85
86 /** The minimum possible update delay is 1/2 second. */
87 public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
88
89 /** If not specified, trigger maxumum delay is 2 minutes. */
90 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
91
92 /** The minimum possible update delay is 1 second. */
93 public static final long MIN_TRIGGER_MAX_DELAY = 1000;
94
Christopher Tate7060b042014-06-09 19:50:00 -070095 final JobInfo job;
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070096 /** Uid of the package requesting this job. */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000097 final int callingUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080098 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -070099
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000100 final String sourcePackageName;
101 final int sourceUserId;
102 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800103 final String sourceTag;
104
105 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000106
Dianne Hackborn342e6032017-04-13 18:04:31 -0700107 private GrantedUriPermissions uriPerms;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700108 private boolean prepared;
109
Christopher Tateb164f012017-04-26 15:41:37 -0700110 static final boolean DEBUG_PREPARE = true;
111 private Throwable unpreparedPoint = null;
112
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800113 /**
114 * Earliest point in the future at which this job will be eligible to run. A value of 0
115 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
116 */
117 private final long earliestRunTimeElapsedMillis;
118 /**
119 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
120 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
121 */
122 private final long latestRunTimeElapsedMillis;
123
124 /** How many times this job has failed, used to compute back-off. */
125 private final int numFailures;
126
Christopher Tate7060b042014-06-09 19:50:00 -0700127 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800128 final int requiredConstraints;
129 int satisfiedConstraints = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800130
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700131 // Set to true if doze constraint was satisfied due to app being whitelisted.
132 public boolean dozeWhitelisted;
133
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700134 /**
135 * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
136 */
137 public static final int TRACKING_BATTERY = 1<<0;
138 /**
139 * Flag for {@link #trackingControllers}: the network connectivity controller is currently
140 * tracking this job.
141 */
142 public static final int TRACKING_CONNECTIVITY = 1<<1;
143 /**
144 * Flag for {@link #trackingControllers}: the content observer controller is currently
145 * tracking this job.
146 */
147 public static final int TRACKING_CONTENT = 1<<2;
148 /**
149 * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job.
150 */
151 public static final int TRACKING_IDLE = 1<<3;
152 /**
153 * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job.
154 */
155 public static final int TRACKING_STORAGE = 1<<4;
156 /**
157 * Flag for {@link #trackingControllers}: the time controller is currently tracking this job.
158 */
159 public static final int TRACKING_TIME = 1<<5;
160
161 /**
162 * Bit mask of controllers that are currently tracking the job.
163 */
164 private int trackingControllers;
165
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800166 // These are filled in by controllers when preparing for execution.
167 public ArraySet<Uri> changedUris;
168 public ArraySet<String> changedAuthorities;
169
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800170 public int lastEvaluatedPriority;
171
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700172 // If non-null, this is work that has been enqueued for the job.
173 public ArrayList<JobWorkItem> pendingWork;
174
175 // If non-null, this is work that is currently being executed.
176 public ArrayList<JobWorkItem> executingWork;
177
178 public int nextPendingWorkId = 1;
179
Christopher Tate5d346052016-03-08 12:56:08 -0800180 // Used by shell commands
181 public int overrideState = 0;
182
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700183 // When this job was enqueued, for ordering. (in elapsedRealtimeMillis)
184 public long enqueueTime;
185
186 // Metrics about queue latency. (in uptimeMillis)
Christopher Tate7234fc62017-04-03 17:36:07 -0700187 public long madePending;
188 public long madeActive;
189
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800190 /**
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700191 * Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
192 * for dumpsys.
193 */
194 private long mLastSuccessfulRunTime;
195
196 /**
197 * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
198 */
199 private long mLastFailedRunTime;
200
201 /**
Christopher Tate616541d2017-07-26 14:27:38 -0700202 * Transient: when a job is inflated from disk before we have a reliable RTC clock time,
203 * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent
204 * store in UTC so that we can fix up the job's scheduling criteria once we get a good
205 * wall-clock time. If we have to persist the job again before the clock has been updated,
206 * we record these times again rather than calculating based on the earliest/latest elapsed
207 * time base figures.
208 *
209 * 'first' is the earliest/delay time, and 'second' is the latest/deadline time.
210 */
211 private Pair<Long, Long> mPersistedUtcTimes;
212
213 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800214 * For use only by ContentObserverController: state it is maintaining about content URIs
215 * being observed.
216 */
217 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -0700218
Christopher Tate7060b042014-06-09 19:50:00 -0700219 /** Provide a handle to the service that this job will be run on. */
220 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000221 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700222 }
223
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800224 private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800225 int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700226 long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime) {
Christopher Tate7060b042014-06-09 19:50:00 -0700227 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000228 this.callingUid = callingUid;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000229
230 int tempSourceUid = -1;
231 if (sourceUserId != -1 && sourcePackageName != null) {
232 try {
233 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
234 sourceUserId);
235 } catch (RemoteException ex) {
236 // Can't happen, PackageManager runs in the same process.
237 }
238 }
239 if (tempSourceUid == -1) {
240 this.sourceUid = callingUid;
241 this.sourceUserId = UserHandle.getUserId(callingUid);
242 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800243 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000244 } else {
245 this.sourceUid = tempSourceUid;
246 this.sourceUserId = sourceUserId;
247 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800248 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000249 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800250
Shreyas Basargeeda34e42016-04-26 00:14:02 +0100251 this.batteryName = this.sourceTag != null
252 ? this.sourceTag + ":" + job.getService().getPackageName()
253 : job.getService().flattenToShortString();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800254 this.tag = "*job*/" + this.batteryName;
255
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800256 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
257 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
258 this.numFailures = numFailures;
259
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800260 int requiredConstraints = job.getConstraintFlags();
Christopher Tate60977f42017-04-13 13:48:46 -0700261
262 switch (job.getNetworkType()) {
263 case JobInfo.NETWORK_TYPE_NONE:
264 // No constraint.
265 break;
266 case JobInfo.NETWORK_TYPE_ANY:
267 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
268 break;
269 case JobInfo.NETWORK_TYPE_UNMETERED:
270 requiredConstraints |= CONSTRAINT_UNMETERED;
271 break;
272 case JobInfo.NETWORK_TYPE_NOT_ROAMING:
273 requiredConstraints |= CONSTRAINT_NOT_ROAMING;
274 break;
275 case JobInfo.NETWORK_TYPE_METERED:
276 requiredConstraints |= CONSTRAINT_METERED;
277 break;
278 default:
279 Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType());
280 break;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800281 }
Christopher Tate60977f42017-04-13 13:48:46 -0700282
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800283 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
284 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
285 }
286 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
287 requiredConstraints |= CONSTRAINT_DEADLINE;
288 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800289 if (job.getTriggerContentUris() != null) {
290 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
291 }
292 this.requiredConstraints = requiredConstraints;
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700293
294 mLastSuccessfulRunTime = lastSuccessfulRunTime;
295 mLastFailedRunTime = lastFailedRunTime;
Christopher Tate7060b042014-06-09 19:50:00 -0700296 }
297
Christopher Tate616541d2017-07-26 14:27:38 -0700298 /** Copy constructor: used specifically when cloning JobStatus objects for persistence,
299 * so we preserve RTC window bounds if the source object has them. */
Matthew Williams0cc76542015-10-16 21:04:51 -0700300 public JobStatus(JobStatus jobStatus) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800301 this(jobStatus.getJob(), jobStatus.getUid(),
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800302 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800303 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700304 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
305 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime());
Christopher Tate616541d2017-07-26 14:27:38 -0700306 mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
307 if (jobStatus.mPersistedUtcTimes != null) {
308 if (DEBUG) {
309 Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here"));
310 }
311 }
Christopher Tate7060b042014-06-09 19:50:00 -0700312 }
313
314 /**
315 * Create a new JobStatus that was loaded from disk. We ignore the provided
316 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
317 * from the {@link com.android.server.job.JobStore} and still want to respect its
318 * wallclock runtime rather than resetting it on every boot.
319 * We consider a freshly loaded job to no longer be in back-off.
320 */
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800321 public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700322 String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
Christopher Tate616541d2017-07-26 14:27:38 -0700323 long lastSuccessfulRunTime, long lastFailedRunTime,
324 Pair<Long, Long> persistedExecutionTimesUTC) {
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800325 this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700326 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
327 lastSuccessfulRunTime, lastFailedRunTime);
Christopher Tate616541d2017-07-26 14:27:38 -0700328
329 // Only during initial inflation do we record the UTC-timebase execution bounds
330 // read from the persistent store. If we ever have to recreate the JobStatus on
331 // the fly, it means we're rescheduling the job; and this means that the calculated
332 // elapsed timebase bounds intrinsically become correct.
333 this.mPersistedUtcTimes = persistedExecutionTimesUTC;
334 if (persistedExecutionTimesUTC != null) {
335 if (DEBUG) {
336 Slog.i(TAG, "+ restored job with RTC times because of bad boot clock");
337 }
338 }
Christopher Tate7060b042014-06-09 19:50:00 -0700339 }
340
341 /** Create a new job to be rescheduled with the provided parameters. */
342 public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700343 long newLatestRuntimeElapsedMillis, int backoffAttempt,
344 long lastSuccessfulRunTime, long lastFailedRunTime) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800345 this(rescheduling.job, rescheduling.getUid(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800346 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
347 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700348 newLatestRuntimeElapsedMillis,
349 lastSuccessfulRunTime, lastFailedRunTime);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800350 }
Christopher Tate7060b042014-06-09 19:50:00 -0700351
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800352 /**
353 * Create a newly scheduled job.
354 * @param callingUid Uid of the package that scheduled this job.
355 * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
356 * the calling package is the source.
357 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
358 */
359 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800360 int sourceUserId, String tag) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800361 final long elapsedNow = SystemClock.elapsedRealtime();
362 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
363 if (job.isPeriodic()) {
364 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
365 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
366 } else {
367 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
368 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
369 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
370 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
371 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800372 return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700373 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
374 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
Christopher Tate7060b042014-06-09 19:50:00 -0700375 }
376
Dianne Hackborn342e6032017-04-13 18:04:31 -0700377 public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700378 if (pendingWork == null) {
379 pendingWork = new ArrayList<>();
380 }
381 work.setWorkId(nextPendingWorkId);
382 nextPendingWorkId++;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700383 if (work.getIntent() != null
384 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) {
385 work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid,
386 sourcePackageName, sourceUserId, toShortString()));
387 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700388 pendingWork.add(work);
389 }
390
391 public JobWorkItem dequeueWorkLocked() {
392 if (pendingWork != null && pendingWork.size() > 0) {
393 JobWorkItem work = pendingWork.remove(0);
394 if (work != null) {
395 if (executingWork == null) {
396 executingWork = new ArrayList<>();
397 }
398 executingWork.add(work);
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700399 work.bumpDeliveryCount();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700400 }
401 return work;
402 }
403 return null;
404 }
405
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700406 public boolean hasWorkLocked() {
407 return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
408 }
409
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700410 public boolean hasExecutingWorkLocked() {
411 return executingWork != null && executingWork.size() > 0;
412 }
413
Dianne Hackborn342e6032017-04-13 18:04:31 -0700414 private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) {
415 if (work.getGrants() != null) {
416 ((GrantedUriPermissions)work.getGrants()).revoke(am);
417 }
418 }
419
420 public boolean completeWorkLocked(IActivityManager am, int workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700421 if (executingWork != null) {
422 final int N = executingWork.size();
423 for (int i = 0; i < N; i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700424 JobWorkItem work = executingWork.get(i);
425 if (work.getWorkId() == workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700426 executingWork.remove(i);
Dianne Hackborn342e6032017-04-13 18:04:31 -0700427 ungrantWorkItem(am, work);
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700428 return true;
429 }
430 }
431 }
432 return false;
433 }
434
Dianne Hackborn342e6032017-04-13 18:04:31 -0700435 private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) {
436 if (list != null) {
437 final int N = list.size();
438 for (int i = 0; i < N; i++) {
439 ungrantWorkItem(am, list.get(i));
440 }
441 }
442 }
443
444 public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700445 if (incomingJob != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700446 // We are replacing with a new job -- transfer the work! We do any executing
447 // work first, since that was originally at the front of the pending work.
448 if (executingWork != null && executingWork.size() > 0) {
449 incomingJob.pendingWork = executingWork;
450 }
451 if (incomingJob.pendingWork == null) {
452 incomingJob.pendingWork = pendingWork;
453 } else if (pendingWork != null && pendingWork.size() > 0) {
454 incomingJob.pendingWork.addAll(pendingWork);
455 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700456 pendingWork = null;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700457 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700458 incomingJob.nextPendingWorkId = nextPendingWorkId;
459 } else {
460 // We are completely stopping the job... need to clean up work.
Dianne Hackborn342e6032017-04-13 18:04:31 -0700461 ungrantWorkList(am, pendingWork);
462 pendingWork = null;
463 ungrantWorkList(am, executingWork);
464 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700465 }
466 }
467
468 public void prepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700469 if (prepared) {
470 Slog.wtf(TAG, "Already prepared: " + this);
471 return;
472 }
473 prepared = true;
Christopher Tateb164f012017-04-26 15:41:37 -0700474 if (DEBUG_PREPARE) {
475 unpreparedPoint = null;
476 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700477 final ClipData clip = job.getClipData();
478 if (clip != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700479 uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName,
480 sourceUserId, job.getClipGrantFlags(), toShortString());
Dianne Hackborna47223f2017-03-30 13:49:13 -0700481 }
482 }
483
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700484 public void unprepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700485 if (!prepared) {
486 Slog.wtf(TAG, "Hasn't been prepared: " + this);
Christopher Tateb164f012017-04-26 15:41:37 -0700487 if (DEBUG_PREPARE && unpreparedPoint != null) {
488 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint);
489 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700490 return;
491 }
492 prepared = false;
Christopher Tateb164f012017-04-26 15:41:37 -0700493 if (DEBUG_PREPARE) {
494 unpreparedPoint = new Throwable().fillInStackTrace();
495 }
Dianne Hackborn342e6032017-04-13 18:04:31 -0700496 if (uriPerms != null) {
497 uriPerms.revoke(am);
498 uriPerms = null;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700499 }
500 }
501
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700502 public boolean isPreparedLocked() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700503 return prepared;
504 }
505
Christopher Tate7060b042014-06-09 19:50:00 -0700506 public JobInfo getJob() {
507 return job;
508 }
509
510 public int getJobId() {
511 return job.getId();
512 }
513
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700514 public void printUniqueId(PrintWriter pw) {
515 UserHandle.formatUid(pw, callingUid);
516 pw.print("/");
517 pw.print(job.getId());
518 }
519
Christopher Tate7060b042014-06-09 19:50:00 -0700520 public int getNumFailures() {
521 return numFailures;
522 }
523
524 public ComponentName getServiceComponent() {
525 return job.getService();
526 }
527
Shreyas Basarge968ac752016-01-11 23:09:26 +0000528 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000529 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000530 }
531
532 public int getSourceUid() {
533 return sourceUid;
534 }
535
536 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000537 return sourceUserId;
538 }
539
Christopher Tate7060b042014-06-09 19:50:00 -0700540 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000541 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700542 }
543
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800544 public String getSourceTag() {
545 return sourceTag;
546 }
547
Christopher Tate7060b042014-06-09 19:50:00 -0700548 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000549 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700550 }
551
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800552 public String getBatteryName() {
553 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700554 }
555
556 public String getTag() {
557 return tag;
558 }
559
Shreyas Basarge5db09082016-01-07 13:38:29 +0000560 public int getPriority() {
561 return job.getPriority();
562 }
Christopher Tate7060b042014-06-09 19:50:00 -0700563
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600564 public int getFlags() {
565 return job.getFlags();
566 }
567
Christopher Tate60977f42017-04-13 13:48:46 -0700568 /** Does this job have any sort of networking constraint? */
Christopher Tate7060b042014-06-09 19:50:00 -0700569 public boolean hasConnectivityConstraint() {
Christopher Tate60977f42017-04-13 13:48:46 -0700570 return (requiredConstraints&CONNECTIVITY_MASK) != 0;
571 }
572
573 public boolean needsAnyConnectivity() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800574 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700575 }
576
Christopher Tate60977f42017-04-13 13:48:46 -0700577 public boolean needsUnmeteredConnectivity() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800578 return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700579 }
580
Christopher Tate60977f42017-04-13 13:48:46 -0700581 public boolean needsMeteredConnectivity() {
582 return (requiredConstraints&CONSTRAINT_METERED) != 0;
583 }
584
585 public boolean needsNonRoamingConnectivity() {
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600586 return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0;
587 }
588
Christopher Tate7060b042014-06-09 19:50:00 -0700589 public boolean hasChargingConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800590 return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700591 }
592
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800593 public boolean hasBatteryNotLowConstraint() {
594 return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0;
595 }
596
597 public boolean hasPowerConstraint() {
598 return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0;
599 }
600
Dianne Hackborn532ea262017-03-17 17:50:55 -0700601 public boolean hasStorageNotLowConstraint() {
602 return (requiredConstraints&CONSTRAINT_STORAGE_NOT_LOW) != 0;
603 }
604
Christopher Tate7060b042014-06-09 19:50:00 -0700605 public boolean hasTimingDelayConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800606 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700607 }
608
609 public boolean hasDeadlineConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800610 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700611 }
612
613 public boolean hasIdleConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800614 return (requiredConstraints&CONSTRAINT_IDLE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700615 }
616
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800617 public boolean hasContentTriggerConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800618 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800619 }
620
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700621 public long getTriggerContentUpdateDelay() {
622 long time = job.getTriggerContentUpdateDelay();
623 if (time < 0) {
624 return DEFAULT_TRIGGER_UPDATE_DELAY;
625 }
626 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
627 }
628
629 public long getTriggerContentMaxDelay() {
630 long time = job.getTriggerContentMaxDelay();
631 if (time < 0) {
632 return DEFAULT_TRIGGER_MAX_DELAY;
633 }
634 return Math.max(time, MIN_TRIGGER_MAX_DELAY);
635 }
636
Matthew Williams900c67f2014-07-09 12:46:53 -0700637 public boolean isPersisted() {
638 return job.isPersisted();
639 }
640
Christopher Tate7060b042014-06-09 19:50:00 -0700641 public long getEarliestRunTime() {
642 return earliestRunTimeElapsedMillis;
643 }
644
645 public long getLatestRunTimeElapsed() {
646 return latestRunTimeElapsedMillis;
647 }
648
Christopher Tate616541d2017-07-26 14:27:38 -0700649 public Pair<Long, Long> getPersistedUtcTimes() {
650 return mPersistedUtcTimes;
651 }
652
653 public void clearPersistedUtcTimes() {
654 mPersistedUtcTimes = null;
655 }
656
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800657 boolean setChargingConstraintSatisfied(boolean state) {
658 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
659 }
660
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800661 boolean setBatteryNotLowConstraintSatisfied(boolean state) {
662 return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
663 }
664
Dianne Hackborn532ea262017-03-17 17:50:55 -0700665 boolean setStorageNotLowConstraintSatisfied(boolean state) {
666 return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
667 }
668
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800669 boolean setTimingDelayConstraintSatisfied(boolean state) {
670 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
671 }
672
673 boolean setDeadlineConstraintSatisfied(boolean state) {
674 return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
675 }
676
677 boolean setIdleConstraintSatisfied(boolean state) {
678 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
679 }
680
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600681 boolean setConnectivityConstraintSatisfied(boolean state) {
682 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
683 }
684
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800685 boolean setUnmeteredConstraintSatisfied(boolean state) {
686 return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
687 }
688
Christopher Tate60977f42017-04-13 13:48:46 -0700689 boolean setMeteredConstraintSatisfied(boolean state) {
690 return setConstraintSatisfied(CONSTRAINT_METERED, state);
691 }
692
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600693 boolean setNotRoamingConstraintSatisfied(boolean state) {
694 return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800695 }
696
697 boolean setAppNotIdleConstraintSatisfied(boolean state) {
698 return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
699 }
700
701 boolean setContentTriggerConstraintSatisfied(boolean state) {
702 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
703 }
704
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700705 boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
706 dozeWhitelisted = whitelisted;
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700707 return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
708 }
709
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800710 boolean setConstraintSatisfied(int constraint, boolean state) {
711 boolean old = (satisfiedConstraints&constraint) != 0;
712 if (old == state) {
713 return false;
714 }
715 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
716 return true;
717 }
718
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700719 boolean isConstraintSatisfied(int constraint) {
720 return (satisfiedConstraints&constraint) != 0;
721 }
722
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700723 boolean clearTrackingController(int which) {
724 if ((trackingControllers&which) != 0) {
725 trackingControllers &= ~which;
726 return true;
727 }
728 return false;
729 }
730
731 void setTrackingController(int which) {
732 trackingControllers |= which;
733 }
734
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700735 public long getLastSuccessfulRunTime() {
736 return mLastSuccessfulRunTime;
737 }
738
739 public long getLastFailedRunTime() {
740 return mLastFailedRunTime;
741 }
742
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700743 public boolean shouldDump(int filterUid) {
744 return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
745 || UserHandle.getAppId(getSourceUid()) == filterUid;
746 }
747
Christopher Tate7060b042014-06-09 19:50:00 -0700748 /**
Matthew Williams03a4da62014-09-10 17:32:18 -0700749 * @return Whether or not this job is ready to run, based on its requirements. This is true if
750 * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700751 * TODO: This function is called a *lot*. We should probably just have it check an
752 * already-computed boolean, which we updated whenever we see one of the states it depends
753 * on here change.
Christopher Tate7060b042014-06-09 19:50:00 -0700754 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800755 public boolean isReady() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800756 // Deadline constraint trumps other constraints (except for periodic jobs where deadline
Christopher Tate5d346052016-03-08 12:56:08 -0800757 // is an implementation detail. A periodic job should only run if its constraints are
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800758 // satisfied).
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700759 // AppNotIdle implicit constraint must be satisfied
760 // DeviceNotDozing implicit constraint must be satisfied
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600761 final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
762 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
763 final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
764 final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
765 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
766 return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing;
Matthew Williams03a4da62014-09-10 17:32:18 -0700767 }
768
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800769 static final int CONSTRAINTS_OF_INTEREST =
Dianne Hackborn532ea262017-03-17 17:50:55 -0700770 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW |
771 CONSTRAINT_TIMING_DELAY |
Christopher Tate06f08522017-06-13 12:12:09 -0700772 CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
773 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED |
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800774 CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
775
Christopher Tate5d346052016-03-08 12:56:08 -0800776 // Soft override covers all non-"functional" constraints
777 static final int SOFT_OVERRIDE_CONSTRAINTS =
Dianne Hackborn532ea262017-03-17 17:50:55 -0700778 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800779 | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
Christopher Tate5d346052016-03-08 12:56:08 -0800780
Matthew Williams03a4da62014-09-10 17:32:18 -0700781 /**
782 * @return Whether the constraints set on this job are satisfied.
783 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800784 public boolean isConstraintsSatisfied() {
Christopher Tate5d346052016-03-08 12:56:08 -0800785 if (overrideState == OVERRIDE_FULL) {
786 // force override: the job is always runnable
787 return true;
788 }
789
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800790 final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
Christopher Tate5d346052016-03-08 12:56:08 -0800791
792 int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
793 if (overrideState == OVERRIDE_SOFT) {
794 // override: pretend all 'soft' requirements are satisfied
795 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
796 }
797
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800798 return (sat & req) == req;
Christopher Tate7060b042014-06-09 19:50:00 -0700799 }
800
801 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000802 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -0700803 }
804
805 @Override
806 public String toString() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700807 StringBuilder sb = new StringBuilder(128);
808 sb.append("JobStatus{");
809 sb.append(Integer.toHexString(System.identityHashCode(this)));
810 sb.append(" #");
811 UserHandle.formatUid(sb, callingUid);
812 sb.append("/");
813 sb.append(job.getId());
814 sb.append(' ');
815 sb.append(batteryName);
816 sb.append(" u=");
817 sb.append(getUserId());
818 sb.append(" s=");
819 sb.append(getSourceUid());
820 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
821 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700822 long now = SystemClock.elapsedRealtime();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700823 sb.append(" TIME=");
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700824 formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
825 sb.append(":");
826 formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
Dianne Hackborna47223f2017-03-30 13:49:13 -0700827 }
828 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
829 sb.append(" NET=");
830 sb.append(job.getNetworkType());
831 }
832 if (job.isRequireCharging()) {
833 sb.append(" CHARGING");
834 }
835 if (job.isRequireBatteryNotLow()) {
836 sb.append(" BATNOTLOW");
837 }
838 if (job.isRequireStorageNotLow()) {
839 sb.append(" STORENOTLOW");
840 }
841 if (job.isRequireDeviceIdle()) {
842 sb.append(" IDLE");
843 }
Christopher Tate616541d2017-07-26 14:27:38 -0700844 if (job.isPeriodic()) {
845 sb.append(" PERIODIC");
846 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700847 if (job.isPersisted()) {
848 sb.append(" PERSISTED");
849 }
850 if ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) == 0) {
851 sb.append(" WAIT:APP_NOT_IDLE");
852 }
853 if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
854 sb.append(" WAIT:DEV_NOT_DOZING");
855 }
856 if (job.getTriggerContentUris() != null) {
857 sb.append(" URIS=");
858 sb.append(Arrays.toString(job.getTriggerContentUris()));
859 }
860 if (numFailures != 0) {
861 sb.append(" failures=");
862 sb.append(numFailures);
863 }
864 if (isReady()) {
865 sb.append(" READY");
866 }
867 sb.append("}");
868 return sb.toString();
Christopher Tate7060b042014-06-09 19:50:00 -0700869 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700870
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700871 private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700872 if (runtime == defaultValue) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700873 pw.print("none");
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700874 } else {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700875 TimeUtils.formatDuration(runtime - now, pw);
876 }
877 }
878
879 private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) {
880 if (runtime == defaultValue) {
881 sb.append("none");
882 } else {
883 TimeUtils.formatDuration(runtime - now, sb);
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700884 }
885 }
886
887 /**
888 * Convenience function to identify a job uniquely without pulling all the data that
889 * {@link #toString()} returns.
890 */
891 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800892 StringBuilder sb = new StringBuilder();
893 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700894 sb.append(" #");
895 UserHandle.formatUid(sb, callingUid);
896 sb.append("/");
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800897 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800898 sb.append(' ');
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700899 sb.append(batteryName);
900 return sb.toString();
901 }
902
903 /**
904 * Convenience function to identify a job uniquely without pulling all the data that
905 * {@link #toString()} returns.
906 */
907 public String toShortStringExceptUniqueId() {
908 StringBuilder sb = new StringBuilder();
909 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800910 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -0800911 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800912 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700913 }
914
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800915 void dumpConstraints(PrintWriter pw, int constraints) {
916 if ((constraints&CONSTRAINT_CHARGING) != 0) {
917 pw.print(" CHARGING");
918 }
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800919 if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
920 pw.print(" BATTERY_NOT_LOW");
921 }
Dianne Hackborn532ea262017-03-17 17:50:55 -0700922 if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) {
923 pw.print(" STORAGE_NOT_LOW");
924 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800925 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
926 pw.print(" TIMING_DELAY");
927 }
928 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
929 pw.print(" DEADLINE");
930 }
931 if ((constraints&CONSTRAINT_IDLE) != 0) {
932 pw.print(" IDLE");
933 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600934 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
935 pw.print(" CONNECTIVITY");
936 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800937 if ((constraints&CONSTRAINT_UNMETERED) != 0) {
938 pw.print(" UNMETERED");
939 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600940 if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
941 pw.print(" NOT_ROAMING");
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800942 }
Christopher Tate06f08522017-06-13 12:12:09 -0700943 if ((constraints&CONSTRAINT_METERED) != 0) {
944 pw.print(" METERED");
945 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800946 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
947 pw.print(" APP_NOT_IDLE");
948 }
949 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
950 pw.print(" CONTENT_TRIGGER");
951 }
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700952 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
953 pw.print(" DEVICE_NOT_DOZING");
954 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800955 }
956
Dianne Hackborn342e6032017-04-13 18:04:31 -0700957 private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
958 pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #");
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700959 pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
960 pw.print("x "); pw.println(work.getIntent());
Dianne Hackborn342e6032017-04-13 18:04:31 -0700961 if (work.getGrants() != null) {
962 pw.print(prefix); pw.println(" URI grants:");
963 ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " ");
964 }
965 }
966
Christopher Tate7060b042014-06-09 19:50:00 -0700967 // Dumpsys infrastructure
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700968 public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000969 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800970 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -0700971 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000972 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
973 pw.print(" user="); pw.print(getSourceUserId());
974 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800975 if (full) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700976 pw.print(prefix); pw.println("JobInfo:");
977 pw.print(prefix); pw.print(" Service: ");
978 pw.println(job.getService().flattenToShortString());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800979 if (job.isPeriodic()) {
980 pw.print(prefix); pw.print(" PERIODIC: interval=");
981 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
982 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
983 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800984 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800985 if (job.isPersisted()) {
986 pw.print(prefix); pw.println(" PERSISTED");
987 }
988 if (job.getPriority() != 0) {
989 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
990 }
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600991 if (job.getFlags() != 0) {
992 pw.print(prefix); pw.print(" Flags: ");
993 pw.println(Integer.toHexString(job.getFlags()));
994 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800995 pw.print(prefix); pw.print(" Requires: charging=");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800996 pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
997 pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
Dianne Hackborn970510b2016-02-24 16:56:42 -0800998 pw.println(job.isRequireDeviceIdle());
999 if (job.getTriggerContentUris() != null) {
1000 pw.print(prefix); pw.println(" Trigger content URIs:");
1001 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
1002 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
1003 pw.print(prefix); pw.print(" ");
1004 pw.print(Integer.toHexString(trig.getFlags()));
1005 pw.print(' '); pw.println(trig.getUri());
1006 }
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001007 if (job.getTriggerContentUpdateDelay() >= 0) {
1008 pw.print(prefix); pw.print(" Trigger update delay: ");
1009 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
1010 pw.println();
1011 }
1012 if (job.getTriggerContentMaxDelay() >= 0) {
1013 pw.print(prefix); pw.print(" Trigger max delay: ");
1014 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
1015 pw.println();
1016 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001017 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001018 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
1019 pw.print(prefix); pw.print(" Extras: ");
1020 pw.println(job.getExtras().toShortString());
1021 }
1022 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
1023 pw.print(prefix); pw.print(" Transient extras: ");
1024 pw.println(job.getTransientExtras().toShortString());
1025 }
1026 if (job.getClipData() != null) {
1027 pw.print(prefix); pw.print(" Clip data: ");
1028 StringBuilder b = new StringBuilder(128);
1029 job.getClipData().toShortString(b);
1030 pw.println(b);
1031 }
Dianne Hackborn342e6032017-04-13 18:04:31 -07001032 if (uriPerms != null) {
1033 pw.print(prefix); pw.println(" Granted URI permissions:");
1034 uriPerms.dump(pw, prefix + " ");
1035 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001036 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
1037 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
1038 }
1039 if (job.getMinLatencyMillis() != 0) {
1040 pw.print(prefix); pw.print(" Minimum latency: ");
1041 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
1042 pw.println();
1043 }
1044 if (job.getMaxExecutionDelayMillis() != 0) {
1045 pw.print(prefix); pw.print(" Max execution delay: ");
1046 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
1047 pw.println();
1048 }
1049 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
1050 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001051 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001052 if (job.hasEarlyConstraint()) {
1053 pw.print(prefix); pw.println(" Has early constraint");
1054 }
1055 if (job.hasLateConstraint()) {
1056 pw.print(prefix); pw.println(" Has late constraint");
1057 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001058 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001059 pw.print(prefix); pw.print("Required constraints:");
1060 dumpConstraints(pw, requiredConstraints);
1061 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001062 if (full) {
1063 pw.print(prefix); pw.print("Satisfied constraints:");
1064 dumpConstraints(pw, satisfiedConstraints);
1065 pw.println();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001066 pw.print(prefix); pw.print("Unsatisfied constraints:");
1067 dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
1068 pw.println();
Dianne Hackborn7ab40252016-06-15 17:30:24 -07001069 if (dozeWhitelisted) {
1070 pw.print(prefix); pw.println("Doze whitelisted: true");
1071 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001072 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001073 if (trackingControllers != 0) {
1074 pw.print(prefix); pw.print("Tracking:");
1075 if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY");
1076 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY");
1077 if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT");
1078 if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE");
1079 if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE");
1080 if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME");
1081 pw.println();
1082 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001083 if (changedAuthorities != null) {
1084 pw.print(prefix); pw.println("Changed authorities:");
1085 for (int i=0; i<changedAuthorities.size(); i++) {
1086 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
1087 }
1088 if (changedUris != null) {
1089 pw.print(prefix); pw.println("Changed URIs:");
1090 for (int i=0; i<changedUris.size(); i++) {
1091 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i));
1092 }
1093 }
1094 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001095 if (pendingWork != null && pendingWork.size() > 0) {
1096 pw.print(prefix); pw.println("Pending work:");
1097 for (int i = 0; i < pendingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001098 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001099 }
1100 }
1101 if (executingWork != null && executingWork.size() > 0) {
1102 pw.print(prefix); pw.println("Executing work:");
1103 for (int i = 0; i < executingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001104 dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001105 }
1106 }
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001107 pw.print(prefix); pw.print("Enqueue time: ");
1108 TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
1109 pw.println();
1110 pw.print(prefix); pw.print("Run time: earliest=");
1111 formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
1112 pw.print(", latest=");
1113 formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
1114 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001115 if (numFailures != 0) {
1116 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
1117 }
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001118 final Time t = new Time();
1119 final String format = "%Y-%m-%d %H:%M:%S";
1120 if (mLastSuccessfulRunTime != 0) {
1121 pw.print(prefix); pw.print("Last successful run: ");
1122 t.set(mLastSuccessfulRunTime);
1123 pw.println(t.format(format));
1124 }
1125 if (mLastFailedRunTime != 0) {
1126 pw.print(prefix); pw.print("Last failed run: ");
1127 t.set(mLastFailedRunTime);
1128 pw.println(t.format(format));
1129 }
Christopher Tate7060b042014-06-09 19:50:00 -07001130 }
1131}