Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.server.job.controllers; |
| 18 | |
Shreyas Basarge | 968ac75 | 2016-01-11 23:09:26 +0000 | [diff] [blame] | 19 | import android.app.AppGlobals; |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 20 | import android.app.IActivityManager; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 21 | import android.app.job.JobInfo; |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 22 | import android.app.job.JobWorkItem; |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 23 | import android.content.ClipData; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 24 | import android.content.ComponentName; |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 25 | import android.net.Uri; |
Shreyas Basarge | 968ac75 | 2016-01-11 23:09:26 +0000 | [diff] [blame] | 26 | import android.os.RemoteException; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 27 | import android.os.SystemClock; |
| 28 | import android.os.UserHandle; |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 29 | import android.text.format.Time; |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 30 | import android.util.ArraySet; |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 31 | import android.util.Pair; |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 32 | import android.util.Slog; |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 33 | import android.util.TimeUtils; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 34 | |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 35 | import com.android.server.job.GrantedUriPermissions; |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 36 | import com.android.server.job.JobSchedulerService; |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 37 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 38 | import java.io.PrintWriter; |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 39 | import java.util.ArrayList; |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 40 | import java.util.Arrays; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 41 | |
| 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 Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 53 | public final class JobStatus { |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 54 | static final String TAG = "JobSchedulerService"; |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 55 | static final boolean DEBUG = JobSchedulerService.DEBUG; |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 56 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 57 | public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE; |
| 58 | public static final long NO_EARLIEST_RUNTIME = 0L; |
| 59 | |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 60 | 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 Hackborn | 532ea26 | 2017-03-17 17:50:55 -0700 | [diff] [blame] | 63 | static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW; |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 64 | 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 Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 72 | static final int CONSTRAINT_METERED = 1<<23; |
Suprabh Shukla | 3ac1daa | 2017-07-14 12:15:27 -0700 | [diff] [blame] | 73 | static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22; |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 74 | |
| 75 | static final int CONNECTIVITY_MASK = |
| 76 | CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY | |
| 77 | CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED; |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 78 | |
Christopher Tate | 5d34605 | 2016-03-08 12:56:08 -0800 | [diff] [blame] | 79 | // Soft override: ignore constraints like time that don't affect API availability |
| 80 | public static final int OVERRIDE_SOFT = 1; |
| 81 | // Full override: ignore all constraints including API-affecting like connectivity |
| 82 | public static final int OVERRIDE_FULL = 2; |
| 83 | |
Dianne Hackborn | 8db0fc1 | 2016-04-12 13:48:25 -0700 | [diff] [blame] | 84 | /** If not specified, trigger update delay is 10 seconds. */ |
| 85 | public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000; |
| 86 | |
| 87 | /** The minimum possible update delay is 1/2 second. */ |
| 88 | public static final long MIN_TRIGGER_UPDATE_DELAY = 500; |
| 89 | |
| 90 | /** If not specified, trigger maxumum delay is 2 minutes. */ |
| 91 | public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000; |
| 92 | |
| 93 | /** The minimum possible update delay is 1 second. */ |
| 94 | public static final long MIN_TRIGGER_MAX_DELAY = 1000; |
| 95 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 96 | final JobInfo job; |
Matthew Williams | 9ae3dbe | 2014-08-21 13:47:47 -0700 | [diff] [blame] | 97 | /** Uid of the package requesting this job. */ |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 98 | final int callingUid; |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 99 | final String batteryName; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 100 | |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 101 | final String sourcePackageName; |
| 102 | final int sourceUserId; |
| 103 | final int sourceUid; |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 104 | final String sourceTag; |
| 105 | |
| 106 | final String tag; |
Shreyas Basarge | 968ac75 | 2016-01-11 23:09:26 +0000 | [diff] [blame] | 107 | |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 108 | private GrantedUriPermissions uriPerms; |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 109 | private boolean prepared; |
| 110 | |
Christopher Tate | b164f01 | 2017-04-26 15:41:37 -0700 | [diff] [blame] | 111 | static final boolean DEBUG_PREPARE = true; |
| 112 | private Throwable unpreparedPoint = null; |
| 113 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 114 | /** |
| 115 | * Earliest point in the future at which this job will be eligible to run. A value of 0 |
| 116 | * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}. |
| 117 | */ |
| 118 | private final long earliestRunTimeElapsedMillis; |
| 119 | /** |
| 120 | * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE} |
| 121 | * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}. |
| 122 | */ |
| 123 | private final long latestRunTimeElapsedMillis; |
| 124 | |
| 125 | /** How many times this job has failed, used to compute back-off. */ |
| 126 | private final int numFailures; |
| 127 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 128 | // Constraints. |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 129 | final int requiredConstraints; |
| 130 | int satisfiedConstraints = 0; |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 131 | |
Dianne Hackborn | 7ab4025 | 2016-06-15 17:30:24 -0700 | [diff] [blame] | 132 | // Set to true if doze constraint was satisfied due to app being whitelisted. |
| 133 | public boolean dozeWhitelisted; |
| 134 | |
Dianne Hackborn | f9bac16 | 2017-04-20 17:17:48 -0700 | [diff] [blame] | 135 | /** |
| 136 | * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job. |
| 137 | */ |
| 138 | public static final int TRACKING_BATTERY = 1<<0; |
| 139 | /** |
| 140 | * Flag for {@link #trackingControllers}: the network connectivity controller is currently |
| 141 | * tracking this job. |
| 142 | */ |
| 143 | public static final int TRACKING_CONNECTIVITY = 1<<1; |
| 144 | /** |
| 145 | * Flag for {@link #trackingControllers}: the content observer controller is currently |
| 146 | * tracking this job. |
| 147 | */ |
| 148 | public static final int TRACKING_CONTENT = 1<<2; |
| 149 | /** |
| 150 | * Flag for {@link #trackingControllers}: the idle controller is currently tracking this job. |
| 151 | */ |
| 152 | public static final int TRACKING_IDLE = 1<<3; |
| 153 | /** |
| 154 | * Flag for {@link #trackingControllers}: the storage controller is currently tracking this job. |
| 155 | */ |
| 156 | public static final int TRACKING_STORAGE = 1<<4; |
| 157 | /** |
| 158 | * Flag for {@link #trackingControllers}: the time controller is currently tracking this job. |
| 159 | */ |
| 160 | public static final int TRACKING_TIME = 1<<5; |
| 161 | |
| 162 | /** |
| 163 | * Bit mask of controllers that are currently tracking the job. |
| 164 | */ |
| 165 | private int trackingControllers; |
| 166 | |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 167 | // These are filled in by controllers when preparing for execution. |
| 168 | public ArraySet<Uri> changedUris; |
| 169 | public ArraySet<String> changedAuthorities; |
| 170 | |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 171 | public int lastEvaluatedPriority; |
| 172 | |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 173 | // If non-null, this is work that has been enqueued for the job. |
| 174 | public ArrayList<JobWorkItem> pendingWork; |
| 175 | |
| 176 | // If non-null, this is work that is currently being executed. |
| 177 | public ArrayList<JobWorkItem> executingWork; |
| 178 | |
| 179 | public int nextPendingWorkId = 1; |
| 180 | |
Christopher Tate | 5d34605 | 2016-03-08 12:56:08 -0800 | [diff] [blame] | 181 | // Used by shell commands |
| 182 | public int overrideState = 0; |
| 183 | |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 184 | // When this job was enqueued, for ordering. (in elapsedRealtimeMillis) |
| 185 | public long enqueueTime; |
| 186 | |
| 187 | // Metrics about queue latency. (in uptimeMillis) |
Christopher Tate | 7234fc6 | 2017-04-03 17:36:07 -0700 | [diff] [blame] | 188 | public long madePending; |
| 189 | public long madeActive; |
| 190 | |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 191 | /** |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 192 | * Last time a job finished successfully for a periodic job, in the currentTimeMillis time, |
| 193 | * for dumpsys. |
| 194 | */ |
| 195 | private long mLastSuccessfulRunTime; |
| 196 | |
| 197 | /** |
| 198 | * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys. |
| 199 | */ |
| 200 | private long mLastFailedRunTime; |
| 201 | |
| 202 | /** |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 203 | * Transient: when a job is inflated from disk before we have a reliable RTC clock time, |
| 204 | * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent |
| 205 | * store in UTC so that we can fix up the job's scheduling criteria once we get a good |
| 206 | * wall-clock time. If we have to persist the job again before the clock has been updated, |
| 207 | * we record these times again rather than calculating based on the earliest/latest elapsed |
| 208 | * time base figures. |
| 209 | * |
| 210 | * 'first' is the earliest/delay time, and 'second' is the latest/deadline time. |
| 211 | */ |
| 212 | private Pair<Long, Long> mPersistedUtcTimes; |
| 213 | |
| 214 | /** |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 215 | * For use only by ContentObserverController: state it is maintaining about content URIs |
| 216 | * being observed. |
| 217 | */ |
| 218 | ContentObserverController.JobInstance contentObserverJobInstance; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 219 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 220 | /** Provide a handle to the service that this job will be run on. */ |
| 221 | public int getServiceToken() { |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 222 | return callingUid; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 223 | } |
| 224 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 225 | private JobStatus(JobInfo job, int callingUid, String sourcePackageName, |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 226 | int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis, |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 227 | long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime) { |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 228 | this.job = job; |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 229 | this.callingUid = callingUid; |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 230 | |
| 231 | int tempSourceUid = -1; |
| 232 | if (sourceUserId != -1 && sourcePackageName != null) { |
| 233 | try { |
| 234 | tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0, |
| 235 | sourceUserId); |
| 236 | } catch (RemoteException ex) { |
| 237 | // Can't happen, PackageManager runs in the same process. |
| 238 | } |
| 239 | } |
| 240 | if (tempSourceUid == -1) { |
| 241 | this.sourceUid = callingUid; |
| 242 | this.sourceUserId = UserHandle.getUserId(callingUid); |
| 243 | this.sourcePackageName = job.getService().getPackageName(); |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 244 | this.sourceTag = null; |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 245 | } else { |
| 246 | this.sourceUid = tempSourceUid; |
| 247 | this.sourceUserId = sourceUserId; |
| 248 | this.sourcePackageName = sourcePackageName; |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 249 | this.sourceTag = tag; |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 250 | } |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 251 | |
Shreyas Basarge | eda34e4 | 2016-04-26 00:14:02 +0100 | [diff] [blame] | 252 | this.batteryName = this.sourceTag != null |
| 253 | ? this.sourceTag + ":" + job.getService().getPackageName() |
| 254 | : job.getService().flattenToShortString(); |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 255 | this.tag = "*job*/" + this.batteryName; |
| 256 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 257 | this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis; |
| 258 | this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis; |
| 259 | this.numFailures = numFailures; |
| 260 | |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 261 | int requiredConstraints = job.getConstraintFlags(); |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 262 | |
| 263 | switch (job.getNetworkType()) { |
| 264 | case JobInfo.NETWORK_TYPE_NONE: |
| 265 | // No constraint. |
| 266 | break; |
| 267 | case JobInfo.NETWORK_TYPE_ANY: |
| 268 | requiredConstraints |= CONSTRAINT_CONNECTIVITY; |
| 269 | break; |
| 270 | case JobInfo.NETWORK_TYPE_UNMETERED: |
| 271 | requiredConstraints |= CONSTRAINT_UNMETERED; |
| 272 | break; |
| 273 | case JobInfo.NETWORK_TYPE_NOT_ROAMING: |
| 274 | requiredConstraints |= CONSTRAINT_NOT_ROAMING; |
| 275 | break; |
| 276 | case JobInfo.NETWORK_TYPE_METERED: |
| 277 | requiredConstraints |= CONSTRAINT_METERED; |
| 278 | break; |
| 279 | default: |
| 280 | Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType()); |
| 281 | break; |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 282 | } |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 283 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 284 | if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) { |
| 285 | requiredConstraints |= CONSTRAINT_TIMING_DELAY; |
| 286 | } |
| 287 | if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { |
| 288 | requiredConstraints |= CONSTRAINT_DEADLINE; |
| 289 | } |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 290 | if (job.getTriggerContentUris() != null) { |
| 291 | requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER; |
| 292 | } |
| 293 | this.requiredConstraints = requiredConstraints; |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 294 | |
| 295 | mLastSuccessfulRunTime = lastSuccessfulRunTime; |
| 296 | mLastFailedRunTime = lastFailedRunTime; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 297 | } |
| 298 | |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 299 | /** Copy constructor: used specifically when cloning JobStatus objects for persistence, |
| 300 | * so we preserve RTC window bounds if the source object has them. */ |
Matthew Williams | 0cc7654 | 2015-10-16 21:04:51 -0700 | [diff] [blame] | 301 | public JobStatus(JobStatus jobStatus) { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 302 | this(jobStatus.getJob(), jobStatus.getUid(), |
Dianne Hackborn | d506b2b | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 303 | jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 304 | jobStatus.getSourceTag(), jobStatus.getNumFailures(), |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 305 | jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), |
| 306 | jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime()); |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 307 | mPersistedUtcTimes = jobStatus.mPersistedUtcTimes; |
| 308 | if (jobStatus.mPersistedUtcTimes != null) { |
| 309 | if (DEBUG) { |
| 310 | Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here")); |
| 311 | } |
| 312 | } |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 313 | } |
| 314 | |
| 315 | /** |
| 316 | * Create a new JobStatus that was loaded from disk. We ignore the provided |
| 317 | * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job |
| 318 | * from the {@link com.android.server.job.JobStore} and still want to respect its |
| 319 | * wallclock runtime rather than resetting it on every boot. |
| 320 | * We consider a freshly loaded job to no longer be in back-off. |
| 321 | */ |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 322 | public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 323 | String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 324 | long lastSuccessfulRunTime, long lastFailedRunTime, |
| 325 | Pair<Long, Long> persistedExecutionTimesUTC) { |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 326 | this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0, |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 327 | earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, |
| 328 | lastSuccessfulRunTime, lastFailedRunTime); |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 329 | |
| 330 | // Only during initial inflation do we record the UTC-timebase execution bounds |
| 331 | // read from the persistent store. If we ever have to recreate the JobStatus on |
| 332 | // the fly, it means we're rescheduling the job; and this means that the calculated |
| 333 | // elapsed timebase bounds intrinsically become correct. |
| 334 | this.mPersistedUtcTimes = persistedExecutionTimesUTC; |
| 335 | if (persistedExecutionTimesUTC != null) { |
| 336 | if (DEBUG) { |
| 337 | Slog.i(TAG, "+ restored job with RTC times because of bad boot clock"); |
| 338 | } |
| 339 | } |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 340 | } |
| 341 | |
| 342 | /** Create a new job to be rescheduled with the provided parameters. */ |
| 343 | public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 344 | long newLatestRuntimeElapsedMillis, int backoffAttempt, |
| 345 | long lastSuccessfulRunTime, long lastFailedRunTime) { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 346 | this(rescheduling.job, rescheduling.getUid(), |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 347 | rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), |
| 348 | rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis, |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 349 | newLatestRuntimeElapsedMillis, |
| 350 | lastSuccessfulRunTime, lastFailedRunTime); |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 351 | } |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 352 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 353 | /** |
| 354 | * Create a newly scheduled job. |
| 355 | * @param callingUid Uid of the package that scheduled this job. |
| 356 | * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates |
| 357 | * the calling package is the source. |
| 358 | * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the |
| 359 | */ |
| 360 | public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName, |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 361 | int sourceUserId, String tag) { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 362 | final long elapsedNow = SystemClock.elapsedRealtime(); |
| 363 | final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis; |
| 364 | if (job.isPeriodic()) { |
| 365 | latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis(); |
| 366 | earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis(); |
| 367 | } else { |
| 368 | earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ? |
| 369 | elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME; |
| 370 | latestRunTimeElapsedMillis = job.hasLateConstraint() ? |
| 371 | elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME; |
| 372 | } |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 373 | return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0, |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 374 | earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, |
| 375 | 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */); |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 376 | } |
| 377 | |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 378 | public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) { |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 379 | if (pendingWork == null) { |
| 380 | pendingWork = new ArrayList<>(); |
| 381 | } |
| 382 | work.setWorkId(nextPendingWorkId); |
| 383 | nextPendingWorkId++; |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 384 | if (work.getIntent() != null |
| 385 | && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) { |
| 386 | work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid, |
| 387 | sourcePackageName, sourceUserId, toShortString())); |
| 388 | } |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 389 | pendingWork.add(work); |
| 390 | } |
| 391 | |
| 392 | public JobWorkItem dequeueWorkLocked() { |
| 393 | if (pendingWork != null && pendingWork.size() > 0) { |
| 394 | JobWorkItem work = pendingWork.remove(0); |
| 395 | if (work != null) { |
| 396 | if (executingWork == null) { |
| 397 | executingWork = new ArrayList<>(); |
| 398 | } |
| 399 | executingWork.add(work); |
Dianne Hackborn | 28d1b66 | 2017-04-21 14:17:23 -0700 | [diff] [blame] | 400 | work.bumpDeliveryCount(); |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 401 | } |
| 402 | return work; |
| 403 | } |
| 404 | return null; |
| 405 | } |
| 406 | |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 407 | public boolean hasWorkLocked() { |
| 408 | return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked(); |
| 409 | } |
| 410 | |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 411 | public boolean hasExecutingWorkLocked() { |
| 412 | return executingWork != null && executingWork.size() > 0; |
| 413 | } |
| 414 | |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 415 | private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) { |
| 416 | if (work.getGrants() != null) { |
| 417 | ((GrantedUriPermissions)work.getGrants()).revoke(am); |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | public boolean completeWorkLocked(IActivityManager am, int workId) { |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 422 | if (executingWork != null) { |
| 423 | final int N = executingWork.size(); |
| 424 | for (int i = 0; i < N; i++) { |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 425 | JobWorkItem work = executingWork.get(i); |
| 426 | if (work.getWorkId() == workId) { |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 427 | executingWork.remove(i); |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 428 | ungrantWorkItem(am, work); |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 429 | return true; |
| 430 | } |
| 431 | } |
| 432 | } |
| 433 | return false; |
| 434 | } |
| 435 | |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 436 | private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) { |
| 437 | if (list != null) { |
| 438 | final int N = list.size(); |
| 439 | for (int i = 0; i < N; i++) { |
| 440 | ungrantWorkItem(am, list.get(i)); |
| 441 | } |
| 442 | } |
| 443 | } |
| 444 | |
| 445 | public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) { |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 446 | if (incomingJob != null) { |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 447 | // We are replacing with a new job -- transfer the work! We do any executing |
| 448 | // work first, since that was originally at the front of the pending work. |
| 449 | if (executingWork != null && executingWork.size() > 0) { |
| 450 | incomingJob.pendingWork = executingWork; |
| 451 | } |
| 452 | if (incomingJob.pendingWork == null) { |
| 453 | incomingJob.pendingWork = pendingWork; |
| 454 | } else if (pendingWork != null && pendingWork.size() > 0) { |
| 455 | incomingJob.pendingWork.addAll(pendingWork); |
| 456 | } |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 457 | pendingWork = null; |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 458 | executingWork = null; |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 459 | incomingJob.nextPendingWorkId = nextPendingWorkId; |
| 460 | } else { |
| 461 | // We are completely stopping the job... need to clean up work. |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 462 | ungrantWorkList(am, pendingWork); |
| 463 | pendingWork = null; |
| 464 | ungrantWorkList(am, executingWork); |
| 465 | executingWork = null; |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 466 | } |
| 467 | } |
| 468 | |
| 469 | public void prepareLocked(IActivityManager am) { |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 470 | if (prepared) { |
| 471 | Slog.wtf(TAG, "Already prepared: " + this); |
| 472 | return; |
| 473 | } |
| 474 | prepared = true; |
Christopher Tate | b164f01 | 2017-04-26 15:41:37 -0700 | [diff] [blame] | 475 | if (DEBUG_PREPARE) { |
| 476 | unpreparedPoint = null; |
| 477 | } |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 478 | final ClipData clip = job.getClipData(); |
| 479 | if (clip != null) { |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 480 | uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName, |
| 481 | sourceUserId, job.getClipGrantFlags(), toShortString()); |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 482 | } |
| 483 | } |
| 484 | |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 485 | public void unprepareLocked(IActivityManager am) { |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 486 | if (!prepared) { |
| 487 | Slog.wtf(TAG, "Hasn't been prepared: " + this); |
Christopher Tate | b164f01 | 2017-04-26 15:41:37 -0700 | [diff] [blame] | 488 | if (DEBUG_PREPARE && unpreparedPoint != null) { |
| 489 | Slog.e(TAG, "Was already unprepared at ", unpreparedPoint); |
| 490 | } |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 491 | return; |
| 492 | } |
| 493 | prepared = false; |
Christopher Tate | b164f01 | 2017-04-26 15:41:37 -0700 | [diff] [blame] | 494 | if (DEBUG_PREPARE) { |
| 495 | unpreparedPoint = new Throwable().fillInStackTrace(); |
| 496 | } |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 497 | if (uriPerms != null) { |
| 498 | uriPerms.revoke(am); |
| 499 | uriPerms = null; |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 500 | } |
| 501 | } |
| 502 | |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 503 | public boolean isPreparedLocked() { |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 504 | return prepared; |
| 505 | } |
| 506 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 507 | public JobInfo getJob() { |
| 508 | return job; |
| 509 | } |
| 510 | |
| 511 | public int getJobId() { |
| 512 | return job.getId(); |
| 513 | } |
| 514 | |
Dianne Hackborn | e9a988c | 2016-05-27 17:59:40 -0700 | [diff] [blame] | 515 | public void printUniqueId(PrintWriter pw) { |
| 516 | UserHandle.formatUid(pw, callingUid); |
| 517 | pw.print("/"); |
| 518 | pw.print(job.getId()); |
| 519 | } |
| 520 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 521 | public int getNumFailures() { |
| 522 | return numFailures; |
| 523 | } |
| 524 | |
| 525 | public ComponentName getServiceComponent() { |
| 526 | return job.getService(); |
| 527 | } |
| 528 | |
Shreyas Basarge | 968ac75 | 2016-01-11 23:09:26 +0000 | [diff] [blame] | 529 | public String getSourcePackageName() { |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 530 | return sourcePackageName; |
Shreyas Basarge | 968ac75 | 2016-01-11 23:09:26 +0000 | [diff] [blame] | 531 | } |
| 532 | |
| 533 | public int getSourceUid() { |
| 534 | return sourceUid; |
| 535 | } |
| 536 | |
| 537 | public int getSourceUserId() { |
Shreyas Basarge | 968ac75 | 2016-01-11 23:09:26 +0000 | [diff] [blame] | 538 | return sourceUserId; |
| 539 | } |
| 540 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 541 | public int getUserId() { |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 542 | return UserHandle.getUserId(callingUid); |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 543 | } |
| 544 | |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 545 | public String getSourceTag() { |
| 546 | return sourceTag; |
| 547 | } |
| 548 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 549 | public int getUid() { |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 550 | return callingUid; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 551 | } |
| 552 | |
Dianne Hackborn | 1085ff6 | 2016-02-23 17:04:58 -0800 | [diff] [blame] | 553 | public String getBatteryName() { |
| 554 | return batteryName; |
Dianne Hackborn | fdb1956 | 2014-07-11 16:03:36 -0700 | [diff] [blame] | 555 | } |
| 556 | |
| 557 | public String getTag() { |
| 558 | return tag; |
| 559 | } |
| 560 | |
Shreyas Basarge | 5db0908 | 2016-01-07 13:38:29 +0000 | [diff] [blame] | 561 | public int getPriority() { |
| 562 | return job.getPriority(); |
| 563 | } |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 564 | |
Jeff Sharkey | 1b6519b | 2016-04-28 15:33:18 -0600 | [diff] [blame] | 565 | public int getFlags() { |
| 566 | return job.getFlags(); |
| 567 | } |
| 568 | |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 569 | /** Does this job have any sort of networking constraint? */ |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 570 | public boolean hasConnectivityConstraint() { |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 571 | return (requiredConstraints&CONNECTIVITY_MASK) != 0; |
| 572 | } |
| 573 | |
| 574 | public boolean needsAnyConnectivity() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 575 | return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 576 | } |
| 577 | |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 578 | public boolean needsUnmeteredConnectivity() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 579 | return (requiredConstraints&CONSTRAINT_UNMETERED) != 0; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 580 | } |
| 581 | |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 582 | public boolean needsMeteredConnectivity() { |
| 583 | return (requiredConstraints&CONSTRAINT_METERED) != 0; |
| 584 | } |
| 585 | |
| 586 | public boolean needsNonRoamingConnectivity() { |
Jeff Sharkey | f07c7b9 | 2016-04-22 09:50:16 -0600 | [diff] [blame] | 587 | return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0; |
| 588 | } |
| 589 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 590 | public boolean hasChargingConstraint() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 591 | return (requiredConstraints&CONSTRAINT_CHARGING) != 0; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 592 | } |
| 593 | |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 594 | public boolean hasBatteryNotLowConstraint() { |
| 595 | return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0; |
| 596 | } |
| 597 | |
| 598 | public boolean hasPowerConstraint() { |
| 599 | return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0; |
| 600 | } |
| 601 | |
Dianne Hackborn | 532ea26 | 2017-03-17 17:50:55 -0700 | [diff] [blame] | 602 | public boolean hasStorageNotLowConstraint() { |
| 603 | return (requiredConstraints&CONSTRAINT_STORAGE_NOT_LOW) != 0; |
| 604 | } |
| 605 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 606 | public boolean hasTimingDelayConstraint() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 607 | return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 608 | } |
| 609 | |
| 610 | public boolean hasDeadlineConstraint() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 611 | return (requiredConstraints&CONSTRAINT_DEADLINE) != 0; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 612 | } |
| 613 | |
| 614 | public boolean hasIdleConstraint() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 615 | return (requiredConstraints&CONSTRAINT_IDLE) != 0; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 616 | } |
| 617 | |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 618 | public boolean hasContentTriggerConstraint() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 619 | return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0; |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 620 | } |
| 621 | |
Dianne Hackborn | 8db0fc1 | 2016-04-12 13:48:25 -0700 | [diff] [blame] | 622 | public long getTriggerContentUpdateDelay() { |
| 623 | long time = job.getTriggerContentUpdateDelay(); |
| 624 | if (time < 0) { |
| 625 | return DEFAULT_TRIGGER_UPDATE_DELAY; |
| 626 | } |
| 627 | return Math.max(time, MIN_TRIGGER_UPDATE_DELAY); |
| 628 | } |
| 629 | |
| 630 | public long getTriggerContentMaxDelay() { |
| 631 | long time = job.getTriggerContentMaxDelay(); |
| 632 | if (time < 0) { |
| 633 | return DEFAULT_TRIGGER_MAX_DELAY; |
| 634 | } |
| 635 | return Math.max(time, MIN_TRIGGER_MAX_DELAY); |
| 636 | } |
| 637 | |
Matthew Williams | 900c67f | 2014-07-09 12:46:53 -0700 | [diff] [blame] | 638 | public boolean isPersisted() { |
| 639 | return job.isPersisted(); |
| 640 | } |
| 641 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 642 | public long getEarliestRunTime() { |
| 643 | return earliestRunTimeElapsedMillis; |
| 644 | } |
| 645 | |
| 646 | public long getLatestRunTimeElapsed() { |
| 647 | return latestRunTimeElapsedMillis; |
| 648 | } |
| 649 | |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 650 | public Pair<Long, Long> getPersistedUtcTimes() { |
| 651 | return mPersistedUtcTimes; |
| 652 | } |
| 653 | |
| 654 | public void clearPersistedUtcTimes() { |
| 655 | mPersistedUtcTimes = null; |
| 656 | } |
| 657 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 658 | boolean setChargingConstraintSatisfied(boolean state) { |
| 659 | return setConstraintSatisfied(CONSTRAINT_CHARGING, state); |
| 660 | } |
| 661 | |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 662 | boolean setBatteryNotLowConstraintSatisfied(boolean state) { |
| 663 | return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state); |
| 664 | } |
| 665 | |
Dianne Hackborn | 532ea26 | 2017-03-17 17:50:55 -0700 | [diff] [blame] | 666 | boolean setStorageNotLowConstraintSatisfied(boolean state) { |
| 667 | return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state); |
| 668 | } |
| 669 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 670 | boolean setTimingDelayConstraintSatisfied(boolean state) { |
| 671 | return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state); |
| 672 | } |
| 673 | |
| 674 | boolean setDeadlineConstraintSatisfied(boolean state) { |
| 675 | return setConstraintSatisfied(CONSTRAINT_DEADLINE, state); |
| 676 | } |
| 677 | |
| 678 | boolean setIdleConstraintSatisfied(boolean state) { |
| 679 | return setConstraintSatisfied(CONSTRAINT_IDLE, state); |
| 680 | } |
| 681 | |
Jeff Sharkey | f07c7b9 | 2016-04-22 09:50:16 -0600 | [diff] [blame] | 682 | boolean setConnectivityConstraintSatisfied(boolean state) { |
| 683 | return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state); |
| 684 | } |
| 685 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 686 | boolean setUnmeteredConstraintSatisfied(boolean state) { |
| 687 | return setConstraintSatisfied(CONSTRAINT_UNMETERED, state); |
| 688 | } |
| 689 | |
Christopher Tate | 60977f4 | 2017-04-13 13:48:46 -0700 | [diff] [blame] | 690 | boolean setMeteredConstraintSatisfied(boolean state) { |
| 691 | return setConstraintSatisfied(CONSTRAINT_METERED, state); |
| 692 | } |
| 693 | |
Jeff Sharkey | f07c7b9 | 2016-04-22 09:50:16 -0600 | [diff] [blame] | 694 | boolean setNotRoamingConstraintSatisfied(boolean state) { |
| 695 | return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state); |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 696 | } |
| 697 | |
| 698 | boolean setAppNotIdleConstraintSatisfied(boolean state) { |
| 699 | return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state); |
| 700 | } |
| 701 | |
| 702 | boolean setContentTriggerConstraintSatisfied(boolean state) { |
| 703 | return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state); |
| 704 | } |
| 705 | |
Dianne Hackborn | 7ab4025 | 2016-06-15 17:30:24 -0700 | [diff] [blame] | 706 | boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) { |
| 707 | dozeWhitelisted = whitelisted; |
Amith Yamasani | cb926fc | 2016-03-14 17:15:20 -0700 | [diff] [blame] | 708 | return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state); |
| 709 | } |
| 710 | |
Suprabh Shukla | 3ac1daa | 2017-07-14 12:15:27 -0700 | [diff] [blame] | 711 | boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) { |
| 712 | return setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state); |
| 713 | } |
| 714 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 715 | boolean setConstraintSatisfied(int constraint, boolean state) { |
| 716 | boolean old = (satisfiedConstraints&constraint) != 0; |
| 717 | if (old == state) { |
| 718 | return false; |
| 719 | } |
| 720 | satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0); |
| 721 | return true; |
| 722 | } |
| 723 | |
Dianne Hackborn | e9a988c | 2016-05-27 17:59:40 -0700 | [diff] [blame] | 724 | boolean isConstraintSatisfied(int constraint) { |
| 725 | return (satisfiedConstraints&constraint) != 0; |
| 726 | } |
| 727 | |
Dianne Hackborn | f9bac16 | 2017-04-20 17:17:48 -0700 | [diff] [blame] | 728 | boolean clearTrackingController(int which) { |
| 729 | if ((trackingControllers&which) != 0) { |
| 730 | trackingControllers &= ~which; |
| 731 | return true; |
| 732 | } |
| 733 | return false; |
| 734 | } |
| 735 | |
| 736 | void setTrackingController(int which) { |
| 737 | trackingControllers |= which; |
| 738 | } |
| 739 | |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 740 | public long getLastSuccessfulRunTime() { |
| 741 | return mLastSuccessfulRunTime; |
| 742 | } |
| 743 | |
| 744 | public long getLastFailedRunTime() { |
| 745 | return mLastFailedRunTime; |
| 746 | } |
| 747 | |
Dianne Hackborn | ef3aa6e | 2016-04-29 18:18:08 -0700 | [diff] [blame] | 748 | public boolean shouldDump(int filterUid) { |
| 749 | return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid |
| 750 | || UserHandle.getAppId(getSourceUid()) == filterUid; |
| 751 | } |
| 752 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 753 | /** |
Matthew Williams | 03a4da6 | 2014-09-10 17:32:18 -0700 | [diff] [blame] | 754 | * @return Whether or not this job is ready to run, based on its requirements. This is true if |
| 755 | * the constraints are satisfied <strong>or</strong> the deadline on the job has expired. |
Dianne Hackborn | 28d1b66 | 2017-04-21 14:17:23 -0700 | [diff] [blame] | 756 | * TODO: This function is called a *lot*. We should probably just have it check an |
| 757 | * already-computed boolean, which we updated whenever we see one of the states it depends |
| 758 | * on here change. |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 759 | */ |
Dianne Hackborn | d506b2b | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 760 | public boolean isReady() { |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 761 | // Deadline constraint trumps other constraints (except for periodic jobs where deadline |
Christopher Tate | 5d34605 | 2016-03-08 12:56:08 -0800 | [diff] [blame] | 762 | // is an implementation detail. A periodic job should only run if its constraints are |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 763 | // satisfied). |
Amith Yamasani | cb926fc | 2016-03-14 17:15:20 -0700 | [diff] [blame] | 764 | // AppNotIdle implicit constraint must be satisfied |
| 765 | // DeviceNotDozing implicit constraint must be satisfied |
Suprabh Shukla | 3ac1daa | 2017-07-14 12:15:27 -0700 | [diff] [blame] | 766 | // NotRestrictedInBackground implicit constraint must be satisfied |
Jeff Sharkey | 1b6519b | 2016-04-28 15:33:18 -0600 | [diff] [blame] | 767 | final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint() |
| 768 | && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0); |
| 769 | final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0; |
| 770 | final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0 |
| 771 | || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; |
Suprabh Shukla | 3ac1daa | 2017-07-14 12:15:27 -0700 | [diff] [blame] | 772 | final boolean notRestrictedInBg = |
| 773 | (satisfiedConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0; |
| 774 | return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing |
| 775 | && notRestrictedInBg; |
Matthew Williams | 03a4da6 | 2014-09-10 17:32:18 -0700 | [diff] [blame] | 776 | } |
| 777 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 778 | static final int CONSTRAINTS_OF_INTEREST = |
Dianne Hackborn | 532ea26 | 2017-03-17 17:50:55 -0700 | [diff] [blame] | 779 | CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW | |
| 780 | CONSTRAINT_TIMING_DELAY | |
Christopher Tate | 06f0852 | 2017-06-13 12:12:09 -0700 | [diff] [blame] | 781 | CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | |
| 782 | CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 783 | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER; |
| 784 | |
Christopher Tate | 5d34605 | 2016-03-08 12:56:08 -0800 | [diff] [blame] | 785 | // Soft override covers all non-"functional" constraints |
| 786 | static final int SOFT_OVERRIDE_CONSTRAINTS = |
Dianne Hackborn | 532ea26 | 2017-03-17 17:50:55 -0700 | [diff] [blame] | 787 | CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 788 | | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE; |
Christopher Tate | 5d34605 | 2016-03-08 12:56:08 -0800 | [diff] [blame] | 789 | |
Matthew Williams | 03a4da6 | 2014-09-10 17:32:18 -0700 | [diff] [blame] | 790 | /** |
| 791 | * @return Whether the constraints set on this job are satisfied. |
| 792 | */ |
Dianne Hackborn | d506b2b | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 793 | public boolean isConstraintsSatisfied() { |
Christopher Tate | 5d34605 | 2016-03-08 12:56:08 -0800 | [diff] [blame] | 794 | if (overrideState == OVERRIDE_FULL) { |
| 795 | // force override: the job is always runnable |
| 796 | return true; |
| 797 | } |
| 798 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 799 | final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST; |
Christopher Tate | 5d34605 | 2016-03-08 12:56:08 -0800 | [diff] [blame] | 800 | |
| 801 | int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST; |
| 802 | if (overrideState == OVERRIDE_SOFT) { |
| 803 | // override: pretend all 'soft' requirements are satisfied |
| 804 | sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS); |
| 805 | } |
| 806 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 807 | return (sat & req) == req; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 808 | } |
| 809 | |
| 810 | public boolean matches(int uid, int jobId) { |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 811 | return this.job.getId() == jobId && this.callingUid == uid; |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 812 | } |
| 813 | |
| 814 | @Override |
| 815 | public String toString() { |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 816 | StringBuilder sb = new StringBuilder(128); |
| 817 | sb.append("JobStatus{"); |
| 818 | sb.append(Integer.toHexString(System.identityHashCode(this))); |
| 819 | sb.append(" #"); |
| 820 | UserHandle.formatUid(sb, callingUid); |
| 821 | sb.append("/"); |
| 822 | sb.append(job.getId()); |
| 823 | sb.append(' '); |
| 824 | sb.append(batteryName); |
| 825 | sb.append(" u="); |
| 826 | sb.append(getUserId()); |
| 827 | sb.append(" s="); |
| 828 | sb.append(getSourceUid()); |
| 829 | if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME |
| 830 | || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 831 | long now = SystemClock.elapsedRealtime(); |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 832 | sb.append(" TIME="); |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 833 | formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now); |
| 834 | sb.append(":"); |
| 835 | formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now); |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 836 | } |
| 837 | if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) { |
| 838 | sb.append(" NET="); |
| 839 | sb.append(job.getNetworkType()); |
| 840 | } |
| 841 | if (job.isRequireCharging()) { |
| 842 | sb.append(" CHARGING"); |
| 843 | } |
| 844 | if (job.isRequireBatteryNotLow()) { |
| 845 | sb.append(" BATNOTLOW"); |
| 846 | } |
| 847 | if (job.isRequireStorageNotLow()) { |
| 848 | sb.append(" STORENOTLOW"); |
| 849 | } |
| 850 | if (job.isRequireDeviceIdle()) { |
| 851 | sb.append(" IDLE"); |
| 852 | } |
Christopher Tate | 616541d | 2017-07-26 14:27:38 -0700 | [diff] [blame] | 853 | if (job.isPeriodic()) { |
| 854 | sb.append(" PERIODIC"); |
| 855 | } |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 856 | if (job.isPersisted()) { |
| 857 | sb.append(" PERSISTED"); |
| 858 | } |
| 859 | if ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) == 0) { |
| 860 | sb.append(" WAIT:APP_NOT_IDLE"); |
| 861 | } |
| 862 | if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) { |
| 863 | sb.append(" WAIT:DEV_NOT_DOZING"); |
| 864 | } |
| 865 | if (job.getTriggerContentUris() != null) { |
| 866 | sb.append(" URIS="); |
| 867 | sb.append(Arrays.toString(job.getTriggerContentUris())); |
| 868 | } |
| 869 | if (numFailures != 0) { |
| 870 | sb.append(" failures="); |
| 871 | sb.append(numFailures); |
| 872 | } |
| 873 | if (isReady()) { |
| 874 | sb.append(" READY"); |
| 875 | } |
| 876 | sb.append("}"); |
| 877 | return sb.toString(); |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 878 | } |
Matthew Williams | 9ae3dbe | 2014-08-21 13:47:47 -0700 | [diff] [blame] | 879 | |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 880 | private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) { |
Matthew Williams | 9ae3dbe | 2014-08-21 13:47:47 -0700 | [diff] [blame] | 881 | if (runtime == defaultValue) { |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 882 | pw.print("none"); |
Matthew Williams | 9ae3dbe | 2014-08-21 13:47:47 -0700 | [diff] [blame] | 883 | } else { |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 884 | TimeUtils.formatDuration(runtime - now, pw); |
| 885 | } |
| 886 | } |
| 887 | |
| 888 | private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) { |
| 889 | if (runtime == defaultValue) { |
| 890 | sb.append("none"); |
| 891 | } else { |
| 892 | TimeUtils.formatDuration(runtime - now, sb); |
Matthew Williams | 9ae3dbe | 2014-08-21 13:47:47 -0700 | [diff] [blame] | 893 | } |
| 894 | } |
| 895 | |
| 896 | /** |
| 897 | * Convenience function to identify a job uniquely without pulling all the data that |
| 898 | * {@link #toString()} returns. |
| 899 | */ |
| 900 | public String toShortString() { |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 901 | StringBuilder sb = new StringBuilder(); |
| 902 | sb.append(Integer.toHexString(System.identityHashCode(this))); |
Dianne Hackborn | e9a988c | 2016-05-27 17:59:40 -0700 | [diff] [blame] | 903 | sb.append(" #"); |
| 904 | UserHandle.formatUid(sb, callingUid); |
| 905 | sb.append("/"); |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 906 | sb.append(job.getId()); |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 907 | sb.append(' '); |
Dianne Hackborn | e9a988c | 2016-05-27 17:59:40 -0700 | [diff] [blame] | 908 | sb.append(batteryName); |
| 909 | return sb.toString(); |
| 910 | } |
| 911 | |
| 912 | /** |
| 913 | * Convenience function to identify a job uniquely without pulling all the data that |
| 914 | * {@link #toString()} returns. |
| 915 | */ |
| 916 | public String toShortStringExceptUniqueId() { |
| 917 | StringBuilder sb = new StringBuilder(); |
| 918 | sb.append(Integer.toHexString(System.identityHashCode(this))); |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 919 | sb.append(' '); |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 920 | sb.append(batteryName); |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 921 | return sb.toString(); |
Matthew Williams | 9ae3dbe | 2014-08-21 13:47:47 -0700 | [diff] [blame] | 922 | } |
| 923 | |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 924 | void dumpConstraints(PrintWriter pw, int constraints) { |
| 925 | if ((constraints&CONSTRAINT_CHARGING) != 0) { |
| 926 | pw.print(" CHARGING"); |
| 927 | } |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 928 | if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) { |
| 929 | pw.print(" BATTERY_NOT_LOW"); |
| 930 | } |
Dianne Hackborn | 532ea26 | 2017-03-17 17:50:55 -0700 | [diff] [blame] | 931 | if ((constraints& CONSTRAINT_STORAGE_NOT_LOW) != 0) { |
| 932 | pw.print(" STORAGE_NOT_LOW"); |
| 933 | } |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 934 | if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) { |
| 935 | pw.print(" TIMING_DELAY"); |
| 936 | } |
| 937 | if ((constraints&CONSTRAINT_DEADLINE) != 0) { |
| 938 | pw.print(" DEADLINE"); |
| 939 | } |
| 940 | if ((constraints&CONSTRAINT_IDLE) != 0) { |
| 941 | pw.print(" IDLE"); |
| 942 | } |
Jeff Sharkey | f07c7b9 | 2016-04-22 09:50:16 -0600 | [diff] [blame] | 943 | if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) { |
| 944 | pw.print(" CONNECTIVITY"); |
| 945 | } |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 946 | if ((constraints&CONSTRAINT_UNMETERED) != 0) { |
| 947 | pw.print(" UNMETERED"); |
| 948 | } |
Jeff Sharkey | f07c7b9 | 2016-04-22 09:50:16 -0600 | [diff] [blame] | 949 | if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) { |
| 950 | pw.print(" NOT_ROAMING"); |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 951 | } |
Christopher Tate | 06f0852 | 2017-06-13 12:12:09 -0700 | [diff] [blame] | 952 | if ((constraints&CONSTRAINT_METERED) != 0) { |
| 953 | pw.print(" METERED"); |
| 954 | } |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 955 | if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) { |
| 956 | pw.print(" APP_NOT_IDLE"); |
| 957 | } |
| 958 | if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) { |
| 959 | pw.print(" CONTENT_TRIGGER"); |
| 960 | } |
Amith Yamasani | cb926fc | 2016-03-14 17:15:20 -0700 | [diff] [blame] | 961 | if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) { |
| 962 | pw.print(" DEVICE_NOT_DOZING"); |
| 963 | } |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 964 | } |
| 965 | |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 966 | private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) { |
| 967 | pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #"); |
Dianne Hackborn | 28d1b66 | 2017-04-21 14:17:23 -0700 | [diff] [blame] | 968 | pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount()); |
| 969 | pw.print("x "); pw.println(work.getIntent()); |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 970 | if (work.getGrants() != null) { |
| 971 | pw.print(prefix); pw.println(" URI grants:"); |
| 972 | ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " "); |
| 973 | } |
| 974 | } |
| 975 | |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 976 | // Dumpsys infrastructure |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 977 | public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) { |
Shreyas Basarge | 8e64e2e | 2016-02-12 15:49:31 +0000 | [diff] [blame] | 978 | pw.print(prefix); UserHandle.formatUid(pw, callingUid); |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 979 | pw.print(" tag="); pw.println(tag); |
Christopher Tate | f973a7b | 2014-08-29 12:54:08 -0700 | [diff] [blame] | 980 | pw.print(prefix); |
Shreyas Basarge | d8bf6b9 | 2016-02-02 23:45:14 +0000 | [diff] [blame] | 981 | pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid()); |
| 982 | pw.print(" user="); pw.print(getSourceUserId()); |
| 983 | pw.print(" pkg="); pw.println(getSourcePackageName()); |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 984 | if (full) { |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 985 | pw.print(prefix); pw.println("JobInfo:"); |
| 986 | pw.print(prefix); pw.print(" Service: "); |
| 987 | pw.println(job.getService().flattenToShortString()); |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 988 | if (job.isPeriodic()) { |
| 989 | pw.print(prefix); pw.print(" PERIODIC: interval="); |
| 990 | TimeUtils.formatDuration(job.getIntervalMillis(), pw); |
| 991 | pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw); |
| 992 | pw.println(); |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 993 | } |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 994 | if (job.isPersisted()) { |
| 995 | pw.print(prefix); pw.println(" PERSISTED"); |
| 996 | } |
| 997 | if (job.getPriority() != 0) { |
| 998 | pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority()); |
| 999 | } |
Jeff Sharkey | 1b6519b | 2016-04-28 15:33:18 -0600 | [diff] [blame] | 1000 | if (job.getFlags() != 0) { |
| 1001 | pw.print(prefix); pw.print(" Flags: "); |
| 1002 | pw.println(Integer.toHexString(job.getFlags())); |
| 1003 | } |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 1004 | pw.print(prefix); pw.print(" Requires: charging="); |
Dianne Hackborn | a06ec6a | 2017-02-13 10:08:42 -0800 | [diff] [blame] | 1005 | pw.print(job.isRequireCharging()); pw.print(" batteryNotLow="); |
| 1006 | pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle="); |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 1007 | pw.println(job.isRequireDeviceIdle()); |
| 1008 | if (job.getTriggerContentUris() != null) { |
| 1009 | pw.print(prefix); pw.println(" Trigger content URIs:"); |
| 1010 | for (int i = 0; i < job.getTriggerContentUris().length; i++) { |
| 1011 | JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i]; |
| 1012 | pw.print(prefix); pw.print(" "); |
| 1013 | pw.print(Integer.toHexString(trig.getFlags())); |
| 1014 | pw.print(' '); pw.println(trig.getUri()); |
| 1015 | } |
Dianne Hackborn | 8db0fc1 | 2016-04-12 13:48:25 -0700 | [diff] [blame] | 1016 | if (job.getTriggerContentUpdateDelay() >= 0) { |
| 1017 | pw.print(prefix); pw.print(" Trigger update delay: "); |
| 1018 | TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw); |
| 1019 | pw.println(); |
| 1020 | } |
| 1021 | if (job.getTriggerContentMaxDelay() >= 0) { |
| 1022 | pw.print(prefix); pw.print(" Trigger max delay: "); |
| 1023 | TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw); |
| 1024 | pw.println(); |
| 1025 | } |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 1026 | } |
Dianne Hackborn | a47223f | 2017-03-30 13:49:13 -0700 | [diff] [blame] | 1027 | if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) { |
| 1028 | pw.print(prefix); pw.print(" Extras: "); |
| 1029 | pw.println(job.getExtras().toShortString()); |
| 1030 | } |
| 1031 | if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) { |
| 1032 | pw.print(prefix); pw.print(" Transient extras: "); |
| 1033 | pw.println(job.getTransientExtras().toShortString()); |
| 1034 | } |
| 1035 | if (job.getClipData() != null) { |
| 1036 | pw.print(prefix); pw.print(" Clip data: "); |
| 1037 | StringBuilder b = new StringBuilder(128); |
| 1038 | job.getClipData().toShortString(b); |
| 1039 | pw.println(b); |
| 1040 | } |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 1041 | if (uriPerms != null) { |
| 1042 | pw.print(prefix); pw.println(" Granted URI permissions:"); |
| 1043 | uriPerms.dump(pw, prefix + " "); |
| 1044 | } |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 1045 | if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) { |
| 1046 | pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType()); |
| 1047 | } |
| 1048 | if (job.getMinLatencyMillis() != 0) { |
| 1049 | pw.print(prefix); pw.print(" Minimum latency: "); |
| 1050 | TimeUtils.formatDuration(job.getMinLatencyMillis(), pw); |
| 1051 | pw.println(); |
| 1052 | } |
| 1053 | if (job.getMaxExecutionDelayMillis() != 0) { |
| 1054 | pw.print(prefix); pw.print(" Max execution delay: "); |
| 1055 | TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw); |
| 1056 | pw.println(); |
| 1057 | } |
| 1058 | pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy()); |
| 1059 | pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw); |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 1060 | pw.println(); |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 1061 | if (job.hasEarlyConstraint()) { |
| 1062 | pw.print(prefix); pw.println(" Has early constraint"); |
| 1063 | } |
| 1064 | if (job.hasLateConstraint()) { |
| 1065 | pw.print(prefix); pw.println(" Has late constraint"); |
| 1066 | } |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 1067 | } |
Dianne Hackborn | b0001f6 | 2016-02-16 10:30:33 -0800 | [diff] [blame] | 1068 | pw.print(prefix); pw.print("Required constraints:"); |
| 1069 | dumpConstraints(pw, requiredConstraints); |
| 1070 | pw.println(); |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 1071 | if (full) { |
| 1072 | pw.print(prefix); pw.print("Satisfied constraints:"); |
| 1073 | dumpConstraints(pw, satisfiedConstraints); |
| 1074 | pw.println(); |
Jeff Sharkey | 1b6519b | 2016-04-28 15:33:18 -0600 | [diff] [blame] | 1075 | pw.print(prefix); pw.print("Unsatisfied constraints:"); |
| 1076 | dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints)); |
| 1077 | pw.println(); |
Dianne Hackborn | 7ab4025 | 2016-06-15 17:30:24 -0700 | [diff] [blame] | 1078 | if (dozeWhitelisted) { |
| 1079 | pw.print(prefix); pw.println("Doze whitelisted: true"); |
| 1080 | } |
Dianne Hackborn | 970510b | 2016-02-24 16:56:42 -0800 | [diff] [blame] | 1081 | } |
Dianne Hackborn | f9bac16 | 2017-04-20 17:17:48 -0700 | [diff] [blame] | 1082 | if (trackingControllers != 0) { |
| 1083 | pw.print(prefix); pw.print("Tracking:"); |
| 1084 | if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY"); |
| 1085 | if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY"); |
| 1086 | if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT"); |
| 1087 | if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE"); |
| 1088 | if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE"); |
| 1089 | if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME"); |
| 1090 | pw.println(); |
| 1091 | } |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 1092 | if (changedAuthorities != null) { |
| 1093 | pw.print(prefix); pw.println("Changed authorities:"); |
| 1094 | for (int i=0; i<changedAuthorities.size(); i++) { |
| 1095 | pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i)); |
| 1096 | } |
| 1097 | if (changedUris != null) { |
| 1098 | pw.print(prefix); pw.println("Changed URIs:"); |
| 1099 | for (int i=0; i<changedUris.size(); i++) { |
| 1100 | pw.print(prefix); pw.print(" "); pw.println(changedUris.valueAt(i)); |
| 1101 | } |
| 1102 | } |
| 1103 | } |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 1104 | if (pendingWork != null && pendingWork.size() > 0) { |
| 1105 | pw.print(prefix); pw.println("Pending work:"); |
| 1106 | for (int i = 0; i < pendingWork.size(); i++) { |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 1107 | dumpJobWorkItem(pw, prefix, pendingWork.get(i), i); |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 1108 | } |
| 1109 | } |
| 1110 | if (executingWork != null && executingWork.size() > 0) { |
| 1111 | pw.print(prefix); pw.println("Executing work:"); |
| 1112 | for (int i = 0; i < executingWork.size(); i++) { |
Dianne Hackborn | 342e603 | 2017-04-13 18:04:31 -0700 | [diff] [blame] | 1113 | dumpJobWorkItem(pw, prefix, executingWork.get(i), i); |
Dianne Hackborn | 7da13d7 | 2017-04-04 17:17:35 -0700 | [diff] [blame] | 1114 | } |
| 1115 | } |
Dianne Hackborn | bfc2331 | 2017-05-11 11:53:24 -0700 | [diff] [blame] | 1116 | pw.print(prefix); pw.print("Enqueue time: "); |
| 1117 | TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw); |
| 1118 | pw.println(); |
| 1119 | pw.print(prefix); pw.print("Run time: earliest="); |
| 1120 | formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis); |
| 1121 | pw.print(", latest="); |
| 1122 | formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis); |
| 1123 | pw.println(); |
Dianne Hackborn | 1a30bd9 | 2016-01-11 11:05:00 -0800 | [diff] [blame] | 1124 | if (numFailures != 0) { |
| 1125 | pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures); |
| 1126 | } |
Makoto Onuki | ab8a67f | 2017-06-20 12:20:34 -0700 | [diff] [blame] | 1127 | final Time t = new Time(); |
| 1128 | final String format = "%Y-%m-%d %H:%M:%S"; |
| 1129 | if (mLastSuccessfulRunTime != 0) { |
| 1130 | pw.print(prefix); pw.print("Last successful run: "); |
| 1131 | t.set(mLastSuccessfulRunTime); |
| 1132 | pw.println(t.format(format)); |
| 1133 | } |
| 1134 | if (mLastFailedRunTime != 0) { |
| 1135 | pw.print(prefix); pw.print("Last failed run: "); |
| 1136 | t.set(mLastFailedRunTime); |
| 1137 | pw.println(t.format(format)); |
| 1138 | } |
Christopher Tate | 7060b04 | 2014-06-09 19:50:00 -0700 | [diff] [blame] | 1139 | } |
| 1140 | } |