blob: a91f5a46409c9e0453de95dbd3b4736cb2c6ac44 [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;
Matthew Williamseffacfa2014-06-05 20:56:40 -070028import android.util.Slog;
Dianne Hackborne9a988c2016-05-27 17:59:40 -070029import android.util.TimeUtils;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080030import android.util.proto.ProtoOutputStream;
Matthew Williams6de79e22014-05-01 10:47:00 -070031
Christopher Tate7060b042014-06-09 19:50:00 -070032import com.android.server.job.JobSchedulerService;
33import com.android.server.job.StateChangedListener;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080034import com.android.server.job.StateControllerProto;
Matthew Williams6de79e22014-05-01 10:47:00 -070035
Matthew Williamseffacfa2014-06-05 20:56:40 -070036import java.io.PrintWriter;
Matthew Williams6de79e22014-05-01 10:47:00 -070037import java.util.Iterator;
38import java.util.LinkedList;
39import java.util.List;
40import java.util.ListIterator;
41
42/**
Christopher Tate7060b042014-06-09 19:50:00 -070043 * This class sets an alarm for the next expiring job, and determines whether a job's minimum
Matthew Williams6de79e22014-05-01 10:47:00 -070044 * delay has been satisfied.
45 */
Dianne Hackborn6466c1c2017-06-13 10:33:19 -070046public final class TimeController extends StateController {
Christopher Tate7060b042014-06-09 19:50:00 -070047 private static final String TAG = "JobScheduler.Time";
Matthew Williams6de79e22014-05-01 10:47:00 -070048
Christopher Tate2fcbe212015-12-09 16:00:37 -080049 /** Deadline alarm tag for logging purposes */
Dianne Hackborne9a988c2016-05-27 17:59:40 -070050 private final String DEADLINE_TAG = "*job.deadline*";
Christopher Tate2fcbe212015-12-09 16:00:37 -080051 /** Delay alarm tag for logging purposes */
Dianne Hackborne9a988c2016-05-27 17:59:40 -070052 private final String DELAY_TAG = "*job.delay*";
Matthew Williams6de79e22014-05-01 10:47:00 -070053
Christopher Tate7060b042014-06-09 19:50:00 -070054 private long mNextJobExpiredElapsedMillis;
Matthew Williams6de79e22014-05-01 10:47:00 -070055 private long mNextDelayExpiredElapsedMillis;
56
Narayan Kamath8d828252018-01-11 15:22:37 +000057 private final boolean mChainedAttributionEnabled;
58
Matthew Williams6de79e22014-05-01 10:47:00 -070059 private AlarmManager mAlarmService = null;
Christopher Tate7060b042014-06-09 19:50:00 -070060 /** List of tracked jobs, sorted asc. by deadline */
Dianne Hackbornf9bac162017-04-20 17:17:48 -070061 private final List<JobStatus> mTrackedJobs = new LinkedList<>();
Matthew Williams9b9244b62014-05-14 11:06:04 -070062 /** Singleton. */
63 private static TimeController mSingleton;
Matthew Williams6de79e22014-05-01 10:47:00 -070064
Christopher Tate7060b042014-06-09 19:50:00 -070065 public static synchronized TimeController get(JobSchedulerService jms) {
Matthew Williams9b9244b62014-05-14 11:06:04 -070066 if (mSingleton == null) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -080067 mSingleton = new TimeController(jms, jms.getContext(), jms.getLock());
Matthew Williams9b9244b62014-05-14 11:06:04 -070068 }
69 return mSingleton;
70 }
71
Dianne Hackborn33d31c52016-02-16 10:30:33 -080072 private TimeController(StateChangedListener stateChangedListener, Context context,
73 Object lock) {
74 super(stateChangedListener, context, lock);
Christopher Tate2fcbe212015-12-09 16:00:37 -080075
Christopher Tate7060b042014-06-09 19:50:00 -070076 mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
Matthew Williamseffacfa2014-06-05 20:56:40 -070077 mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
Narayan Kamath8d828252018-01-11 15:22:37 +000078 mChainedAttributionEnabled = WorkSource.isChainedBatteryAttributionEnabled(context);
Matthew Williams6de79e22014-05-01 10:47:00 -070079 }
80
81 /**
Christopher Tate7060b042014-06-09 19:50:00 -070082 * 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 -070083 * list.
84 */
85 @Override
Dianne Hackbornb0001f62016-02-16 10:30:33 -080086 public void maybeStartTrackingJobLocked(JobStatus job, JobStatus lastJob) {
87 if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -070088 maybeStopTrackingJobLocked(job, null, false);
Dianne Hackbornf9bac162017-04-20 17:17:48 -070089
90 // First: check the constraints now, because if they are already satisfied
91 // then there is no need to track it. This gives us a fast path for a common
92 // pattern of having a job with a 0 deadline constraint ("run immediately").
93 // Unlike most controllers, once one of our constraints has been satisfied, it
94 // will never be unsatisfied (our time base can not go backwards).
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070095 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Dianne Hackbornf9bac162017-04-20 17:17:48 -070096 if (job.hasDeadlineConstraint() && evaluateDeadlineConstraint(job, nowElapsedMillis)) {
97 return;
98 } else if (job.hasTimingDelayConstraint() && evaluateTimingDelayConstraint(job,
99 nowElapsedMillis)) {
100 return;
101 }
102
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800103 boolean isInsert = false;
104 ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
105 while (it.hasPrevious()) {
106 JobStatus ts = it.previous();
107 if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
108 // Insert
109 isInsert = true;
110 break;
Matthew Williams6de79e22014-05-01 10:47:00 -0700111 }
112 }
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800113 if (isInsert) {
114 it.next();
115 }
116 it.add(job);
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700117 job.setTrackingController(JobStatus.TRACKING_TIME);
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800118 maybeUpdateAlarmsLocked(
119 job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700120 job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE,
Narayan Kamath8d828252018-01-11 15:22:37 +0000121 deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
Matthew Williams6de79e22014-05-01 10:47:00 -0700122 }
123 }
124
125 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700126 * 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 -0700127 * tracking was the one our alarms were based off of.
Matthew Williams6de79e22014-05-01 10:47:00 -0700128 */
129 @Override
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700130 public void maybeStopTrackingJobLocked(JobStatus job, JobStatus incomingJob,
131 boolean forUpdate) {
132 if (job.clearTrackingController(JobStatus.TRACKING_TIME)) {
133 if (mTrackedJobs.remove(job)) {
134 checkExpiredDelaysAndResetAlarm();
135 checkExpiredDeadlinesAndResetAlarm();
136 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700137 }
138 }
139
140 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700141 * Determines whether this controller can stop tracking the given job.
142 * The controller is no longer interested in a job once its time constraint is satisfied, and
143 * the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
Matthew Williams6de79e22014-05-01 10:47:00 -0700144 * back and forth.
145 */
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800146 private boolean canStopTrackingJobLocked(JobStatus job) {
Christopher Tate7060b042014-06-09 19:50:00 -0700147 return (!job.hasTimingDelayConstraint() ||
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800148 (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
Christopher Tate7060b042014-06-09 19:50:00 -0700149 (!job.hasDeadlineConstraint() ||
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800150 (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
Matthew Williams6de79e22014-05-01 10:47:00 -0700151 }
152
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800153 private void ensureAlarmServiceLocked() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700154 if (mAlarmService == null) {
155 mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
156 }
157 }
158
159 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700160 * Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
Matthew Williamseffacfa2014-06-05 20:56:40 -0700161 * if so, removing them from this list, and updating the alarm for the next expiry time.
Matthew Williams6de79e22014-05-01 10:47:00 -0700162 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800163 private void checkExpiredDeadlinesAndResetAlarm() {
164 synchronized (mLock) {
165 long nextExpiryTime = Long.MAX_VALUE;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700166 int nextExpiryUid = 0;
Adam Lesinskic746b382017-10-13 14:31:08 -0700167 String nextExpiryPackageName = null;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700168 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Matthew Williams6de79e22014-05-01 10:47:00 -0700169
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800170 Iterator<JobStatus> it = mTrackedJobs.iterator();
171 while (it.hasNext()) {
172 JobStatus job = it.next();
173 if (!job.hasDeadlineConstraint()) {
174 continue;
175 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700176
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700177 if (evaluateDeadlineConstraint(job, nowElapsedMillis)) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800178 mStateChangedListener.onRunJobNow(job);
179 it.remove();
180 } else { // Sorted by expiry time, so take the next one and stop.
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700181 nextExpiryTime = job.getLatestRunTimeElapsed();
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700182 nextExpiryUid = job.getSourceUid();
Adam Lesinskic746b382017-10-13 14:31:08 -0700183 nextExpiryPackageName = job.getSourcePackageName();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800184 break;
185 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700186 }
Narayan Kamath8d828252018-01-11 15:22:37 +0000187 setDeadlineExpiredAlarmLocked(nextExpiryTime,
188 deriveWorkSource(nextExpiryUid, nextExpiryPackageName));
Matthew Williams6de79e22014-05-01 10:47:00 -0700189 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700190 }
191
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700192 private boolean evaluateDeadlineConstraint(JobStatus job, long nowElapsedMillis) {
193 final long jobDeadline = job.getLatestRunTimeElapsed();
194
195 if (jobDeadline <= nowElapsedMillis) {
196 if (job.hasTimingDelayConstraint()) {
197 job.setTimingDelayConstraintSatisfied(true);
198 }
199 job.setDeadlineConstraintSatisfied(true);
200 return true;
201 }
202 return false;
203 }
204
Matthew Williams6de79e22014-05-01 10:47:00 -0700205 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700206 * Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
207 * tracked jobs and marks them as ready as appropriate.
Matthew Williams6de79e22014-05-01 10:47:00 -0700208 */
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800209 private void checkExpiredDelaysAndResetAlarm() {
210 synchronized (mLock) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700211 final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800212 long nextDelayTime = Long.MAX_VALUE;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700213 int nextDelayUid = 0;
Adam Lesinskic746b382017-10-13 14:31:08 -0700214 String nextDelayPackageName = null;
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800215 boolean ready = false;
216 Iterator<JobStatus> it = mTrackedJobs.iterator();
217 while (it.hasNext()) {
218 final JobStatus job = it.next();
219 if (!job.hasTimingDelayConstraint()) {
220 continue;
Matthew Williams6de79e22014-05-01 10:47:00 -0700221 }
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700222 if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800223 if (canStopTrackingJobLocked(job)) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800224 it.remove();
225 }
226 if (job.isReady()) {
227 ready = true;
228 }
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700229 } else if (!job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)) {
230 // If this job still doesn't have its delay constraint satisfied,
231 // then see if it is the next upcoming delay time for the alarm.
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700232 final long jobDelayTime = job.getEarliestRunTime();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800233 if (nextDelayTime > jobDelayTime) {
234 nextDelayTime = jobDelayTime;
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700235 nextDelayUid = job.getSourceUid();
Adam Lesinskic746b382017-10-13 14:31:08 -0700236 nextDelayPackageName = job.getSourcePackageName();
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800237 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700238 }
239 }
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800240 if (ready) {
241 mStateChangedListener.onControllerStateChanged();
242 }
Narayan Kamath8d828252018-01-11 15:22:37 +0000243 setDelayExpiredAlarmLocked(nextDelayTime,
244 deriveWorkSource(nextDelayUid, nextDelayPackageName));
245 }
246 }
247
248 private WorkSource deriveWorkSource(int uid, @Nullable String packageName) {
249 if (mChainedAttributionEnabled) {
250 WorkSource ws = new WorkSource();
251 ws.createWorkChain()
252 .addNode(uid, packageName)
253 .addNode(Process.SYSTEM_UID, "JobScheduler");
254 return ws;
255 } else {
256 return packageName == null ? new WorkSource(uid) : new WorkSource(uid, packageName);
Matthew Williams6de79e22014-05-01 10:47:00 -0700257 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700258 }
259
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700260 private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) {
261 final long jobDelayTime = job.getEarliestRunTime();
262 if (jobDelayTime <= nowElapsedMillis) {
263 job.setTimingDelayConstraintSatisfied(true);
264 return true;
265 }
266 return false;
267 }
268
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700269 private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed,
Adam Lesinskic746b382017-10-13 14:31:08 -0700270 WorkSource ws) {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700271 if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
Adam Lesinskic746b382017-10-13 14:31:08 -0700272 setDelayExpiredAlarmLocked(delayExpiredElapsed, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700273 }
Christopher Tate7060b042014-06-09 19:50:00 -0700274 if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
Adam Lesinskic746b382017-10-13 14:31:08 -0700275 setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700276 }
277 }
278
279 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700280 * 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 -0700281 * delay will expire.
Shreyas Basarge4b7e339c2016-01-20 16:25:07 +0000282 * This alarm <b>will</b> wake up the phone.
Matthew Williamseffacfa2014-06-05 20:56:40 -0700283 */
Adam Lesinskic746b382017-10-13 14:31:08 -0700284 private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700285 alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700286 mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800287 updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700288 mNextDelayExpiredElapsedMillis, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700289 }
290
291 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700292 * 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 -0700293 * deadline will expire.
294 * This alarm <b>will</b> wake up the phone.
295 */
Adam Lesinskic746b382017-10-13 14:31:08 -0700296 private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700297 alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
Christopher Tate7060b042014-06-09 19:50:00 -0700298 mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800299 updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700300 mNextJobExpiredElapsedMillis, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700301 }
302
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700303 private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700304 final long earliestWakeupTimeElapsed = sElapsedRealtimeClock.millis();
Matthew Williamsa9f993c2014-09-11 11:31:05 -0700305 if (proposedAlarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
306 return earliestWakeupTimeElapsed;
307 }
308 return proposedAlarmTimeElapsedMillis;
309 }
310
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800311 private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
Adam Lesinskic746b382017-10-13 14:31:08 -0700312 long alarmTimeElapsed, WorkSource ws) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -0800313 ensureAlarmServiceLocked();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700314 if (alarmTimeElapsed == Long.MAX_VALUE) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800315 mAlarmService.cancel(listener);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700316 } else {
317 if (DEBUG) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800318 Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700319 }
Shreyas Basarge4b7e339c2016-01-20 16:25:07 +0000320 mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed,
Adam Lesinskic746b382017-10-13 14:31:08 -0700321 AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700322 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700323 }
324
Christopher Tate2fcbe212015-12-09 16:00:37 -0800325 // Job/delay expiration alarm handling
326
327 private final OnAlarmListener mDeadlineExpiredListener = new OnAlarmListener() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700328 @Override
Christopher Tate2fcbe212015-12-09 16:00:37 -0800329 public void onAlarm() {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700330 if (DEBUG) {
Christopher Tate2fcbe212015-12-09 16:00:37 -0800331 Slog.d(TAG, "Deadline-expired alarm fired");
Matthew Williamseffacfa2014-06-05 20:56:40 -0700332 }
Christopher Tate2fcbe212015-12-09 16:00:37 -0800333 checkExpiredDeadlinesAndResetAlarm();
334 }
335 };
336
337 private final OnAlarmListener mNextDelayExpiredListener = new OnAlarmListener() {
338 @Override
339 public void onAlarm() {
340 if (DEBUG) {
341 Slog.d(TAG, "Delay-expired alarm fired");
Matthew Williams6de79e22014-05-01 10:47:00 -0700342 }
Christopher Tate2fcbe212015-12-09 16:00:37 -0800343 checkExpiredDelaysAndResetAlarm();
Matthew Williams6de79e22014-05-01 10:47:00 -0700344 }
345 };
Matthew Williamseffacfa2014-06-05 20:56:40 -0700346
347 @Override
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700348 public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700349 final long nowElapsed = sElapsedRealtimeClock.millis();
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700350 pw.print("Alarms: now=");
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800351 pw.print(nowElapsed);
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700352 pw.println();
353 pw.print("Next delay alarm in ");
354 TimeUtils.formatDuration(mNextDelayExpiredElapsedMillis, nowElapsed, pw);
355 pw.println();
356 pw.print("Next deadline alarm in ");
357 TimeUtils.formatDuration(mNextJobExpiredElapsedMillis, nowElapsed, pw);
358 pw.println();
359 pw.print("Tracking ");
360 pw.print(mTrackedJobs.size());
361 pw.println(":");
Christopher Tate7060b042014-06-09 19:50:00 -0700362 for (JobStatus ts : mTrackedJobs) {
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700363 if (!ts.shouldDump(filterUid)) {
364 continue;
365 }
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700366 pw.print(" #");
367 ts.printUniqueId(pw);
368 pw.print(" from ");
369 UserHandle.formatUid(pw, ts.getSourceUid());
370 pw.print(": Delay=");
371 if (ts.hasTimingDelayConstraint()) {
372 TimeUtils.formatDuration(ts.getEarliestRunTime(), nowElapsed, pw);
373 } else {
374 pw.print("N/A");
375 }
376 pw.print(", Deadline=");
377 if (ts.hasDeadlineConstraint()) {
378 TimeUtils.formatDuration(ts.getLatestRunTimeElapsed(), nowElapsed, pw);
379 } else {
380 pw.print("N/A");
381 }
382 pw.println();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700383 }
384 }
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800385
386 @Override
387 public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
388 final long token = proto.start(fieldId);
389 final long mToken = proto.start(StateControllerProto.TIME);
390
391 final long nowElapsed = sElapsedRealtimeClock.millis();
392 proto.write(StateControllerProto.TimeController.NOW_ELAPSED_REALTIME, nowElapsed);
393 proto.write(StateControllerProto.TimeController.TIME_UNTIL_NEXT_DELAY_ALARM_MS,
394 mNextDelayExpiredElapsedMillis - nowElapsed);
395 proto.write(StateControllerProto.TimeController.TIME_UNTIL_NEXT_DEADLINE_ALARM_MS,
396 mNextJobExpiredElapsedMillis - nowElapsed);
397
398 for (JobStatus ts : mTrackedJobs) {
399 if (!ts.shouldDump(filterUid)) {
400 continue;
401 }
402 final long tsToken = proto.start(StateControllerProto.TimeController.TRACKED_JOBS);
403 ts.writeToShortProto(proto, StateControllerProto.TimeController.TrackedJob.INFO);
404
405 proto.write(StateControllerProto.TimeController.TrackedJob.HAS_TIMING_DELAY_CONSTRAINT,
406 ts.hasTimingDelayConstraint());
407 proto.write(StateControllerProto.TimeController.TrackedJob.DELAY_TIME_REMAINING_MS,
408 ts.getEarliestRunTime() - nowElapsed);
409
410 proto.write(StateControllerProto.TimeController.TrackedJob.HAS_DEADLINE_CONSTRAINT,
411 ts.hasDeadlineConstraint());
412 proto.write(StateControllerProto.TimeController.TrackedJob.TIME_REMAINING_UNTIL_DEADLINE_MS,
413 ts.getLatestRunTimeElapsed() - nowElapsed);
414
415 proto.end(tsToken);
416 }
417
418 proto.end(mToken);
419 proto.end(token);
420 }
421}