blob: bbee0ebd281b0165d4e0a586254ddae81045b944 [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
Matthew Williams6de79e22014-05-01 10:47:00 -070021import android.app.AlarmManager;
Christopher Tate2fcbe212015-12-09 16:00:37 -080022import android.app.AlarmManager.OnAlarmListener;
Matthew Williams6de79e22014-05-01 10:47:00 -070023import android.content.Context;
Dianne Hackborne9a988c2016-05-27 17:59:40 -070024import android.os.UserHandle;
25import android.os.WorkSource;
Matthew Williamseffacfa2014-06-05 20:56:40 -070026import android.util.Slog;
Dianne Hackborne9a988c2016-05-27 17:59:40 -070027import android.util.TimeUtils;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080028import android.util.proto.ProtoOutputStream;
Matthew Williams6de79e22014-05-01 10:47:00 -070029
Christopher Tate7060b042014-06-09 19:50:00 -070030import com.android.server.job.JobSchedulerService;
31import com.android.server.job.StateChangedListener;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080032import com.android.server.job.StateControllerProto;
Matthew Williams6de79e22014-05-01 10:47:00 -070033
Matthew Williamseffacfa2014-06-05 20:56:40 -070034import java.io.PrintWriter;
Matthew Williams6de79e22014-05-01 10:47:00 -070035import java.util.Iterator;
36import java.util.LinkedList;
37import java.util.List;
38import java.util.ListIterator;
39
40/**
Christopher Tate7060b042014-06-09 19:50:00 -070041 * This class sets an alarm for the next expiring job, and determines whether a job's minimum
Matthew Williams6de79e22014-05-01 10:47:00 -070042 * delay has been satisfied.
43 */
Dianne Hackborn6466c1c2017-06-13 10:33:19 -070044public final class TimeController extends StateController {
Christopher Tate7060b042014-06-09 19:50:00 -070045 private static final String TAG = "JobScheduler.Time";
Matthew Williams6de79e22014-05-01 10:47:00 -070046
Christopher Tate2fcbe212015-12-09 16:00:37 -080047 /** Deadline alarm tag for logging purposes */
Dianne Hackborne9a988c2016-05-27 17:59:40 -070048 private final String DEADLINE_TAG = "*job.deadline*";
Christopher Tate2fcbe212015-12-09 16:00:37 -080049 /** Delay alarm tag for logging purposes */
Dianne Hackborne9a988c2016-05-27 17:59:40 -070050 private final String DELAY_TAG = "*job.delay*";
Matthew Williams6de79e22014-05-01 10:47:00 -070051
Christopher Tate7060b042014-06-09 19:50:00 -070052 private long mNextJobExpiredElapsedMillis;
Matthew Williams6de79e22014-05-01 10:47:00 -070053 private long mNextDelayExpiredElapsedMillis;
54
55 private AlarmManager mAlarmService = null;
Christopher Tate7060b042014-06-09 19:50:00 -070056 /** List of tracked jobs, sorted asc. by deadline */
Dianne Hackbornf9bac162017-04-20 17:17:48 -070057 private final List<JobStatus> mTrackedJobs = new LinkedList<>();
Matthew Williams9b9244b62014-05-14 11:06:04 -070058 /** Singleton. */
59 private static TimeController mSingleton;
Matthew Williams6de79e22014-05-01 10:47:00 -070060
Christopher Tate7060b042014-06-09 19:50:00 -070061 public static synchronized TimeController get(JobSchedulerService jms) {
Matthew Williams9b9244b62014-05-14 11:06:04 -070062 if (mSingleton == null) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -080063 mSingleton = new TimeController(jms, jms.getContext(), jms.getLock());
Matthew Williams9b9244b62014-05-14 11:06:04 -070064 }
65 return mSingleton;
66 }
67
Dianne Hackborn33d31c52016-02-16 10:30:33 -080068 private TimeController(StateChangedListener stateChangedListener, Context context,
69 Object lock) {
70 super(stateChangedListener, context, lock);
Christopher Tate2fcbe212015-12-09 16:00:37 -080071
Christopher Tate7060b042014-06-09 19:50:00 -070072 mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
Matthew Williamseffacfa2014-06-05 20:56:40 -070073 mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
Matthew Williams6de79e22014-05-01 10:47:00 -070074 }
75
76 /**
Christopher Tate7060b042014-06-09 19:50:00 -070077 * 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 -070078 * list.
79 */
80 @Override
Dianne Hackbornb0001f62016-02-16 10:30:33 -080081 public void maybeStartTrackingJobLocked(JobStatus job, JobStatus lastJob) {
82 if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -070083 maybeStopTrackingJobLocked(job, null, false);
Dianne Hackbornf9bac162017-04-20 17:17:48 -070084
85 // First: check the constraints now, because if they are already satisfied
86 // then there is no need to track it. This gives us a fast path for a common
87 // pattern of having a job with a 0 deadline constraint ("run immediately").
88 // Unlike most controllers, once one of our constraints has been satisfied, it
89 // will never be unsatisfied (our time base can not go backwards).
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070090 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Dianne Hackbornf9bac162017-04-20 17:17:48 -070091 if (job.hasDeadlineConstraint() && evaluateDeadlineConstraint(job, nowElapsedMillis)) {
92 return;
93 } else if (job.hasTimingDelayConstraint() && evaluateTimingDelayConstraint(job,
94 nowElapsedMillis)) {
95 return;
96 }
97
Dianne Hackbornb0001f62016-02-16 10:30:33 -080098 boolean isInsert = false;
99 ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
100 while (it.hasPrevious()) {
101 JobStatus ts = it.previous();
102 if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
103 // Insert
104 isInsert = true;
105 break;
Matthew Williams6de79e22014-05-01 10:47:00 -0700106 }
107 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800108 if (isInsert) {
109 it.next();
110 }
111 it.add(job);
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700112 job.setTrackingController(JobStatus.TRACKING_TIME);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800113 maybeUpdateAlarmsLocked(
114 job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700115 job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE,
Adam Lesinskic746b382017-10-13 14:31:08 -0700116 new WorkSource(job.getSourceUid(), job.getSourcePackageName()));
Matthew Williams6de79e22014-05-01 10:47:00 -0700117 }
118 }
119
120 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700121 * 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 -0700122 * tracking was the one our alarms were based off of.
Matthew Williams6de79e22014-05-01 10:47:00 -0700123 */
124 @Override
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700125 public void maybeStopTrackingJobLocked(JobStatus job, JobStatus incomingJob,
126 boolean forUpdate) {
127 if (job.clearTrackingController(JobStatus.TRACKING_TIME)) {
128 if (mTrackedJobs.remove(job)) {
129 checkExpiredDelaysAndResetAlarm();
130 checkExpiredDeadlinesAndResetAlarm();
131 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700132 }
133 }
134
135 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700136 * Determines whether this controller can stop tracking the given job.
137 * The controller is no longer interested in a job once its time constraint is satisfied, and
138 * the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
Matthew Williams6de79e22014-05-01 10:47:00 -0700139 * back and forth.
140 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800141 private boolean canStopTrackingJobLocked(JobStatus job) {
Christopher Tate7060b042014-06-09 19:50:00 -0700142 return (!job.hasTimingDelayConstraint() ||
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800143 (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
Christopher Tate7060b042014-06-09 19:50:00 -0700144 (!job.hasDeadlineConstraint() ||
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800145 (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
Matthew Williams6de79e22014-05-01 10:47:00 -0700146 }
147
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800148 private void ensureAlarmServiceLocked() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700149 if (mAlarmService == null) {
150 mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
151 }
152 }
153
154 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700155 * Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
Matthew Williamseffacfa2014-06-05 20:56:40 -0700156 * if so, removing them from this list, and updating the alarm for the next expiry time.
Matthew Williams6de79e22014-05-01 10:47:00 -0700157 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800158 private void checkExpiredDeadlinesAndResetAlarm() {
159 synchronized (mLock) {
160 long nextExpiryTime = Long.MAX_VALUE;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700161 int nextExpiryUid = 0;
Adam Lesinskic746b382017-10-13 14:31:08 -0700162 String nextExpiryPackageName = null;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700163 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Matthew Williams6de79e22014-05-01 10:47:00 -0700164
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800165 Iterator<JobStatus> it = mTrackedJobs.iterator();
166 while (it.hasNext()) {
167 JobStatus job = it.next();
168 if (!job.hasDeadlineConstraint()) {
169 continue;
170 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700171
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700172 if (evaluateDeadlineConstraint(job, nowElapsedMillis)) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800173 mStateChangedListener.onRunJobNow(job);
174 it.remove();
175 } else { // Sorted by expiry time, so take the next one and stop.
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700176 nextExpiryTime = job.getLatestRunTimeElapsed();
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700177 nextExpiryUid = job.getSourceUid();
Adam Lesinskic746b382017-10-13 14:31:08 -0700178 nextExpiryPackageName = job.getSourcePackageName();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800179 break;
180 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700181 }
Adam Lesinskic746b382017-10-13 14:31:08 -0700182 setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryPackageName != null
183 ? new WorkSource(nextExpiryUid, nextExpiryPackageName)
184 : new WorkSource(nextExpiryUid));
Matthew Williams6de79e22014-05-01 10:47:00 -0700185 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700186 }
187
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700188 private boolean evaluateDeadlineConstraint(JobStatus job, long nowElapsedMillis) {
189 final long jobDeadline = job.getLatestRunTimeElapsed();
190
191 if (jobDeadline <= nowElapsedMillis) {
192 if (job.hasTimingDelayConstraint()) {
193 job.setTimingDelayConstraintSatisfied(true);
194 }
195 job.setDeadlineConstraintSatisfied(true);
196 return true;
197 }
198 return false;
199 }
200
Matthew Williams6de79e22014-05-01 10:47:00 -0700201 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700202 * Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
203 * tracked jobs and marks them as ready as appropriate.
Matthew Williams6de79e22014-05-01 10:47:00 -0700204 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800205 private void checkExpiredDelaysAndResetAlarm() {
206 synchronized (mLock) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700207 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800208 long nextDelayTime = Long.MAX_VALUE;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700209 int nextDelayUid = 0;
Adam Lesinskic746b382017-10-13 14:31:08 -0700210 String nextDelayPackageName = null;
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800211 boolean ready = false;
212 Iterator<JobStatus> it = mTrackedJobs.iterator();
213 while (it.hasNext()) {
214 final JobStatus job = it.next();
215 if (!job.hasTimingDelayConstraint()) {
216 continue;
Matthew Williams6de79e22014-05-01 10:47:00 -0700217 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700218 if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800219 if (canStopTrackingJobLocked(job)) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800220 it.remove();
221 }
222 if (job.isReady()) {
223 ready = true;
224 }
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700225 } else if (!job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)) {
226 // If this job still doesn't have its delay constraint satisfied,
227 // then see if it is the next upcoming delay time for the alarm.
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700228 final long jobDelayTime = job.getEarliestRunTime();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800229 if (nextDelayTime > jobDelayTime) {
230 nextDelayTime = jobDelayTime;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700231 nextDelayUid = job.getSourceUid();
Adam Lesinskic746b382017-10-13 14:31:08 -0700232 nextDelayPackageName = job.getSourcePackageName();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800233 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700234 }
235 }
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800236 if (ready) {
237 mStateChangedListener.onControllerStateChanged();
238 }
Adam Lesinskic746b382017-10-13 14:31:08 -0700239 setDelayExpiredAlarmLocked(nextDelayTime, nextDelayPackageName != null
240 ? new WorkSource(nextDelayUid, nextDelayPackageName)
241 : new WorkSource(nextDelayUid));
Matthew Williams6de79e22014-05-01 10:47:00 -0700242 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700243 }
244
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700245 private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) {
246 final long jobDelayTime = job.getEarliestRunTime();
247 if (jobDelayTime <= nowElapsedMillis) {
248 job.setTimingDelayConstraintSatisfied(true);
249 return true;
250 }
251 return false;
252 }
253
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700254 private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed,
Adam Lesinskic746b382017-10-13 14:31:08 -0700255 WorkSource ws) {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700256 if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
Adam Lesinskic746b382017-10-13 14:31:08 -0700257 setDelayExpiredAlarmLocked(delayExpiredElapsed, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700258 }
Christopher Tate7060b042014-06-09 19:50:00 -0700259 if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
Adam Lesinskic746b382017-10-13 14:31:08 -0700260 setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700261 }
262 }
263
264 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700265 * 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 -0700266 * delay will expire.
Shreyas Basarge4b7e339c2016-01-20 16:25:07 +0000267 * This alarm <b>will</b> wake up the phone.
Matthew Williamseffacfa2014-06-05 20:56:40 -0700268 */
Adam Lesinskic746b382017-10-13 14:31:08 -0700269 private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700270 alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700271 mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800272 updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700273 mNextDelayExpiredElapsedMillis, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700274 }
275
276 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700277 * 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 -0700278 * deadline will expire.
279 * This alarm <b>will</b> wake up the phone.
280 */
Adam Lesinskic746b382017-10-13 14:31:08 -0700281 private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700282 alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700283 mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800284 updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700285 mNextJobExpiredElapsedMillis, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700286 }
287
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700288 private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700289 final long earliestWakeupTimeElapsed = sElapsedRealtimeClock.millis();
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700290 if (proposedAlarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
291 return earliestWakeupTimeElapsed;
292 }
293 return proposedAlarmTimeElapsedMillis;
294 }
295
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800296 private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700297 long alarmTimeElapsed, WorkSource ws) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800298 ensureAlarmServiceLocked();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700299 if (alarmTimeElapsed == Long.MAX_VALUE) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800300 mAlarmService.cancel(listener);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700301 } else {
302 if (DEBUG) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800303 Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700304 }
Shreyas Basarge4b7e339c2016-01-20 16:25:07 +0000305 mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed,
Adam Lesinskic746b382017-10-13 14:31:08 -0700306 AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700307 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700308 }
309
Christopher Tate2fcbe212015-12-09 16:00:37 -0800310 // Job/delay expiration alarm handling
311
312 private final OnAlarmListener mDeadlineExpiredListener = new OnAlarmListener() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700313 @Override
Christopher Tate2fcbe212015-12-09 16:00:37 -0800314 public void onAlarm() {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700315 if (DEBUG) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800316 Slog.d(TAG, "Deadline-expired alarm fired");
Matthew Williamseffacfa2014-06-05 20:56:40 -0700317 }
Christopher Tate2fcbe212015-12-09 16:00:37 -0800318 checkExpiredDeadlinesAndResetAlarm();
319 }
320 };
321
322 private final OnAlarmListener mNextDelayExpiredListener = new OnAlarmListener() {
323 @Override
324 public void onAlarm() {
325 if (DEBUG) {
326 Slog.d(TAG, "Delay-expired alarm fired");
Matthew Williams6de79e22014-05-01 10:47:00 -0700327 }
Christopher Tate2fcbe212015-12-09 16:00:37 -0800328 checkExpiredDelaysAndResetAlarm();
Matthew Williams6de79e22014-05-01 10:47:00 -0700329 }
330 };
Matthew Williamseffacfa2014-06-05 20:56:40 -0700331
332 @Override
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700333 public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700334 final long nowElapsed = sElapsedRealtimeClock.millis();
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700335 pw.print("Alarms: now=");
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800336 pw.print(nowElapsed);
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700337 pw.println();
338 pw.print("Next delay alarm in ");
339 TimeUtils.formatDuration(mNextDelayExpiredElapsedMillis, nowElapsed, pw);
340 pw.println();
341 pw.print("Next deadline alarm in ");
342 TimeUtils.formatDuration(mNextJobExpiredElapsedMillis, nowElapsed, pw);
343 pw.println();
344 pw.print("Tracking ");
345 pw.print(mTrackedJobs.size());
346 pw.println(":");
Christopher Tate7060b042014-06-09 19:50:00 -0700347 for (JobStatus ts : mTrackedJobs) {
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700348 if (!ts.shouldDump(filterUid)) {
349 continue;
350 }
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700351 pw.print(" #");
352 ts.printUniqueId(pw);
353 pw.print(" from ");
354 UserHandle.formatUid(pw, ts.getSourceUid());
355 pw.print(": Delay=");
356 if (ts.hasTimingDelayConstraint()) {
357 TimeUtils.formatDuration(ts.getEarliestRunTime(), nowElapsed, pw);
358 } else {
359 pw.print("N/A");
360 }
361 pw.print(", Deadline=");
362 if (ts.hasDeadlineConstraint()) {
363 TimeUtils.formatDuration(ts.getLatestRunTimeElapsed(), nowElapsed, pw);
364 } else {
365 pw.print("N/A");
366 }
367 pw.println();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700368 }
369 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800370
371 @Override
372 public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
373 final long token = proto.start(fieldId);
374 final long mToken = proto.start(StateControllerProto.TIME);
375
376 final long nowElapsed = sElapsedRealtimeClock.millis();
377 proto.write(StateControllerProto.TimeController.NOW_ELAPSED_REALTIME, nowElapsed);
378 proto.write(StateControllerProto.TimeController.TIME_UNTIL_NEXT_DELAY_ALARM_MS,
379 mNextDelayExpiredElapsedMillis - nowElapsed);
380 proto.write(StateControllerProto.TimeController.TIME_UNTIL_NEXT_DEADLINE_ALARM_MS,
381 mNextJobExpiredElapsedMillis - nowElapsed);
382
383 for (JobStatus ts : mTrackedJobs) {
384 if (!ts.shouldDump(filterUid)) {
385 continue;
386 }
387 final long tsToken = proto.start(StateControllerProto.TimeController.TRACKED_JOBS);
388 ts.writeToShortProto(proto, StateControllerProto.TimeController.TrackedJob.INFO);
389
390 proto.write(StateControllerProto.TimeController.TrackedJob.HAS_TIMING_DELAY_CONSTRAINT,
391 ts.hasTimingDelayConstraint());
392 proto.write(StateControllerProto.TimeController.TrackedJob.DELAY_TIME_REMAINING_MS,
393 ts.getEarliestRunTime() - nowElapsed);
394
395 proto.write(StateControllerProto.TimeController.TrackedJob.HAS_DEADLINE_CONSTRAINT,
396 ts.hasDeadlineConstraint());
397 proto.write(StateControllerProto.TimeController.TrackedJob.TIME_REMAINING_UNTIL_DEADLINE_MS,
398 ts.getLatestRunTimeElapsed() - nowElapsed);
399
400 proto.end(tsToken);
401 }
402
403 proto.end(mToken);
404 proto.end(token);
405 }
406}