blob: fa48b5e974f6e4217f38e3b158b6cacac1d0ab84 [file] [log] [blame]
Matthew Williams6de79e22014-05-01 10:47: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
Christopher Tate7060b042014-06-09 19:50:00 -070017package com.android.server.job.controllers;
Matthew Williams6de79e22014-05-01 10:47:00 -070018
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070019import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
20
Narayan Kamath8d828252018-01-11 15:22:37 +000021import android.annotation.Nullable;
Matthew Williams6de79e22014-05-01 10:47:00 -070022import android.app.AlarmManager;
Christopher Tate2fcbe212015-12-09 16:00:37 -080023import android.app.AlarmManager.OnAlarmListener;
Matthew Williams6de79e22014-05-01 10:47:00 -070024import android.content.Context;
Narayan Kamath8d828252018-01-11 15:22:37 +000025import android.os.Process;
Dianne Hackborne9a988c2016-05-27 17:59:40 -070026import android.os.UserHandle;
27import android.os.WorkSource;
Jeff Sharkey01bb5302018-02-21 20:12:40 -070028import android.util.Log;
Matthew Williamseffacfa2014-06-05 20:56:40 -070029import android.util.Slog;
Dianne Hackborne9a988c2016-05-27 17:59:40 -070030import android.util.TimeUtils;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080031import android.util.proto.ProtoOutputStream;
Matthew Williams6de79e22014-05-01 10:47:00 -070032
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -070033import com.android.internal.util.IndentingPrintWriter;
Christopher Tate7060b042014-06-09 19:50:00 -070034import com.android.server.job.JobSchedulerService;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080035import com.android.server.job.StateControllerProto;
Matthew Williams6de79e22014-05-01 10:47:00 -070036
37import java.util.Iterator;
38import java.util.LinkedList;
39import java.util.List;
40import java.util.ListIterator;
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -070041import java.util.function.Predicate;
Matthew Williams6de79e22014-05-01 10:47:00 -070042
43/**
Christopher Tate7060b042014-06-09 19:50:00 -070044 * This class sets an alarm for the next expiring job, and determines whether a job's minimum
Matthew Williams6de79e22014-05-01 10:47:00 -070045 * delay has been satisfied.
46 */
Dianne Hackborn6466c1c2017-06-13 10:33:19 -070047public final class TimeController extends StateController {
Christopher Tate7060b042014-06-09 19:50:00 -070048 private static final String TAG = "JobScheduler.Time";
Jeff Sharkey01bb5302018-02-21 20:12:40 -070049 private static final boolean DEBUG = JobSchedulerService.DEBUG
50 || Log.isLoggable(TAG, Log.DEBUG);
Matthew Williams6de79e22014-05-01 10:47:00 -070051
Christopher Tate2fcbe212015-12-09 16:00:37 -080052 /** Deadline alarm tag for logging purposes */
Dianne Hackborne9a988c2016-05-27 17:59:40 -070053 private final String DEADLINE_TAG = "*job.deadline*";
Christopher Tate2fcbe212015-12-09 16:00:37 -080054 /** Delay alarm tag for logging purposes */
Dianne Hackborne9a988c2016-05-27 17:59:40 -070055 private final String DELAY_TAG = "*job.delay*";
Matthew Williams6de79e22014-05-01 10:47:00 -070056
Christopher Tate7060b042014-06-09 19:50:00 -070057 private long mNextJobExpiredElapsedMillis;
Matthew Williams6de79e22014-05-01 10:47:00 -070058 private long mNextDelayExpiredElapsedMillis;
59
Narayan Kamath8d828252018-01-11 15:22:37 +000060 private final boolean mChainedAttributionEnabled;
61
Matthew Williams6de79e22014-05-01 10:47:00 -070062 private AlarmManager mAlarmService = null;
Christopher Tate7060b042014-06-09 19:50:00 -070063 /** List of tracked jobs, sorted asc. by deadline */
Dianne Hackbornf9bac162017-04-20 17:17:48 -070064 private final List<JobStatus> mTrackedJobs = new LinkedList<>();
Matthew Williams6de79e22014-05-01 10:47:00 -070065
Jeff Sharkeyac2e8ef2018-02-22 16:06:44 -070066 public TimeController(JobSchedulerService service) {
67 super(service);
Christopher Tate2fcbe212015-12-09 16:00:37 -080068
Christopher Tate7060b042014-06-09 19:50:00 -070069 mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
Matthew Williamseffacfa2014-06-05 20:56:40 -070070 mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
Jeff Sharkeyac2e8ef2018-02-22 16:06:44 -070071 mChainedAttributionEnabled = WorkSource.isChainedBatteryAttributionEnabled(mContext);
Matthew Williams6de79e22014-05-01 10:47:00 -070072 }
73
74 /**
Christopher Tate7060b042014-06-09 19:50:00 -070075 * Check if the job has a timing constraint, and if so determine where to insert it in our
Matthew Williams6de79e22014-05-01 10:47:00 -070076 * list.
77 */
78 @Override
Dianne Hackbornb0001f62016-02-16 10:30:33 -080079 public void maybeStartTrackingJobLocked(JobStatus job, JobStatus lastJob) {
80 if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -070081 maybeStopTrackingJobLocked(job, null, false);
Dianne Hackbornf9bac162017-04-20 17:17:48 -070082
83 // First: check the constraints now, because if they are already satisfied
84 // then there is no need to track it. This gives us a fast path for a common
85 // pattern of having a job with a 0 deadline constraint ("run immediately").
86 // Unlike most controllers, once one of our constraints has been satisfied, it
87 // will never be unsatisfied (our time base can not go backwards).
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070088 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Dianne Hackbornf9bac162017-04-20 17:17:48 -070089 if (job.hasDeadlineConstraint() && evaluateDeadlineConstraint(job, nowElapsedMillis)) {
90 return;
91 } else if (job.hasTimingDelayConstraint() && evaluateTimingDelayConstraint(job,
92 nowElapsedMillis)) {
93 return;
94 }
95
Dianne Hackbornb0001f62016-02-16 10:30:33 -080096 boolean isInsert = false;
97 ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
98 while (it.hasPrevious()) {
99 JobStatus ts = it.previous();
100 if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
101 // Insert
102 isInsert = true;
103 break;
Matthew Williams6de79e22014-05-01 10:47:00 -0700104 }
105 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800106 if (isInsert) {
107 it.next();
108 }
109 it.add(job);
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700110 job.setTrackingController(JobStatus.TRACKING_TIME);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800111 maybeUpdateAlarmsLocked(
112 job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700113 job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE,
Narayan Kamath8d828252018-01-11 15:22:37 +0000114 deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
Matthew Williams6de79e22014-05-01 10:47:00 -0700115 }
116 }
117
118 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700119 * When we stop tracking a job, we only need to update our alarms if the job we're no longer
Matthew Williamseffacfa2014-06-05 20:56:40 -0700120 * tracking was the one our alarms were based off of.
Matthew Williams6de79e22014-05-01 10:47:00 -0700121 */
122 @Override
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700123 public void maybeStopTrackingJobLocked(JobStatus job, JobStatus incomingJob,
124 boolean forUpdate) {
125 if (job.clearTrackingController(JobStatus.TRACKING_TIME)) {
126 if (mTrackedJobs.remove(job)) {
127 checkExpiredDelaysAndResetAlarm();
128 checkExpiredDeadlinesAndResetAlarm();
129 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700130 }
131 }
132
133 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700134 * Determines whether this controller can stop tracking the given job.
135 * The controller is no longer interested in a job once its time constraint is satisfied, and
136 * the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
Matthew Williams6de79e22014-05-01 10:47:00 -0700137 * back and forth.
138 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800139 private boolean canStopTrackingJobLocked(JobStatus job) {
Christopher Tate7060b042014-06-09 19:50:00 -0700140 return (!job.hasTimingDelayConstraint() ||
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800141 (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
Christopher Tate7060b042014-06-09 19:50:00 -0700142 (!job.hasDeadlineConstraint() ||
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800143 (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
Matthew Williams6de79e22014-05-01 10:47:00 -0700144 }
145
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800146 private void ensureAlarmServiceLocked() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700147 if (mAlarmService == null) {
148 mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
149 }
150 }
151
152 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700153 * Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
Matthew Williamseffacfa2014-06-05 20:56:40 -0700154 * if so, removing them from this list, and updating the alarm for the next expiry time.
Matthew Williams6de79e22014-05-01 10:47:00 -0700155 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800156 private void checkExpiredDeadlinesAndResetAlarm() {
157 synchronized (mLock) {
158 long nextExpiryTime = Long.MAX_VALUE;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700159 int nextExpiryUid = 0;
Adam Lesinskic746b382017-10-13 14:31:08 -0700160 String nextExpiryPackageName = null;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700161 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Matthew Williams6de79e22014-05-01 10:47:00 -0700162
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800163 Iterator<JobStatus> it = mTrackedJobs.iterator();
164 while (it.hasNext()) {
165 JobStatus job = it.next();
166 if (!job.hasDeadlineConstraint()) {
167 continue;
168 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700169
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700170 if (evaluateDeadlineConstraint(job, nowElapsedMillis)) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800171 mStateChangedListener.onRunJobNow(job);
172 it.remove();
173 } else { // Sorted by expiry time, so take the next one and stop.
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700174 nextExpiryTime = job.getLatestRunTimeElapsed();
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700175 nextExpiryUid = job.getSourceUid();
Adam Lesinskic746b382017-10-13 14:31:08 -0700176 nextExpiryPackageName = job.getSourcePackageName();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800177 break;
178 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700179 }
Narayan Kamath8d828252018-01-11 15:22:37 +0000180 setDeadlineExpiredAlarmLocked(nextExpiryTime,
181 deriveWorkSource(nextExpiryUid, nextExpiryPackageName));
Matthew Williams6de79e22014-05-01 10:47:00 -0700182 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700183 }
184
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700185 private boolean evaluateDeadlineConstraint(JobStatus job, long nowElapsedMillis) {
186 final long jobDeadline = job.getLatestRunTimeElapsed();
187
188 if (jobDeadline <= nowElapsedMillis) {
189 if (job.hasTimingDelayConstraint()) {
190 job.setTimingDelayConstraintSatisfied(true);
191 }
192 job.setDeadlineConstraintSatisfied(true);
193 return true;
194 }
195 return false;
196 }
197
Matthew Williams6de79e22014-05-01 10:47:00 -0700198 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700199 * Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
200 * tracked jobs and marks them as ready as appropriate.
Matthew Williams6de79e22014-05-01 10:47:00 -0700201 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800202 private void checkExpiredDelaysAndResetAlarm() {
203 synchronized (mLock) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700204 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800205 long nextDelayTime = Long.MAX_VALUE;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700206 int nextDelayUid = 0;
Adam Lesinskic746b382017-10-13 14:31:08 -0700207 String nextDelayPackageName = null;
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800208 boolean ready = false;
209 Iterator<JobStatus> it = mTrackedJobs.iterator();
210 while (it.hasNext()) {
211 final JobStatus job = it.next();
212 if (!job.hasTimingDelayConstraint()) {
213 continue;
Matthew Williams6de79e22014-05-01 10:47:00 -0700214 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700215 if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800216 if (canStopTrackingJobLocked(job)) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800217 it.remove();
218 }
219 if (job.isReady()) {
220 ready = true;
221 }
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700222 } else if (!job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)) {
223 // If this job still doesn't have its delay constraint satisfied,
224 // then see if it is the next upcoming delay time for the alarm.
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700225 final long jobDelayTime = job.getEarliestRunTime();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800226 if (nextDelayTime > jobDelayTime) {
227 nextDelayTime = jobDelayTime;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700228 nextDelayUid = job.getSourceUid();
Adam Lesinskic746b382017-10-13 14:31:08 -0700229 nextDelayPackageName = job.getSourcePackageName();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800230 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700231 }
232 }
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800233 if (ready) {
234 mStateChangedListener.onControllerStateChanged();
235 }
Narayan Kamath8d828252018-01-11 15:22:37 +0000236 setDelayExpiredAlarmLocked(nextDelayTime,
237 deriveWorkSource(nextDelayUid, nextDelayPackageName));
238 }
239 }
240
241 private WorkSource deriveWorkSource(int uid, @Nullable String packageName) {
242 if (mChainedAttributionEnabled) {
243 WorkSource ws = new WorkSource();
244 ws.createWorkChain()
245 .addNode(uid, packageName)
246 .addNode(Process.SYSTEM_UID, "JobScheduler");
247 return ws;
248 } else {
249 return packageName == null ? new WorkSource(uid) : new WorkSource(uid, packageName);
Matthew Williams6de79e22014-05-01 10:47:00 -0700250 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700251 }
252
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700253 private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) {
254 final long jobDelayTime = job.getEarliestRunTime();
255 if (jobDelayTime <= nowElapsedMillis) {
256 job.setTimingDelayConstraintSatisfied(true);
257 return true;
258 }
259 return false;
260 }
261
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700262 private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed,
Adam Lesinskic746b382017-10-13 14:31:08 -0700263 WorkSource ws) {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700264 if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
Adam Lesinskic746b382017-10-13 14:31:08 -0700265 setDelayExpiredAlarmLocked(delayExpiredElapsed, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700266 }
Christopher Tate7060b042014-06-09 19:50:00 -0700267 if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
Adam Lesinskic746b382017-10-13 14:31:08 -0700268 setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700269 }
270 }
271
272 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700273 * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
Matthew Williamseffacfa2014-06-05 20:56:40 -0700274 * delay will expire.
Shreyas Basarge4b7e339c2016-01-20 16:25:07 +0000275 * This alarm <b>will</b> wake up the phone.
Matthew Williamseffacfa2014-06-05 20:56:40 -0700276 */
Adam Lesinskic746b382017-10-13 14:31:08 -0700277 private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700278 alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700279 mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800280 updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700281 mNextDelayExpiredElapsedMillis, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700282 }
283
284 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700285 * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
Matthew Williamseffacfa2014-06-05 20:56:40 -0700286 * deadline will expire.
287 * This alarm <b>will</b> wake up the phone.
288 */
Adam Lesinskic746b382017-10-13 14:31:08 -0700289 private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700290 alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700291 mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800292 updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700293 mNextJobExpiredElapsedMillis, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700294 }
295
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700296 private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700297 final long earliestWakeupTimeElapsed = sElapsedRealtimeClock.millis();
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700298 if (proposedAlarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
299 return earliestWakeupTimeElapsed;
300 }
301 return proposedAlarmTimeElapsedMillis;
302 }
303
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800304 private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700305 long alarmTimeElapsed, WorkSource ws) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800306 ensureAlarmServiceLocked();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700307 if (alarmTimeElapsed == Long.MAX_VALUE) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800308 mAlarmService.cancel(listener);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700309 } else {
310 if (DEBUG) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800311 Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700312 }
Shreyas Basarge4b7e339c2016-01-20 16:25:07 +0000313 mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed,
Adam Lesinskic746b382017-10-13 14:31:08 -0700314 AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700315 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700316 }
317
Christopher Tate2fcbe212015-12-09 16:00:37 -0800318 // Job/delay expiration alarm handling
319
320 private final OnAlarmListener mDeadlineExpiredListener = new OnAlarmListener() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700321 @Override
Christopher Tate2fcbe212015-12-09 16:00:37 -0800322 public void onAlarm() {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700323 if (DEBUG) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800324 Slog.d(TAG, "Deadline-expired alarm fired");
Matthew Williamseffacfa2014-06-05 20:56:40 -0700325 }
Christopher Tate2fcbe212015-12-09 16:00:37 -0800326 checkExpiredDeadlinesAndResetAlarm();
327 }
328 };
329
330 private final OnAlarmListener mNextDelayExpiredListener = new OnAlarmListener() {
331 @Override
332 public void onAlarm() {
333 if (DEBUG) {
334 Slog.d(TAG, "Delay-expired alarm fired");
Matthew Williams6de79e22014-05-01 10:47:00 -0700335 }
Christopher Tate2fcbe212015-12-09 16:00:37 -0800336 checkExpiredDelaysAndResetAlarm();
Matthew Williams6de79e22014-05-01 10:47:00 -0700337 }
338 };
Matthew Williamseffacfa2014-06-05 20:56:40 -0700339
340 @Override
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -0700341 public void dumpControllerStateLocked(IndentingPrintWriter pw,
342 Predicate<JobStatus> predicate) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700343 final long nowElapsed = sElapsedRealtimeClock.millis();
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -0700344 pw.println("Elapsed clock: " + nowElapsed);
345
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700346 pw.print("Next delay alarm in ");
347 TimeUtils.formatDuration(mNextDelayExpiredElapsedMillis, nowElapsed, pw);
348 pw.println();
349 pw.print("Next deadline alarm in ");
350 TimeUtils.formatDuration(mNextJobExpiredElapsedMillis, nowElapsed, pw);
351 pw.println();
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -0700352 pw.println();
353
Christopher Tate7060b042014-06-09 19:50:00 -0700354 for (JobStatus ts : mTrackedJobs) {
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -0700355 if (!predicate.test(ts)) {
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700356 continue;
357 }
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -0700358 pw.print("#");
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700359 ts.printUniqueId(pw);
360 pw.print(" from ");
361 UserHandle.formatUid(pw, ts.getSourceUid());
362 pw.print(": Delay=");
363 if (ts.hasTimingDelayConstraint()) {
364 TimeUtils.formatDuration(ts.getEarliestRunTime(), nowElapsed, pw);
365 } else {
366 pw.print("N/A");
367 }
368 pw.print(", Deadline=");
369 if (ts.hasDeadlineConstraint()) {
370 TimeUtils.formatDuration(ts.getLatestRunTimeElapsed(), nowElapsed, pw);
371 } else {
372 pw.print("N/A");
373 }
374 pw.println();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700375 }
376 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800377
378 @Override
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -0700379 public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
380 Predicate<JobStatus> predicate) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800381 final long token = proto.start(fieldId);
382 final long mToken = proto.start(StateControllerProto.TIME);
383
384 final long nowElapsed = sElapsedRealtimeClock.millis();
385 proto.write(StateControllerProto.TimeController.NOW_ELAPSED_REALTIME, nowElapsed);
386 proto.write(StateControllerProto.TimeController.TIME_UNTIL_NEXT_DELAY_ALARM_MS,
387 mNextDelayExpiredElapsedMillis - nowElapsed);
388 proto.write(StateControllerProto.TimeController.TIME_UNTIL_NEXT_DEADLINE_ALARM_MS,
389 mNextJobExpiredElapsedMillis - nowElapsed);
390
391 for (JobStatus ts : mTrackedJobs) {
Jeff Sharkeyfee8c7b2018-02-21 22:18:45 -0700392 if (!predicate.test(ts)) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800393 continue;
394 }
395 final long tsToken = proto.start(StateControllerProto.TimeController.TRACKED_JOBS);
396 ts.writeToShortProto(proto, StateControllerProto.TimeController.TrackedJob.INFO);
397
398 proto.write(StateControllerProto.TimeController.TrackedJob.HAS_TIMING_DELAY_CONSTRAINT,
399 ts.hasTimingDelayConstraint());
400 proto.write(StateControllerProto.TimeController.TrackedJob.DELAY_TIME_REMAINING_MS,
401 ts.getEarliestRunTime() - nowElapsed);
402
403 proto.write(StateControllerProto.TimeController.TrackedJob.HAS_DEADLINE_CONSTRAINT,
404 ts.hasDeadlineConstraint());
405 proto.write(StateControllerProto.TimeController.TrackedJob.TIME_REMAINING_UNTIL_DEADLINE_MS,
406 ts.getLatestRunTimeElapsed() - nowElapsed);
407
408 proto.end(tsToken);
409 }
410
411 proto.end(mToken);
412 proto.end(token);
413 }
414}