blob: 9658da7a5de0a5e610c30814d3e6876f2be64973 [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;
Dianne Hackborna47223f2017-03-30 13:49:13 -070031import android.util.Slog;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080032import android.util.TimeUtils;
Christopher Tate7060b042014-06-09 19:50:00 -070033
Dianne Hackborn342e6032017-04-13 18:04:31 -070034import com.android.server.job.GrantedUriPermissions;
35
Christopher Tate7060b042014-06-09 19:50:00 -070036import java.io.PrintWriter;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070037import java.util.ArrayList;
Dianne Hackborna47223f2017-03-30 13:49:13 -070038import java.util.Arrays;
Christopher Tate7060b042014-06-09 19:50:00 -070039
40/**
41 * Uniquely identifies a job internally.
42 * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
43 * Contains current state of the requirements of the job, as well as a function to evaluate
44 * whether it's ready to run.
45 * This object is shared among the various controllers - hence why the different fields are atomic.
46 * This isn't strictly necessary because each controller is only interested in a specific field,
47 * and the receivers that are listening for global state change will all run on the main looper,
48 * but we don't enforce that so this is safer.
49 * @hide
50 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -080051public final class JobStatus {
Dianne Hackborna47223f2017-03-30 13:49:13 -070052 static final String TAG = "JobSchedulerService";
53
Christopher Tate7060b042014-06-09 19:50:00 -070054 public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
55 public static final long NO_EARLIEST_RUNTIME = 0L;
56
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080057 static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING;
58 static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;
59 static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW;
Dianne Hackborn532ea262017-03-17 17:50:55 -070060 static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -080061 static final int CONSTRAINT_TIMING_DELAY = 1<<31;
62 static final int CONSTRAINT_DEADLINE = 1<<30;
63 static final int CONSTRAINT_UNMETERED = 1<<29;
64 static final int CONSTRAINT_CONNECTIVITY = 1<<28;
65 static final int CONSTRAINT_APP_NOT_IDLE = 1<<27;
66 static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
67 static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
68 static final int CONSTRAINT_NOT_ROAMING = 1<<24;
Christopher Tate60977f42017-04-13 13:48:46 -070069 static final int CONSTRAINT_METERED = 1<<23;
70
71 static final int CONNECTIVITY_MASK =
72 CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY |
73 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED;
Dianne Hackbornb0001f62016-02-16 10:30:33 -080074
Christopher Tate5d346052016-03-08 12:56:08 -080075 // Soft override: ignore constraints like time that don't affect API availability
76 public static final int OVERRIDE_SOFT = 1;
77 // Full override: ignore all constraints including API-affecting like connectivity
78 public static final int OVERRIDE_FULL = 2;
79
Dianne Hackborn8db0fc12016-04-12 13:48:25 -070080 /** If not specified, trigger update delay is 10 seconds. */
81 public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
82
83 /** The minimum possible update delay is 1/2 second. */
84 public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
85
86 /** If not specified, trigger maxumum delay is 2 minutes. */
87 public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
88
89 /** The minimum possible update delay is 1 second. */
90 public static final long MIN_TRIGGER_MAX_DELAY = 1000;
91
Christopher Tate7060b042014-06-09 19:50:00 -070092 final JobInfo job;
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070093 /** Uid of the package requesting this job. */
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000094 final int callingUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080095 final String batteryName;
Christopher Tate7060b042014-06-09 19:50:00 -070096
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +000097 final String sourcePackageName;
98 final int sourceUserId;
99 final int sourceUid;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800100 final String sourceTag;
101
102 final String tag;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000103
Dianne Hackborn342e6032017-04-13 18:04:31 -0700104 private GrantedUriPermissions uriPerms;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700105 private boolean prepared;
106
Christopher Tateb164f012017-04-26 15:41:37 -0700107 static final boolean DEBUG_PREPARE = true;
108 private Throwable unpreparedPoint = null;
109
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800110 /**
111 * Earliest point in the future at which this job will be eligible to run. A value of 0
112 * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
113 */
114 private final long earliestRunTimeElapsedMillis;
115 /**
116 * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
117 * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
118 */
119 private final long latestRunTimeElapsedMillis;
120
121 /** How many times this job has failed, used to compute back-off. */
122 private final int numFailures;
123
Christopher Tate7060b042014-06-09 19:50:00 -0700124 // Constraints.
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800125 final int requiredConstraints;
126 int satisfiedConstraints = 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800127
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700128 // Set to true if doze constraint was satisfied due to app being whitelisted.
129 public boolean dozeWhitelisted;
130
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700131 /**
132 * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
133 */
134 public static final int TRACKING_BATTERY = 1<<0;
135 /**
136 * Flag for {@link #trackingControllers}: the network connectivity controller is currently
137 * tracking this job.
138 */
139 public static final int TRACKING_CONNECTIVITY = 1<<1;
140 /**
141 * Flag for {@link #trackingControllers}: the content observer controller is currently
142 * tracking this job.
143 */
144 public static final int TRACKING_CONTENT = 1<<2;
145 /**
146 * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job.
147 */
148 public static final int TRACKING_IDLE = 1<<3;
149 /**
150 * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job.
151 */
152 public static final int TRACKING_STORAGE = 1<<4;
153 /**
154 * Flag for {@link #trackingControllers}: the time controller is currently tracking this job.
155 */
156 public static final int TRACKING_TIME = 1<<5;
157
158 /**
159 * Bit mask of controllers that are currently tracking the job.
160 */
161 private int trackingControllers;
162
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800163 // These are filled in by controllers when preparing for execution.
164 public ArraySet<Uri> changedUris;
165 public ArraySet<String> changedAuthorities;
166
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800167 public int lastEvaluatedPriority;
168
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700169 // If non-null, this is work that has been enqueued for the job.
170 public ArrayList<JobWorkItem> pendingWork;
171
172 // If non-null, this is work that is currently being executed.
173 public ArrayList<JobWorkItem> executingWork;
174
175 public int nextPendingWorkId = 1;
176
Christopher Tate5d346052016-03-08 12:56:08 -0800177 // Used by shell commands
178 public int overrideState = 0;
179
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700180 // When this job was enqueued, for ordering. (in elapsedRealtimeMillis)
181 public long enqueueTime;
182
183 // Metrics about queue latency. (in uptimeMillis)
Christopher Tate7234fc62017-04-03 17:36:07 -0700184 public long madePending;
185 public long madeActive;
186
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800187 /**
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700188 * Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
189 * for dumpsys.
190 */
191 private long mLastSuccessfulRunTime;
192
193 /**
194 * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
195 */
196 private long mLastFailedRunTime;
197
198 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800199 * For use only by ContentObserverController: state it is maintaining about content URIs
200 * being observed.
201 */
202 ContentObserverController.JobInstance contentObserverJobInstance;
Christopher Tate7060b042014-06-09 19:50:00 -0700203
Christopher Tate7060b042014-06-09 19:50:00 -0700204 /** Provide a handle to the service that this job will be run on. */
205 public int getServiceToken() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000206 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700207 }
208
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800209 private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800210 int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700211 long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime) {
Christopher Tate7060b042014-06-09 19:50:00 -0700212 this.job = job;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000213 this.callingUid = callingUid;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000214
215 int tempSourceUid = -1;
216 if (sourceUserId != -1 && sourcePackageName != null) {
217 try {
218 tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
219 sourceUserId);
220 } catch (RemoteException ex) {
221 // Can't happen, PackageManager runs in the same process.
222 }
223 }
224 if (tempSourceUid == -1) {
225 this.sourceUid = callingUid;
226 this.sourceUserId = UserHandle.getUserId(callingUid);
227 this.sourcePackageName = job.getService().getPackageName();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800228 this.sourceTag = null;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000229 } else {
230 this.sourceUid = tempSourceUid;
231 this.sourceUserId = sourceUserId;
232 this.sourcePackageName = sourcePackageName;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800233 this.sourceTag = tag;
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000234 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800235
Shreyas Basargeeda34e42016-04-26 00:14:02 +0100236 this.batteryName = this.sourceTag != null
237 ? this.sourceTag + ":" + job.getService().getPackageName()
238 : job.getService().flattenToShortString();
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800239 this.tag = "*job*/" + this.batteryName;
240
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800241 this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
242 this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
243 this.numFailures = numFailures;
244
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800245 int requiredConstraints = job.getConstraintFlags();
Christopher Tate60977f42017-04-13 13:48:46 -0700246
247 switch (job.getNetworkType()) {
248 case JobInfo.NETWORK_TYPE_NONE:
249 // No constraint.
250 break;
251 case JobInfo.NETWORK_TYPE_ANY:
252 requiredConstraints |= CONSTRAINT_CONNECTIVITY;
253 break;
254 case JobInfo.NETWORK_TYPE_UNMETERED:
255 requiredConstraints |= CONSTRAINT_UNMETERED;
256 break;
257 case JobInfo.NETWORK_TYPE_NOT_ROAMING:
258 requiredConstraints |= CONSTRAINT_NOT_ROAMING;
259 break;
260 case JobInfo.NETWORK_TYPE_METERED:
261 requiredConstraints |= CONSTRAINT_METERED;
262 break;
263 default:
264 Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType());
265 break;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800266 }
Christopher Tate60977f42017-04-13 13:48:46 -0700267
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800268 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
269 requiredConstraints |= CONSTRAINT_TIMING_DELAY;
270 }
271 if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
272 requiredConstraints |= CONSTRAINT_DEADLINE;
273 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800274 if (job.getTriggerContentUris() != null) {
275 requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
276 }
277 this.requiredConstraints = requiredConstraints;
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700278
279 mLastSuccessfulRunTime = lastSuccessfulRunTime;
280 mLastFailedRunTime = lastFailedRunTime;
Christopher Tate7060b042014-06-09 19:50:00 -0700281 }
282
Matthew Williams0cc76542015-10-16 21:04:51 -0700283 /** Copy constructor. */
284 public JobStatus(JobStatus jobStatus) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800285 this(jobStatus.getJob(), jobStatus.getUid(),
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800286 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800287 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700288 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
289 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime());
Christopher Tate7060b042014-06-09 19:50:00 -0700290 }
291
292 /**
293 * Create a new JobStatus that was loaded from disk. We ignore the provided
294 * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
295 * from the {@link com.android.server.job.JobStore} and still want to respect its
296 * wallclock runtime rather than resetting it on every boot.
297 * We consider a freshly loaded job to no longer be in back-off.
298 */
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800299 public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700300 String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
301 long lastSuccessfulRunTime, long lastFailedRunTime) {
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800302 this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700303 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
304 lastSuccessfulRunTime, lastFailedRunTime);
Christopher Tate7060b042014-06-09 19:50:00 -0700305 }
306
307 /** Create a new job to be rescheduled with the provided parameters. */
308 public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700309 long newLatestRuntimeElapsedMillis, int backoffAttempt,
310 long lastSuccessfulRunTime, long lastFailedRunTime) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800311 this(rescheduling.job, rescheduling.getUid(),
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800312 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
313 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700314 newLatestRuntimeElapsedMillis,
315 lastSuccessfulRunTime, lastFailedRunTime);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800316 }
Christopher Tate7060b042014-06-09 19:50:00 -0700317
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800318 /**
319 * Create a newly scheduled job.
320 * @param callingUid Uid of the package that scheduled this job.
321 * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
322 * the calling package is the source.
323 * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
324 */
325 public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800326 int sourceUserId, String tag) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800327 final long elapsedNow = SystemClock.elapsedRealtime();
328 final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
329 if (job.isPeriodic()) {
330 latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
331 earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
332 } else {
333 earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
334 elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
335 latestRunTimeElapsedMillis = job.hasLateConstraint() ?
336 elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
337 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800338 return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700339 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
340 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
Christopher Tate7060b042014-06-09 19:50:00 -0700341 }
342
Dianne Hackborn342e6032017-04-13 18:04:31 -0700343 public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700344 if (pendingWork == null) {
345 pendingWork = new ArrayList<>();
346 }
347 work.setWorkId(nextPendingWorkId);
348 nextPendingWorkId++;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700349 if (work.getIntent() != null
350 && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) {
351 work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid,
352 sourcePackageName, sourceUserId, toShortString()));
353 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700354 pendingWork.add(work);
355 }
356
357 public JobWorkItem dequeueWorkLocked() {
358 if (pendingWork != null && pendingWork.size() > 0) {
359 JobWorkItem work = pendingWork.remove(0);
360 if (work != null) {
361 if (executingWork == null) {
362 executingWork = new ArrayList<>();
363 }
364 executingWork.add(work);
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700365 work.bumpDeliveryCount();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700366 }
367 return work;
368 }
369 return null;
370 }
371
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700372 public boolean hasWorkLocked() {
373 return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
374 }
375
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700376 public boolean hasExecutingWorkLocked() {
377 return executingWork != null && executingWork.size() > 0;
378 }
379
Dianne Hackborn342e6032017-04-13 18:04:31 -0700380 private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) {
381 if (work.getGrants() != null) {
382 ((GrantedUriPermissions)work.getGrants()).revoke(am);
383 }
384 }
385
386 public boolean completeWorkLocked(IActivityManager am, int workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700387 if (executingWork != null) {
388 final int N = executingWork.size();
389 for (int i = 0; i < N; i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700390 JobWorkItem work = executingWork.get(i);
391 if (work.getWorkId() == workId) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700392 executingWork.remove(i);
Dianne Hackborn342e6032017-04-13 18:04:31 -0700393 ungrantWorkItem(am, work);
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700394 return true;
395 }
396 }
397 }
398 return false;
399 }
400
Dianne Hackborn342e6032017-04-13 18:04:31 -0700401 private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) {
402 if (list != null) {
403 final int N = list.size();
404 for (int i = 0; i < N; i++) {
405 ungrantWorkItem(am, list.get(i));
406 }
407 }
408 }
409
410 public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700411 if (incomingJob != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700412 // We are replacing with a new job -- transfer the work! We do any executing
413 // work first, since that was originally at the front of the pending work.
414 if (executingWork != null && executingWork.size() > 0) {
415 incomingJob.pendingWork = executingWork;
416 }
417 if (incomingJob.pendingWork == null) {
418 incomingJob.pendingWork = pendingWork;
419 } else if (pendingWork != null && pendingWork.size() > 0) {
420 incomingJob.pendingWork.addAll(pendingWork);
421 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700422 pendingWork = null;
Dianne Hackborn342e6032017-04-13 18:04:31 -0700423 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700424 incomingJob.nextPendingWorkId = nextPendingWorkId;
425 } else {
426 // We are completely stopping the job... need to clean up work.
Dianne Hackborn342e6032017-04-13 18:04:31 -0700427 ungrantWorkList(am, pendingWork);
428 pendingWork = null;
429 ungrantWorkList(am, executingWork);
430 executingWork = null;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700431 }
432 }
433
434 public void prepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700435 if (prepared) {
436 Slog.wtf(TAG, "Already prepared: " + this);
437 return;
438 }
439 prepared = true;
Christopher Tateb164f012017-04-26 15:41:37 -0700440 if (DEBUG_PREPARE) {
441 unpreparedPoint = null;
442 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700443 final ClipData clip = job.getClipData();
444 if (clip != null) {
Dianne Hackborn342e6032017-04-13 18:04:31 -0700445 uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName,
446 sourceUserId, job.getClipGrantFlags(), toShortString());
Dianne Hackborna47223f2017-03-30 13:49:13 -0700447 }
448 }
449
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700450 public void unprepareLocked(IActivityManager am) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700451 if (!prepared) {
452 Slog.wtf(TAG, "Hasn't been prepared: " + this);
Christopher Tateb164f012017-04-26 15:41:37 -0700453 if (DEBUG_PREPARE && unpreparedPoint != null) {
454 Slog.e(TAG, "Was already unprepared at ", unpreparedPoint);
455 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700456 return;
457 }
458 prepared = false;
Christopher Tateb164f012017-04-26 15:41:37 -0700459 if (DEBUG_PREPARE) {
460 unpreparedPoint = new Throwable().fillInStackTrace();
461 }
Dianne Hackborn342e6032017-04-13 18:04:31 -0700462 if (uriPerms != null) {
463 uriPerms.revoke(am);
464 uriPerms = null;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700465 }
466 }
467
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700468 public boolean isPreparedLocked() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700469 return prepared;
470 }
471
Christopher Tate7060b042014-06-09 19:50:00 -0700472 public JobInfo getJob() {
473 return job;
474 }
475
476 public int getJobId() {
477 return job.getId();
478 }
479
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700480 public void printUniqueId(PrintWriter pw) {
481 UserHandle.formatUid(pw, callingUid);
482 pw.print("/");
483 pw.print(job.getId());
484 }
485
Christopher Tate7060b042014-06-09 19:50:00 -0700486 public int getNumFailures() {
487 return numFailures;
488 }
489
490 public ComponentName getServiceComponent() {
491 return job.getService();
492 }
493
Shreyas Basarge968ac752016-01-11 23:09:26 +0000494 public String getSourcePackageName() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000495 return sourcePackageName;
Shreyas Basarge968ac752016-01-11 23:09:26 +0000496 }
497
498 public int getSourceUid() {
499 return sourceUid;
500 }
501
502 public int getSourceUserId() {
Shreyas Basarge968ac752016-01-11 23:09:26 +0000503 return sourceUserId;
504 }
505
Christopher Tate7060b042014-06-09 19:50:00 -0700506 public int getUserId() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000507 return UserHandle.getUserId(callingUid);
Christopher Tate7060b042014-06-09 19:50:00 -0700508 }
509
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800510 public String getSourceTag() {
511 return sourceTag;
512 }
513
Christopher Tate7060b042014-06-09 19:50:00 -0700514 public int getUid() {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000515 return callingUid;
Christopher Tate7060b042014-06-09 19:50:00 -0700516 }
517
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800518 public String getBatteryName() {
519 return batteryName;
Dianne Hackbornfdb19562014-07-11 16:03:36 -0700520 }
521
522 public String getTag() {
523 return tag;
524 }
525
Shreyas Basarge5db09082016-01-07 13:38:29 +0000526 public int getPriority() {
527 return job.getPriority();
528 }
Christopher Tate7060b042014-06-09 19:50:00 -0700529
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600530 public int getFlags() {
531 return job.getFlags();
532 }
533
Christopher Tate60977f42017-04-13 13:48:46 -0700534 /** Does this job have any sort of networking constraint? */
Christopher Tate7060b042014-06-09 19:50:00 -0700535 public boolean hasConnectivityConstraint() {
Christopher Tate60977f42017-04-13 13:48:46 -0700536 return (requiredConstraints&CONNECTIVITY_MASK) != 0;
537 }
538
539 public boolean needsAnyConnectivity() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800540 return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700541 }
542
Christopher Tate60977f42017-04-13 13:48:46 -0700543 public boolean needsUnmeteredConnectivity() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800544 return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700545 }
546
Christopher Tate60977f42017-04-13 13:48:46 -0700547 public boolean needsMeteredConnectivity() {
548 return (requiredConstraints&CONSTRAINT_METERED) != 0;
549 }
550
551 public boolean needsNonRoamingConnectivity() {
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600552 return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0;
553 }
554
Christopher Tate7060b042014-06-09 19:50:00 -0700555 public boolean hasChargingConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800556 return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700557 }
558
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800559 public boolean hasBatteryNotLowConstraint() {
560 return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0;
561 }
562
563 public boolean hasPowerConstraint() {
564 return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0;
565 }
566
Dianne Hackborn532ea262017-03-17 17:50:55 -0700567 public boolean hasStorageNotLowConstraint() {
568 return (requiredConstraints&CONSTRAINT_STORAGE_NOT_LOW) != 0;
569 }
570
Christopher Tate7060b042014-06-09 19:50:00 -0700571 public boolean hasTimingDelayConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800572 return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700573 }
574
575 public boolean hasDeadlineConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800576 return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700577 }
578
579 public boolean hasIdleConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800580 return (requiredConstraints&CONSTRAINT_IDLE) != 0;
Christopher Tate7060b042014-06-09 19:50:00 -0700581 }
582
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800583 public boolean hasContentTriggerConstraint() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800584 return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800585 }
586
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700587 public long getTriggerContentUpdateDelay() {
588 long time = job.getTriggerContentUpdateDelay();
589 if (time < 0) {
590 return DEFAULT_TRIGGER_UPDATE_DELAY;
591 }
592 return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
593 }
594
595 public long getTriggerContentMaxDelay() {
596 long time = job.getTriggerContentMaxDelay();
597 if (time < 0) {
598 return DEFAULT_TRIGGER_MAX_DELAY;
599 }
600 return Math.max(time, MIN_TRIGGER_MAX_DELAY);
601 }
602
Matthew Williams900c67f2014-07-09 12:46:53 -0700603 public boolean isPersisted() {
604 return job.isPersisted();
605 }
606
Christopher Tate7060b042014-06-09 19:50:00 -0700607 public long getEarliestRunTime() {
608 return earliestRunTimeElapsedMillis;
609 }
610
611 public long getLatestRunTimeElapsed() {
612 return latestRunTimeElapsedMillis;
613 }
614
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800615 boolean setChargingConstraintSatisfied(boolean state) {
616 return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
617 }
618
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800619 boolean setBatteryNotLowConstraintSatisfied(boolean state) {
620 return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
621 }
622
Dianne Hackborn532ea262017-03-17 17:50:55 -0700623 boolean setStorageNotLowConstraintSatisfied(boolean state) {
624 return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
625 }
626
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800627 boolean setTimingDelayConstraintSatisfied(boolean state) {
628 return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
629 }
630
631 boolean setDeadlineConstraintSatisfied(boolean state) {
632 return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
633 }
634
635 boolean setIdleConstraintSatisfied(boolean state) {
636 return setConstraintSatisfied(CONSTRAINT_IDLE, state);
637 }
638
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600639 boolean setConnectivityConstraintSatisfied(boolean state) {
640 return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
641 }
642
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800643 boolean setUnmeteredConstraintSatisfied(boolean state) {
644 return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
645 }
646
Christopher Tate60977f42017-04-13 13:48:46 -0700647 boolean setMeteredConstraintSatisfied(boolean state) {
648 return setConstraintSatisfied(CONSTRAINT_METERED, state);
649 }
650
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600651 boolean setNotRoamingConstraintSatisfied(boolean state) {
652 return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800653 }
654
655 boolean setAppNotIdleConstraintSatisfied(boolean state) {
656 return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
657 }
658
659 boolean setContentTriggerConstraintSatisfied(boolean state) {
660 return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
661 }
662
Dianne Hackborn7ab40252016-06-15 17:30:24 -0700663 boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
664 dozeWhitelisted = whitelisted;
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700665 return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
666 }
667
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800668 boolean setConstraintSatisfied(int constraint, boolean state) {
669 boolean old = (satisfiedConstraints&constraint) != 0;
670 if (old == state) {
671 return false;
672 }
673 satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
674 return true;
675 }
676
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700677 boolean isConstraintSatisfied(int constraint) {
678 return (satisfiedConstraints&constraint) != 0;
679 }
680
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700681 boolean clearTrackingController(int which) {
682 if ((trackingControllers&which) != 0) {
683 trackingControllers &= ~which;
684 return true;
685 }
686 return false;
687 }
688
689 void setTrackingController(int which) {
690 trackingControllers |= which;
691 }
692
Makoto Onukiab8a67f2017-06-20 12:20:34 -0700693 public long getLastSuccessfulRunTime() {
694 return mLastSuccessfulRunTime;
695 }
696
697 public long getLastFailedRunTime() {
698 return mLastFailedRunTime;
699 }
700
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700701 public boolean shouldDump(int filterUid) {
702 return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
703 || UserHandle.getAppId(getSourceUid()) == filterUid;
704 }
705
Christopher Tate7060b042014-06-09 19:50:00 -0700706 /**
Matthew Williams03a4da62014-09-10 17:32:18 -0700707 * @return Whether or not this job is ready to run, based on its requirements. This is true if
708 * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700709 * TODO: This function is called a *lot*. We should probably just have it check an
710 * already-computed boolean, which we updated whenever we see one of the states it depends
711 * on here change.
Christopher Tate7060b042014-06-09 19:50:00 -0700712 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800713 public boolean isReady() {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800714 // Deadline constraint trumps other constraints (except for periodic jobs where deadline
Christopher Tate5d346052016-03-08 12:56:08 -0800715 // is an implementation detail. A periodic job should only run if its constraints are
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800716 // satisfied).
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700717 // AppNotIdle implicit constraint must be satisfied
718 // DeviceNotDozing implicit constraint must be satisfied
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600719 final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
720 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
721 final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
722 final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
723 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
724 return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing;
Matthew Williams03a4da62014-09-10 17:32:18 -0700725 }
726
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800727 static final int CONSTRAINTS_OF_INTEREST =
Dianne Hackborn532ea262017-03-17 17:50:55 -0700728 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW |
729 CONSTRAINT_TIMING_DELAY |
Christopher Tate06f08522017-06-13 12:12:09 -0700730 CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
731 CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED |
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800732 CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
733
Christopher Tate5d346052016-03-08 12:56:08 -0800734 // Soft override covers all non-"functional" constraints
735 static final int SOFT_OVERRIDE_CONSTRAINTS =
Dianne Hackborn532ea262017-03-17 17:50:55 -0700736 CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800737 | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
Christopher Tate5d346052016-03-08 12:56:08 -0800738
Matthew Williams03a4da62014-09-10 17:32:18 -0700739 /**
740 * @return Whether the constraints set on this job are satisfied.
741 */
Dianne Hackbornd506b2b2016-02-16 10:30:33 -0800742 public boolean isConstraintsSatisfied() {
Christopher Tate5d346052016-03-08 12:56:08 -0800743 if (overrideState == OVERRIDE_FULL) {
744 // force override: the job is always runnable
745 return true;
746 }
747
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800748 final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
Christopher Tate5d346052016-03-08 12:56:08 -0800749
750 int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
751 if (overrideState == OVERRIDE_SOFT) {
752 // override: pretend all 'soft' requirements are satisfied
753 sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
754 }
755
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800756 return (sat & req) == req;
Christopher Tate7060b042014-06-09 19:50:00 -0700757 }
758
759 public boolean matches(int uid, int jobId) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000760 return this.job.getId() == jobId && this.callingUid == uid;
Christopher Tate7060b042014-06-09 19:50:00 -0700761 }
762
763 @Override
764 public String toString() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700765 StringBuilder sb = new StringBuilder(128);
766 sb.append("JobStatus{");
767 sb.append(Integer.toHexString(System.identityHashCode(this)));
768 sb.append(" #");
769 UserHandle.formatUid(sb, callingUid);
770 sb.append("/");
771 sb.append(job.getId());
772 sb.append(' ');
773 sb.append(batteryName);
774 sb.append(" u=");
775 sb.append(getUserId());
776 sb.append(" s=");
777 sb.append(getSourceUid());
778 if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
779 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700780 long now = SystemClock.elapsedRealtime();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700781 sb.append(" TIME=");
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700782 formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
783 sb.append(":");
784 formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
Dianne Hackborna47223f2017-03-30 13:49:13 -0700785 }
786 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
787 sb.append(" NET=");
788 sb.append(job.getNetworkType());
789 }
790 if (job.isRequireCharging()) {
791 sb.append(" CHARGING");
792 }
793 if (job.isRequireBatteryNotLow()) {
794 sb.append(" BATNOTLOW");
795 }
796 if (job.isRequireStorageNotLow()) {
797 sb.append(" STORENOTLOW");
798 }
799 if (job.isRequireDeviceIdle()) {
800 sb.append(" IDLE");
801 }
802 if (job.isPersisted()) {
803 sb.append(" PERSISTED");
804 }
805 if ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) == 0) {
806 sb.append(" WAIT:APP_NOT_IDLE");
807 }
808 if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
809 sb.append(" WAIT:DEV_NOT_DOZING");
810 }
811 if (job.getTriggerContentUris() != null) {
812 sb.append(" URIS=");
813 sb.append(Arrays.toString(job.getTriggerContentUris()));
814 }
815 if (numFailures != 0) {
816 sb.append(" failures=");
817 sb.append(numFailures);
818 }
819 if (isReady()) {
820 sb.append(" READY");
821 }
822 sb.append("}");
823 return sb.toString();
Christopher Tate7060b042014-06-09 19:50:00 -0700824 }
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700825
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700826 private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700827 if (runtime == defaultValue) {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700828 pw.print("none");
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700829 } else {
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700830 TimeUtils.formatDuration(runtime - now, pw);
831 }
832 }
833
834 private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) {
835 if (runtime == defaultValue) {
836 sb.append("none");
837 } else {
838 TimeUtils.formatDuration(runtime - now, sb);
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700839 }
840 }
841
842 /**
843 * Convenience function to identify a job uniquely without pulling all the data that
844 * {@link #toString()} returns.
845 */
846 public String toShortString() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800847 StringBuilder sb = new StringBuilder();
848 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700849 sb.append(" #");
850 UserHandle.formatUid(sb, callingUid);
851 sb.append("/");
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800852 sb.append(job.getId());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800853 sb.append(' ');
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700854 sb.append(batteryName);
855 return sb.toString();
856 }
857
858 /**
859 * Convenience function to identify a job uniquely without pulling all the data that
860 * {@link #toString()} returns.
861 */
862 public String toShortStringExceptUniqueId() {
863 StringBuilder sb = new StringBuilder();
864 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800865 sb.append(' ');
Dianne Hackborn970510b2016-02-24 16:56:42 -0800866 sb.append(batteryName);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800867 return sb.toString();
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700868 }
869
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800870 void dumpConstraints(PrintWriter pw, int constraints) {
871 if ((constraints&CONSTRAINT_CHARGING) != 0) {
872 pw.print(" CHARGING");
873 }
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800874 if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
875 pw.print(" BATTERY_NOT_LOW");
876 }
Dianne Hackborn532ea262017-03-17 17:50:55 -0700877 if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) {
878 pw.print(" STORAGE_NOT_LOW");
879 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800880 if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
881 pw.print(" TIMING_DELAY");
882 }
883 if ((constraints&CONSTRAINT_DEADLINE) != 0) {
884 pw.print(" DEADLINE");
885 }
886 if ((constraints&CONSTRAINT_IDLE) != 0) {
887 pw.print(" IDLE");
888 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600889 if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
890 pw.print(" CONNECTIVITY");
891 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800892 if ((constraints&CONSTRAINT_UNMETERED) != 0) {
893 pw.print(" UNMETERED");
894 }
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600895 if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
896 pw.print(" NOT_ROAMING");
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800897 }
Christopher Tate06f08522017-06-13 12:12:09 -0700898 if ((constraints&CONSTRAINT_METERED) != 0) {
899 pw.print(" METERED");
900 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800901 if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
902 pw.print(" APP_NOT_IDLE");
903 }
904 if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
905 pw.print(" CONTENT_TRIGGER");
906 }
Amith Yamasanicb926fc2016-03-14 17:15:20 -0700907 if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
908 pw.print(" DEVICE_NOT_DOZING");
909 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800910 }
911
Dianne Hackborn342e6032017-04-13 18:04:31 -0700912 private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
913 pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #");
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700914 pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
915 pw.print("x "); pw.println(work.getIntent());
Dianne Hackborn342e6032017-04-13 18:04:31 -0700916 if (work.getGrants() != null) {
917 pw.print(prefix); pw.println(" URI grants:");
918 ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " ");
919 }
920 }
921
Christopher Tate7060b042014-06-09 19:50:00 -0700922 // Dumpsys infrastructure
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700923 public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
Shreyas Basarge8e64e2e2016-02-12 15:49:31 +0000924 pw.print(prefix); UserHandle.formatUid(pw, callingUid);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800925 pw.print(" tag="); pw.println(tag);
Christopher Tatef973a7b2014-08-29 12:54:08 -0700926 pw.print(prefix);
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000927 pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
928 pw.print(" user="); pw.print(getSourceUserId());
929 pw.print(" pkg="); pw.println(getSourcePackageName());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800930 if (full) {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700931 pw.print(prefix); pw.println("JobInfo:");
932 pw.print(prefix); pw.print(" Service: ");
933 pw.println(job.getService().flattenToShortString());
Dianne Hackborn970510b2016-02-24 16:56:42 -0800934 if (job.isPeriodic()) {
935 pw.print(prefix); pw.print(" PERIODIC: interval=");
936 TimeUtils.formatDuration(job.getIntervalMillis(), pw);
937 pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
938 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800939 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800940 if (job.isPersisted()) {
941 pw.print(prefix); pw.println(" PERSISTED");
942 }
943 if (job.getPriority() != 0) {
944 pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
945 }
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600946 if (job.getFlags() != 0) {
947 pw.print(prefix); pw.print(" Flags: ");
948 pw.println(Integer.toHexString(job.getFlags()));
949 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800950 pw.print(prefix); pw.print(" Requires: charging=");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800951 pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
952 pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
Dianne Hackborn970510b2016-02-24 16:56:42 -0800953 pw.println(job.isRequireDeviceIdle());
954 if (job.getTriggerContentUris() != null) {
955 pw.print(prefix); pw.println(" Trigger content URIs:");
956 for (int i = 0; i < job.getTriggerContentUris().length; i++) {
957 JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
958 pw.print(prefix); pw.print(" ");
959 pw.print(Integer.toHexString(trig.getFlags()));
960 pw.print(' '); pw.println(trig.getUri());
961 }
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700962 if (job.getTriggerContentUpdateDelay() >= 0) {
963 pw.print(prefix); pw.print(" Trigger update delay: ");
964 TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
965 pw.println();
966 }
967 if (job.getTriggerContentMaxDelay() >= 0) {
968 pw.print(prefix); pw.print(" Trigger max delay: ");
969 TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
970 pw.println();
971 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800972 }
Dianne Hackborna47223f2017-03-30 13:49:13 -0700973 if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
974 pw.print(prefix); pw.print(" Extras: ");
975 pw.println(job.getExtras().toShortString());
976 }
977 if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
978 pw.print(prefix); pw.print(" Transient extras: ");
979 pw.println(job.getTransientExtras().toShortString());
980 }
981 if (job.getClipData() != null) {
982 pw.print(prefix); pw.print(" Clip data: ");
983 StringBuilder b = new StringBuilder(128);
984 job.getClipData().toShortString(b);
985 pw.println(b);
986 }
Dianne Hackborn342e6032017-04-13 18:04:31 -0700987 if (uriPerms != null) {
988 pw.print(prefix); pw.println(" Granted URI permissions:");
989 uriPerms.dump(pw, prefix + " ");
990 }
Dianne Hackborn970510b2016-02-24 16:56:42 -0800991 if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
992 pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
993 }
994 if (job.getMinLatencyMillis() != 0) {
995 pw.print(prefix); pw.print(" Minimum latency: ");
996 TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
997 pw.println();
998 }
999 if (job.getMaxExecutionDelayMillis() != 0) {
1000 pw.print(prefix); pw.print(" Max execution delay: ");
1001 TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
1002 pw.println();
1003 }
1004 pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
1005 pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001006 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001007 if (job.hasEarlyConstraint()) {
1008 pw.print(prefix); pw.println(" Has early constraint");
1009 }
1010 if (job.hasLateConstraint()) {
1011 pw.print(prefix); pw.println(" Has late constraint");
1012 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001013 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -08001014 pw.print(prefix); pw.print("Required constraints:");
1015 dumpConstraints(pw, requiredConstraints);
1016 pw.println();
Dianne Hackborn970510b2016-02-24 16:56:42 -08001017 if (full) {
1018 pw.print(prefix); pw.print("Satisfied constraints:");
1019 dumpConstraints(pw, satisfiedConstraints);
1020 pw.println();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001021 pw.print(prefix); pw.print("Unsatisfied constraints:");
1022 dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
1023 pw.println();
Dianne Hackborn7ab40252016-06-15 17:30:24 -07001024 if (dozeWhitelisted) {
1025 pw.print(prefix); pw.println("Doze whitelisted: true");
1026 }
Dianne Hackborn970510b2016-02-24 16:56:42 -08001027 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001028 if (trackingControllers != 0) {
1029 pw.print(prefix); pw.print("Tracking:");
1030 if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY");
1031 if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY");
1032 if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT");
1033 if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE");
1034 if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE");
1035 if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME");
1036 pw.println();
1037 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001038 if (changedAuthorities != null) {
1039 pw.print(prefix); pw.println("Changed authorities:");
1040 for (int i=0; i<changedAuthorities.size(); i++) {
1041 pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i));
1042 }
1043 if (changedUris != null) {
1044 pw.print(prefix); pw.println("Changed URIs:");
1045 for (int i=0; i<changedUris.size(); i++) {
1046 pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i));
1047 }
1048 }
1049 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001050 if (pendingWork != null && pendingWork.size() > 0) {
1051 pw.print(prefix); pw.println("Pending work:");
1052 for (int i = 0; i < pendingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001053 dumpJobWorkItem(pw, prefix, pendingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001054 }
1055 }
1056 if (executingWork != null && executingWork.size() > 0) {
1057 pw.print(prefix); pw.println("Executing work:");
1058 for (int i = 0; i < executingWork.size(); i++) {
Dianne Hackborn342e6032017-04-13 18:04:31 -07001059 dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
Dianne Hackborn7da13d72017-04-04 17:17:35 -07001060 }
1061 }
Dianne Hackbornbfc23312017-05-11 11:53:24 -07001062 pw.print(prefix); pw.print("Enqueue time: ");
1063 TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
1064 pw.println();
1065 pw.print(prefix); pw.print("Run time: earliest=");
1066 formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
1067 pw.print(", latest=");
1068 formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
1069 pw.println();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001070 if (numFailures != 0) {
1071 pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
1072 }
Makoto Onukiab8a67f2017-06-20 12:20:34 -07001073 final Time t = new Time();
1074 final String format = "%Y-%m-%d %H:%M:%S";
1075 if (mLastSuccessfulRunTime != 0) {
1076 pw.print(prefix); pw.print("Last successful run: ");
1077 t.set(mLastSuccessfulRunTime);
1078 pw.println(t.format(format));
1079 }
1080 if (mLastFailedRunTime != 0) {
1081 pw.print(prefix); pw.print("Last failed run: ");
1082 t.set(mLastFailedRunTime);
1083 pw.println(t.format(format));
1084 }
Christopher Tate7060b042014-06-09 19:50:00 -07001085 }
1086}