blob: 47bf188a125a126b90c7ce06cf438ece7f1aef2e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080019import android.app.Activity;
Adrian Roosc42a1e12014-07-07 23:35:53 +020020import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.ActivityManagerNative;
Christopher Tate57ceaaa2013-07-19 16:30:43 -070022import android.app.AlarmManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.app.IAlarmManager;
24import android.app.PendingIntent;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.PackageManager;
30import android.net.Uri;
31import android.os.Binder;
32import android.os.Bundle;
33import android.os.Handler;
Adam Lesinski182f73f2013-12-05 16:48:06 -080034import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.os.Message;
36import android.os.PowerManager;
37import android.os.SystemClock;
38import android.os.SystemProperties;
Dianne Hackborn80a4af22012-08-27 19:18:31 -070039import android.os.UserHandle;
Christopher Tatec4a07d12012-04-06 14:19:13 -070040import android.os.WorkSource;
Adrian Roosc42a1e12014-07-07 23:35:53 +020041import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.text.TextUtils;
Adrian Roosc42a1e12014-07-07 23:35:53 +020043import android.text.format.DateFormat;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -080044import android.util.ArrayMap;
Adrian Roosc42a1e12014-07-07 23:35:53 +020045import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080046import android.util.Slog;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -080047import android.util.SparseArray;
Adrian Roosc42a1e12014-07-07 23:35:53 +020048import android.util.SparseBooleanArray;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070049import android.util.TimeUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050
Christopher Tate4cb338d2013-07-26 13:11:31 -070051import java.io.ByteArrayOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import java.io.FileDescriptor;
53import java.io.PrintWriter;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070054import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.util.ArrayList;
Dianne Hackborn81038902012-11-26 17:04:09 -080056import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import java.util.Calendar;
58import java.util.Collections;
59import java.util.Comparator;
Mike Lockwood1f7b4132009-11-20 15:12:51 -050060import java.util.Date;
Christopher Tate1590f1e2014-10-02 17:27:57 -070061import java.util.HashMap;
Christopher Tate18a75f12013-07-01 18:18:59 -070062import java.util.LinkedList;
Adrian Roosc42a1e12014-07-07 23:35:53 +020063import java.util.Locale;
Christopher Tate81f98822014-12-04 18:27:16 -080064import java.util.Random;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import java.util.TimeZone;
66
Christopher Tatee0a22b32013-07-11 14:43:13 -070067import static android.app.AlarmManager.RTC_WAKEUP;
68import static android.app.AlarmManager.RTC;
69import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
70import static android.app.AlarmManager.ELAPSED_REALTIME;
71
Dianne Hackborn81038902012-11-26 17:04:09 -080072import com.android.internal.util.LocalLog;
73
Adam Lesinski182f73f2013-12-05 16:48:06 -080074class AlarmManagerService extends SystemService {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 // The threshold for how long an alarm can be late before we print a
76 // warning message. The time duration is in milliseconds.
77 private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
Christopher Tatee0a22b32013-07-11 14:43:13 -070078
Christopher Tate498c6cb2014-11-17 16:09:27 -080079 // Minimum futurity of a new alarm
80 private static final long MIN_FUTURITY = 5 * 1000; // 5 seconds, in millis
81
82 // Minimum alarm recurrence interval
83 private static final long MIN_INTERVAL = 60 * 1000; // one minute, in millis
84
Christopher Tatee0a22b32013-07-11 14:43:13 -070085 private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
86 private static final int RTC_MASK = 1 << RTC;
Adam Lesinski182f73f2013-12-05 16:48:06 -080087 private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
Christopher Tatee0a22b32013-07-11 14:43:13 -070088 private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
Adam Lesinski182f73f2013-12-05 16:48:06 -080089 static final int TIME_CHANGED_MASK = 1 << 16;
90 static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
Christopher Tateb8849c12011-02-08 13:39:01 -080091
Christopher Tatee0a22b32013-07-11 14:43:13 -070092 // Mask for testing whether a given alarm type is wakeup vs non-wakeup
Adam Lesinski182f73f2013-12-05 16:48:06 -080093 static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
Christopher Tateb8849c12011-02-08 13:39:01 -080094
Adam Lesinski182f73f2013-12-05 16:48:06 -080095 static final String TAG = "AlarmManager";
96 static final String ClockReceiver_TAG = "ClockReceiver";
97 static final boolean localLOGV = false;
98 static final boolean DEBUG_BATCH = localLOGV || false;
99 static final boolean DEBUG_VALIDATE = localLOGV || false;
Adrian Roosc42a1e12014-07-07 23:35:53 +0200100 static final boolean DEBUG_ALARM_CLOCK = localLOGV || false;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800101 static final int ALARM_EVENT = 1;
102 static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
Adrian Roosc42a1e12014-07-07 23:35:53 +0200103
Adam Lesinski182f73f2013-12-05 16:48:06 -0800104 static final Intent mBackgroundIntent
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800106 static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107
Adam Lesinski182f73f2013-12-05 16:48:06 -0800108 static final boolean WAKEUP_STATS = false;
Christopher Tate18a75f12013-07-01 18:18:59 -0700109
Adrian Roosc42a1e12014-07-07 23:35:53 +0200110 private static final Intent NEXT_ALARM_CLOCK_CHANGED_INTENT = new Intent(
111 AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
112
Adam Lesinski182f73f2013-12-05 16:48:06 -0800113 final LocalLog mLog = new LocalLog(TAG);
Dianne Hackborn81038902012-11-26 17:04:09 -0800114
Adam Lesinski182f73f2013-12-05 16:48:06 -0800115 final Object mLock = new Object();
Dianne Hackborn81038902012-11-26 17:04:09 -0800116
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -0800117 long mNativeData;
Christopher Tate81f98822014-12-04 18:27:16 -0800118
119 private final Random mFuzzer = new Random();
120 private long mNextWakeupBatchStart; // nominal start of next wakeup's delivery window
121 private long mNextWakeup; // actual scheduled next wakeup within that window
Christopher Tatee0a22b32013-07-11 14:43:13 -0700122 private long mNextNonWakeup;
Christopher Tate81f98822014-12-04 18:27:16 -0800123
Adam Lesinski182f73f2013-12-05 16:48:06 -0800124 int mBroadcastRefCount = 0;
125 PowerManager.WakeLock mWakeLock;
Dianne Hackborna1bd7922014-03-21 11:07:11 -0700126 boolean mLastWakeLockUnimportantForLogging;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700127 ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800128 ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
129 final AlarmHandler mHandler = new AlarmHandler();
130 ClockReceiver mClockReceiver;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700131 InteractiveStateReceiver mInteractiveStateReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 private UninstallReceiver mUninstallReceiver;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800133 final ResultReceiver mResultReceiver = new ResultReceiver();
134 PendingIntent mTimeTickSender;
135 PendingIntent mDateChangeSender;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700136 boolean mInteractive = true;
137 long mNonInteractiveStartTime;
138 long mNonInteractiveTime;
139 long mLastAlarmDeliveryTime;
140 long mStartCurrentDelayTime;
141 long mNextNonWakeupDeliveryTime;
Dianne Hackborn998e6082014-09-11 19:13:23 -0700142 int mNumTimeChanged;
Dianne Hackborn81038902012-11-26 17:04:09 -0800143
Jose Lima235510e2014-08-13 12:50:01 -0700144 private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
145 new SparseArray<>();
146 private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray =
147 new SparseArray<>();
Adrian Roosc42a1e12014-07-07 23:35:53 +0200148 private final SparseBooleanArray mPendingSendNextAlarmClockChangedForUser =
149 new SparseBooleanArray();
150 private boolean mNextAlarmClockMayChange;
151
152 // May only use on mHandler's thread, locking not required.
Jose Lima235510e2014-08-13 12:50:01 -0700153 private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
154 new SparseArray<>();
Adrian Roosc42a1e12014-07-07 23:35:53 +0200155
Christopher Tate1590f1e2014-10-02 17:27:57 -0700156 // Alarm delivery ordering bookkeeping
157 static final int PRIO_TICK = 0;
158 static final int PRIO_WAKEUP = 1;
159 static final int PRIO_NORMAL = 2;
160
161 class PriorityClass {
162 int seq;
163 int priority;
164
165 PriorityClass() {
166 seq = mCurrentSeq - 1;
167 priority = PRIO_NORMAL;
168 }
169 }
170
171 final HashMap<String, PriorityClass> mPriorities =
172 new HashMap<String, PriorityClass>();
173 int mCurrentSeq = 0;
174
Christopher Tate18a75f12013-07-01 18:18:59 -0700175 class WakeupEvent {
176 public long when;
177 public int uid;
178 public String action;
179
180 public WakeupEvent(long theTime, int theUid, String theAction) {
181 when = theTime;
182 uid = theUid;
183 action = theAction;
184 }
185 }
186
Adam Lesinski182f73f2013-12-05 16:48:06 -0800187 final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
188 final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
Christopher Tate18a75f12013-07-01 18:18:59 -0700189
Adrian Roosc42a1e12014-07-07 23:35:53 +0200190 final class Batch {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700191 long start; // These endpoints are always in ELAPSED
192 long end;
193 boolean standalone; // certain "batches" don't participate in coalescing
194
195 final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
196
197 Batch() {
198 start = 0;
199 end = Long.MAX_VALUE;
200 }
201
202 Batch(Alarm seed) {
203 start = seed.whenElapsed;
204 end = seed.maxWhen;
205 alarms.add(seed);
206 }
207
208 int size() {
209 return alarms.size();
210 }
211
212 Alarm get(int index) {
213 return alarms.get(index);
214 }
215
216 boolean canHold(long whenElapsed, long maxWhen) {
217 return (end >= whenElapsed) && (start <= maxWhen);
218 }
219
220 boolean add(Alarm alarm) {
221 boolean newStart = false;
222 // narrows the batch if necessary; presumes that canHold(alarm) is true
223 int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder);
224 if (index < 0) {
225 index = 0 - index - 1;
226 }
227 alarms.add(index, alarm);
228 if (DEBUG_BATCH) {
229 Slog.v(TAG, "Adding " + alarm + " to " + this);
230 }
231 if (alarm.whenElapsed > start) {
232 start = alarm.whenElapsed;
233 newStart = true;
234 }
235 if (alarm.maxWhen < end) {
236 end = alarm.maxWhen;
237 }
238
239 if (DEBUG_BATCH) {
240 Slog.v(TAG, " => now " + this);
241 }
242 return newStart;
243 }
244
245 boolean remove(final PendingIntent operation) {
246 boolean didRemove = false;
247 long newStart = 0; // recalculate endpoints as we go
248 long newEnd = Long.MAX_VALUE;
Christopher Tateae269d52013-09-26 13:11:55 -0700249 for (int i = 0; i < alarms.size(); ) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700250 Alarm alarm = alarms.get(i);
251 if (alarm.operation.equals(operation)) {
252 alarms.remove(i);
253 didRemove = true;
Adrian Roosc42a1e12014-07-07 23:35:53 +0200254 if (alarm.alarmClock != null) {
255 mNextAlarmClockMayChange = true;
256 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700257 } else {
258 if (alarm.whenElapsed > newStart) {
259 newStart = alarm.whenElapsed;
260 }
261 if (alarm.maxWhen < newEnd) {
262 newEnd = alarm.maxWhen;
263 }
264 i++;
265 }
266 }
267 if (didRemove) {
268 // commit the new batch bounds
269 start = newStart;
270 end = newEnd;
271 }
272 return didRemove;
273 }
274
275 boolean remove(final String packageName) {
276 boolean didRemove = false;
277 long newStart = 0; // recalculate endpoints as we go
278 long newEnd = Long.MAX_VALUE;
Christopher Tateae269d52013-09-26 13:11:55 -0700279 for (int i = 0; i < alarms.size(); ) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700280 Alarm alarm = alarms.get(i);
281 if (alarm.operation.getTargetPackage().equals(packageName)) {
282 alarms.remove(i);
283 didRemove = true;
Adrian Roosc42a1e12014-07-07 23:35:53 +0200284 if (alarm.alarmClock != null) {
285 mNextAlarmClockMayChange = true;
286 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700287 } else {
288 if (alarm.whenElapsed > newStart) {
289 newStart = alarm.whenElapsed;
290 }
291 if (alarm.maxWhen < newEnd) {
292 newEnd = alarm.maxWhen;
293 }
294 i++;
295 }
296 }
297 if (didRemove) {
298 // commit the new batch bounds
299 start = newStart;
300 end = newEnd;
301 }
302 return didRemove;
303 }
304
305 boolean remove(final int userHandle) {
306 boolean didRemove = false;
307 long newStart = 0; // recalculate endpoints as we go
308 long newEnd = Long.MAX_VALUE;
Christopher Tateae269d52013-09-26 13:11:55 -0700309 for (int i = 0; i < alarms.size(); ) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700310 Alarm alarm = alarms.get(i);
311 if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
312 alarms.remove(i);
313 didRemove = true;
Adrian Roosc42a1e12014-07-07 23:35:53 +0200314 if (alarm.alarmClock != null) {
315 mNextAlarmClockMayChange = true;
316 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700317 } else {
318 if (alarm.whenElapsed > newStart) {
319 newStart = alarm.whenElapsed;
320 }
321 if (alarm.maxWhen < newEnd) {
322 newEnd = alarm.maxWhen;
323 }
324 i++;
325 }
326 }
327 if (didRemove) {
328 // commit the new batch bounds
329 start = newStart;
330 end = newEnd;
331 }
332 return didRemove;
333 }
334
335 boolean hasPackage(final String packageName) {
336 final int N = alarms.size();
337 for (int i = 0; i < N; i++) {
338 Alarm a = alarms.get(i);
339 if (a.operation.getTargetPackage().equals(packageName)) {
340 return true;
341 }
342 }
343 return false;
344 }
345
346 boolean hasWakeups() {
347 final int N = alarms.size();
348 for (int i = 0; i < N; i++) {
349 Alarm a = alarms.get(i);
350 // non-wakeup alarms are types 1 and 3, i.e. have the low bit set
351 if ((a.type & TYPE_NONWAKEUP_MASK) == 0) {
352 return true;
353 }
354 }
355 return false;
356 }
357
358 @Override
359 public String toString() {
360 StringBuilder b = new StringBuilder(40);
361 b.append("Batch{"); b.append(Integer.toHexString(this.hashCode()));
362 b.append(" num="); b.append(size());
363 b.append(" start="); b.append(start);
364 b.append(" end="); b.append(end);
365 if (standalone) {
366 b.append(" STANDALONE");
367 }
368 b.append('}');
369 return b.toString();
370 }
371 }
372
373 static class BatchTimeOrder implements Comparator<Batch> {
374 public int compare(Batch b1, Batch b2) {
Christopher Tate81f98822014-12-04 18:27:16 -0800375 final long start1 = b1.start;
376 final long start2 = b2.start;
377 if (start1 > start2) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700378 return 1;
379 }
Christopher Tate81f98822014-12-04 18:27:16 -0800380 if (start1 < start2) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700381 return -1;
382 }
Christopher Tate81f98822014-12-04 18:27:16 -0800383
384 // Identical trigger times. As a secondary ordering, require that
385 // the batch with the shorter allowable delivery window sorts first.
386 final long interval1 = b1.end - b1.start;
387 final long interval2 = b2.end - b2.start;
388 if (interval1 > interval2) {
389 return 1;
390 }
391 if (interval2 < interval1) {
392 return -1;
393 }
394
395 // equal start + delivery window => they're identical
Christopher Tatee0a22b32013-07-11 14:43:13 -0700396 return 0;
397 }
398 }
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800399
400 final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
401 @Override
402 public int compare(Alarm lhs, Alarm rhs) {
Christopher Tate1590f1e2014-10-02 17:27:57 -0700403 // priority class trumps everything. TICK < WAKEUP < NORMAL
404 if (lhs.priorityClass.priority < rhs.priorityClass.priority) {
405 return -1;
406 } else if (lhs.priorityClass.priority > rhs.priorityClass.priority) {
407 return 1;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800408 }
Christopher Tate1590f1e2014-10-02 17:27:57 -0700409
410 // within each class, sort by nominal delivery time
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800411 if (lhs.whenElapsed < rhs.whenElapsed) {
412 return -1;
413 } else if (lhs.whenElapsed > rhs.whenElapsed) {
414 return 1;
415 }
Christopher Tate1590f1e2014-10-02 17:27:57 -0700416
417 // same priority class + same target delivery time
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800418 return 0;
419 }
420 };
421
Christopher Tate1590f1e2014-10-02 17:27:57 -0700422 void calculateDeliveryPriorities(ArrayList<Alarm> alarms) {
423 final int N = alarms.size();
424 for (int i = 0; i < N; i++) {
425 Alarm a = alarms.get(i);
426
427 final int alarmPrio;
428 if (Intent.ACTION_TIME_TICK.equals(a.operation.getIntent().getAction())) {
429 alarmPrio = PRIO_TICK;
430 } else if (a.wakeup) {
431 alarmPrio = PRIO_WAKEUP;
432 } else {
433 alarmPrio = PRIO_NORMAL;
434 }
435
436 PriorityClass packagePrio = a.priorityClass;
437 if (packagePrio == null) packagePrio = mPriorities.get(a.operation.getCreatorPackage());
438 if (packagePrio == null) {
439 packagePrio = a.priorityClass = new PriorityClass(); // lowest prio & stale sequence
440 mPriorities.put(a.operation.getCreatorPackage(), packagePrio);
441 }
442 a.priorityClass = packagePrio;
443
444 if (packagePrio.seq != mCurrentSeq) {
445 // first alarm we've seen in the current delivery generation from this package
446 packagePrio.priority = alarmPrio;
447 packagePrio.seq = mCurrentSeq;
448 } else {
449 // Multiple alarms from this package being delivered in this generation;
450 // bump the package's delivery class if it's warranted.
451 // TICK < WAKEUP < NORMAL
452 if (alarmPrio < packagePrio.priority) {
453 packagePrio.priority = alarmPrio;
454 }
455 }
456 }
457 }
458
Christopher Tatee0a22b32013-07-11 14:43:13 -0700459 // minimum recurrence period or alarm futurity for us to be able to fuzz it
Adam Lesinski182f73f2013-12-05 16:48:06 -0800460 static final long MIN_FUZZABLE_INTERVAL = 10000;
461 static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
462 final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
Christopher Tatee0a22b32013-07-11 14:43:13 -0700463
Jeff Brownb880d882014-02-10 19:47:07 -0800464 public AlarmManagerService(Context context) {
465 super(context);
466 }
467
Christopher Tatee0a22b32013-07-11 14:43:13 -0700468 static long convertToElapsed(long when, int type) {
469 final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
470 if (isRtc) {
471 when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
472 }
473 return when;
474 }
475
476 // Apply a heuristic to { recurrence interval, futurity of the trigger time } to
477 // calculate the end of our nominal delivery window for the alarm.
478 static long maxTriggerTime(long now, long triggerAtTime, long interval) {
479 // Current heuristic: batchable window is 75% of either the recurrence interval
480 // [for a periodic alarm] or of the time from now to the desired delivery time,
481 // with a minimum delay/interval of 10 seconds, under which we will simply not
482 // defer the alarm.
483 long futurity = (interval == 0)
484 ? (triggerAtTime - now)
485 : interval;
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700486 if (futurity < MIN_FUZZABLE_INTERVAL) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700487 futurity = 0;
488 }
489 return triggerAtTime + (long)(.75 * futurity);
490 }
491
492 // returns true if the batch was added at the head
493 static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) {
494 int index = Collections.binarySearch(list, newBatch, sBatchOrder);
495 if (index < 0) {
496 index = 0 - index - 1;
497 }
498 list.add(index, newBatch);
499 return (index == 0);
500 }
501
Christopher Tate385e4982013-07-23 18:22:29 -0700502 // Return the index of the matching batch, or -1 if none found.
503 int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700504 final int N = mAlarmBatches.size();
505 for (int i = 0; i < N; i++) {
506 Batch b = mAlarmBatches.get(i);
507 if (!b.standalone && b.canHold(whenElapsed, maxWhen)) {
Christopher Tate385e4982013-07-23 18:22:29 -0700508 return i;
Christopher Tatee0a22b32013-07-11 14:43:13 -0700509 }
510 }
Christopher Tate385e4982013-07-23 18:22:29 -0700511 return -1;
Christopher Tatee0a22b32013-07-11 14:43:13 -0700512 }
513
514 // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
515 void rebatchAllAlarms() {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700516 synchronized (mLock) {
Christopher Tate4cb338d2013-07-26 13:11:31 -0700517 rebatchAllAlarmsLocked(true);
518 }
519 }
520
521 void rebatchAllAlarmsLocked(boolean doValidate) {
522 ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
523 mAlarmBatches.clear();
524 final long nowElapsed = SystemClock.elapsedRealtime();
525 final int oldBatches = oldSet.size();
526 for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
527 Batch batch = oldSet.get(batchNum);
528 final int N = batch.size();
529 for (int i = 0; i < N; i++) {
530 Alarm a = batch.get(i);
531 long whenElapsed = convertToElapsed(a.when, a.type);
Christopher Tate3e04b472013-10-21 17:51:31 -0700532 final long maxElapsed;
533 if (a.whenElapsed == a.maxWhen) {
534 // Exact
535 maxElapsed = whenElapsed;
536 } else {
537 // Not exact. Preserve any explicit window, otherwise recalculate
538 // the window based on the alarm's new futurity. Note that this
539 // reflects a policy of preferring timely to deferred delivery.
540 maxElapsed = (a.windowLength > 0)
541 ? (whenElapsed + a.windowLength)
542 : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
543 }
544 setImplLocked(a.type, a.when, whenElapsed, a.windowLength, maxElapsed,
Adrian Roosc42a1e12014-07-07 23:35:53 +0200545 a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource,
546 a.alarmClock, a.userId);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700547 }
548 }
549 }
550
Adam Lesinski182f73f2013-12-05 16:48:06 -0800551 static final class InFlight extends Intent {
Dianne Hackborn81038902012-11-26 17:04:09 -0800552 final PendingIntent mPendingIntent;
David Christieebe51fc2013-07-26 13:23:29 -0700553 final WorkSource mWorkSource;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700554 final String mTag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800555 final BroadcastStats mBroadcastStats;
556 final FilterStats mFilterStats;
Dianne Hackborne5167ca2014-03-08 14:39:10 -0800557 final int mAlarmType;
Dianne Hackborn81038902012-11-26 17:04:09 -0800558
Dianne Hackborne5167ca2014-03-08 14:39:10 -0800559 InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700560 int alarmType, String tag) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800561 mPendingIntent = pendingIntent;
David Christieebe51fc2013-07-26 13:23:29 -0700562 mWorkSource = workSource;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700563 mTag = tag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800564 mBroadcastStats = service.getStatsLocked(pendingIntent);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700565 FilterStats fs = mBroadcastStats.filterStats.get(mTag);
Dianne Hackborn81038902012-11-26 17:04:09 -0800566 if (fs == null) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700567 fs = new FilterStats(mBroadcastStats, mTag);
568 mBroadcastStats.filterStats.put(mTag, fs);
Dianne Hackborn81038902012-11-26 17:04:09 -0800569 }
570 mFilterStats = fs;
Dianne Hackborne5167ca2014-03-08 14:39:10 -0800571 mAlarmType = alarmType;
Dianne Hackborn81038902012-11-26 17:04:09 -0800572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800574
Adam Lesinski182f73f2013-12-05 16:48:06 -0800575 static final class FilterStats {
Dianne Hackborn81038902012-11-26 17:04:09 -0800576 final BroadcastStats mBroadcastStats;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700577 final String mTag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 long aggregateTime;
Dianne Hackborn81038902012-11-26 17:04:09 -0800580 int count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 int numWakeup;
582 long startTime;
583 int nesting;
Dianne Hackborn81038902012-11-26 17:04:09 -0800584
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700585 FilterStats(BroadcastStats broadcastStats, String tag) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800586 mBroadcastStats = broadcastStats;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700587 mTag = tag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800588 }
589 }
590
Adam Lesinski182f73f2013-12-05 16:48:06 -0800591 static final class BroadcastStats {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800592 final int mUid;
Dianne Hackborn81038902012-11-26 17:04:09 -0800593 final String mPackageName;
594
595 long aggregateTime;
596 int count;
597 int numWakeup;
598 long startTime;
599 int nesting;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700600 final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>();
Dianne Hackborn81038902012-11-26 17:04:09 -0800601
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800602 BroadcastStats(int uid, String packageName) {
603 mUid = uid;
Dianne Hackborn81038902012-11-26 17:04:09 -0800604 mPackageName = packageName;
605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 }
607
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800608 final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
609 = new SparseArray<ArrayMap<String, BroadcastStats>>();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700610
611 int mNumDelayedAlarms = 0;
612 long mTotalDelayTime = 0;
613 long mMaxDelayTime = 0;
614
Adam Lesinski182f73f2013-12-05 16:48:06 -0800615 @Override
616 public void onStart() {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800617 mNativeData = init();
Christopher Tate81f98822014-12-04 18:27:16 -0800618 mNextWakeup = mNextWakeupBatchStart = mNextNonWakeup = 0;
Robert CH Chou64ba8e42009-11-04 21:38:49 +0800619
620 // We have to set current TimeZone info to kernel
621 // because kernel doesn't keep this after reboot
Adam Lesinski182f73f2013-12-05 16:48:06 -0800622 setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
Robert CH Chou64ba8e42009-11-04 21:38:49 +0800623
Adam Lesinski182f73f2013-12-05 16:48:06 -0800624 PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800625 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800626
Adam Lesinski182f73f2013-12-05 16:48:06 -0800627 mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 new Intent(Intent.ACTION_TIME_TICK).addFlags(
Dianne Hackborn3bc8f78d2013-09-19 13:34:35 -0700629 Intent.FLAG_RECEIVER_REGISTERED_ONLY
630 | Intent.FLAG_RECEIVER_FOREGROUND), 0,
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700631 UserHandle.ALL);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800632 Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
633 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800634 mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700635 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636
637 // now that we have initied the driver schedule the alarm
Adam Lesinski182f73f2013-12-05 16:48:06 -0800638 mClockReceiver = new ClockReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 mClockReceiver.scheduleTimeTickEvent();
640 mClockReceiver.scheduleDateChangedEvent();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700641 mInteractiveStateReceiver = new InteractiveStateReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 mUninstallReceiver = new UninstallReceiver();
643
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800644 if (mNativeData != 0) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800645 AlarmThread waitThread = new AlarmThread();
646 waitThread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800648 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800650
651 publishBinderService(Context.ALARM_SERVICE, mService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800653
654 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 protected void finalize() throws Throwable {
656 try {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800657 close(mNativeData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 } finally {
659 super.finalize();
660 }
661 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700662
Adam Lesinski182f73f2013-12-05 16:48:06 -0800663 void setTimeZoneImpl(String tz) {
664 if (TextUtils.isEmpty(tz)) {
665 return;
David Christieebe51fc2013-07-26 13:23:29 -0700666 }
667
Adam Lesinski182f73f2013-12-05 16:48:06 -0800668 TimeZone zone = TimeZone.getTimeZone(tz);
669 // Prevent reentrant calls from stepping on each other when writing
670 // the time zone property
671 boolean timeZoneWasChanged = false;
672 synchronized (this) {
673 String current = SystemProperties.get(TIMEZONE_PROPERTY);
674 if (current == null || !current.equals(zone.getID())) {
675 if (localLOGV) {
676 Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
677 }
678 timeZoneWasChanged = true;
679 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
680 }
681
682 // Update the kernel timezone information
683 // Kernel tracks time offsets as 'minutes west of GMT'
684 int gmtOffset = zone.getOffset(System.currentTimeMillis());
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -0800685 setKernelTimezone(mNativeData, -(gmtOffset / 60000));
Adam Lesinski182f73f2013-12-05 16:48:06 -0800686 }
687
688 TimeZone.setDefault(null);
689
690 if (timeZoneWasChanged) {
691 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
692 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
693 intent.putExtra("time-zone", zone.getID());
694 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700697
Adam Lesinski182f73f2013-12-05 16:48:06 -0800698 void removeImpl(PendingIntent operation) {
699 if (operation == null) {
700 return;
701 }
702 synchronized (mLock) {
703 removeLocked(operation);
704 }
705 }
706
707 void setImpl(int type, long triggerAtTime, long windowLength, long interval,
Adrian Roosc42a1e12014-07-07 23:35:53 +0200708 PendingIntent operation, boolean isStandalone, WorkSource workSource,
Jose Lima235510e2014-08-13 12:50:01 -0700709 AlarmManager.AlarmClockInfo alarmClock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800711 Slog.w(TAG, "set/setRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 return;
713 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700714
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700715 // Sanity check the window length. This will catch people mistakenly
716 // trying to pass an end-of-window timestamp rather than a duration.
717 if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
718 Slog.w(TAG, "Window length " + windowLength
719 + "ms suspiciously long; limiting to 1 hour");
720 windowLength = AlarmManager.INTERVAL_HOUR;
721 }
722
Christopher Tate498c6cb2014-11-17 16:09:27 -0800723 // Sanity check the recurrence interval. This will catch people who supply
724 // seconds when the API expects milliseconds.
725 if (interval > 0 && interval < MIN_INTERVAL) {
726 Slog.w(TAG, "Suspiciously short interval " + interval
727 + " millis; expanding to " + (int)(MIN_INTERVAL/1000)
728 + " seconds");
729 interval = MIN_INTERVAL;
730 }
731
Christopher Tatee0a22b32013-07-11 14:43:13 -0700732 if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
733 throw new IllegalArgumentException("Invalid alarm type " + type);
734 }
735
Christopher Tate5f221e82013-07-30 17:13:15 -0700736 if (triggerAtTime < 0) {
737 final long who = Binder.getCallingUid();
738 final long what = Binder.getCallingPid();
739 Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
740 + " pid=" + what);
741 triggerAtTime = 0;
742 }
743
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700744 final long nowElapsed = SystemClock.elapsedRealtime();
Christopher Tate498c6cb2014-11-17 16:09:27 -0800745 final long nominalTrigger = convertToElapsed(triggerAtTime, type);
746 // Try to prevent spamming by making sure we aren't firing alarms in the immediate future
747 final long minTrigger = nowElapsed + MIN_FUTURITY;
748 final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
749
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700750 final long maxElapsed;
751 if (windowLength == AlarmManager.WINDOW_EXACT) {
752 maxElapsed = triggerElapsed;
753 } else if (windowLength < 0) {
754 maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
755 } else {
756 maxElapsed = triggerElapsed + windowLength;
757 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700758
Adrian Roosc42a1e12014-07-07 23:35:53 +0200759 final int userId = UserHandle.getCallingUserId();
760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 synchronized (mLock) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700762 if (DEBUG_BATCH) {
763 Slog.v(TAG, "set(" + operation + ") : type=" + type
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700764 + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
Christopher Tatee0a22b32013-07-11 14:43:13 -0700765 + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
766 + " interval=" + interval + " standalone=" + isStandalone);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 }
Christopher Tate3e04b472013-10-21 17:51:31 -0700768 setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
Adrian Roosc42a1e12014-07-07 23:35:53 +0200769 interval, operation, isStandalone, true, workSource, alarmClock, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 }
771 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772
Christopher Tate3e04b472013-10-21 17:51:31 -0700773 private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
774 long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
Jose Lima235510e2014-08-13 12:50:01 -0700775 boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
776 int userId) {
Christopher Tate3e04b472013-10-21 17:51:31 -0700777 Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
Adrian Roosc42a1e12014-07-07 23:35:53 +0200778 operation, workSource, alarmClock, userId);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700779 removeLocked(operation);
Christopher Tateb8849c12011-02-08 13:39:01 -0800780
Christopher Tate385e4982013-07-23 18:22:29 -0700781 int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
782 if (whichBatch < 0) {
783 Batch batch = new Batch(a);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700784 batch.standalone = isStandalone;
Christopher Tate7d57ed82013-10-25 20:18:03 -0700785 addBatchLocked(mAlarmBatches, batch);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 } else {
Christopher Tate385e4982013-07-23 18:22:29 -0700787 Batch batch = mAlarmBatches.get(whichBatch);
Christopher Tate7d57ed82013-10-25 20:18:03 -0700788 if (batch.add(a)) {
Christopher Tate385e4982013-07-23 18:22:29 -0700789 // The start time of this batch advanced, so batch ordering may
790 // have just been broken. Move it to where it now belongs.
791 mAlarmBatches.remove(whichBatch);
792 addBatchLocked(mAlarmBatches, batch);
793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 }
795
Adrian Roosc42a1e12014-07-07 23:35:53 +0200796 if (alarmClock != null) {
797 mNextAlarmClockMayChange = true;
798 updateNextAlarmClockLocked();
799 }
800
Christopher Tate4cb338d2013-07-26 13:11:31 -0700801 if (DEBUG_VALIDATE) {
Christopher Tate5f221e82013-07-30 17:13:15 -0700802 if (doValidate && !validateConsistencyLocked()) {
803 Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
804 + " when(hex)=" + Long.toHexString(when)
805 + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
806 + " interval=" + interval + " op=" + operation
807 + " standalone=" + isStandalone);
Christopher Tate4cb338d2013-07-26 13:11:31 -0700808 rebatchAllAlarmsLocked(false);
Christopher Tate4cb338d2013-07-26 13:11:31 -0700809 }
810 }
811
Christopher Tate7d57ed82013-10-25 20:18:03 -0700812 rescheduleKernelAlarmsLocked();
Christopher Tatee0a22b32013-07-11 14:43:13 -0700813 }
814
Adam Lesinski182f73f2013-12-05 16:48:06 -0800815 private final IBinder mService = new IAlarmManager.Stub() {
816 @Override
817 public void set(int type, long triggerAtTime, long windowLength, long interval,
Jose Lima235510e2014-08-13 12:50:01 -0700818 PendingIntent operation, WorkSource workSource,
819 AlarmManager.AlarmClockInfo alarmClock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800820 if (workSource != null) {
821 getContext().enforceCallingPermission(
822 android.Manifest.permission.UPDATE_DEVICE_STATS,
823 "AlarmManager.set");
Christopher Tate89779822012-08-31 14:40:03 -0700824 }
825
Christopher Tate81f98822014-12-04 18:27:16 -0800826 // Exact alarms are standalone; inexact get batched together
Adam Lesinski182f73f2013-12-05 16:48:06 -0800827 setImpl(type, triggerAtTime, windowLength, interval, operation,
Christopher Tate81f98822014-12-04 18:27:16 -0800828 windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800829 }
Christopher Tate89779822012-08-31 14:40:03 -0700830
Adam Lesinski182f73f2013-12-05 16:48:06 -0800831 @Override
Greg Hackmann0cab8962014-02-21 16:35:52 -0800832 public boolean setTime(long millis) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800833 getContext().enforceCallingOrSelfPermission(
834 "android.permission.SET_TIME",
835 "setTime");
836
Greg Hackmann0cab8962014-02-21 16:35:52 -0800837 if (mNativeData == 0) {
838 Slog.w(TAG, "Not setting time since no alarm driver is available.");
839 return false;
Christopher Tate89779822012-08-31 14:40:03 -0700840 }
Greg Hackmann0cab8962014-02-21 16:35:52 -0800841
842 synchronized (mLock) {
843 return setKernelTime(mNativeData, millis) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800846
847 @Override
848 public void setTimeZone(String tz) {
849 getContext().enforceCallingOrSelfPermission(
850 "android.permission.SET_TIME_ZONE",
851 "setTimeZone");
852
853 final long oldId = Binder.clearCallingIdentity();
854 try {
855 setTimeZoneImpl(tz);
856 } finally {
857 Binder.restoreCallingIdentity(oldId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 }
859 }
Christopher Tate4cb338d2013-07-26 13:11:31 -0700860
Adam Lesinski182f73f2013-12-05 16:48:06 -0800861 @Override
862 public void remove(PendingIntent operation) {
863 removeImpl(operation);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 }
Christopher Tate4cb338d2013-07-26 13:11:31 -0700866
Adam Lesinski182f73f2013-12-05 16:48:06 -0800867 @Override
Jose Lima235510e2014-08-13 12:50:01 -0700868 public AlarmManager.AlarmClockInfo getNextAlarmClock(int userId) {
Adrian Roosc42a1e12014-07-07 23:35:53 +0200869 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
870 Binder.getCallingUid(), userId, false /* allowAll */, false /* requireFull */,
871 "getNextAlarmClock", null);
872
873 return getNextAlarmClockImpl(userId);
874 }
875
876 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -0800877 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
878 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
879 != PackageManager.PERMISSION_GRANTED) {
880 pw.println("Permission Denial: can't dump AlarmManager from from pid="
881 + Binder.getCallingPid()
882 + ", uid=" + Binder.getCallingUid());
883 return;
Christopher Tate4cb338d2013-07-26 13:11:31 -0700884 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700885
Adam Lesinski182f73f2013-12-05 16:48:06 -0800886 dumpImpl(pw);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700887 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800888 };
Christopher Tate4cb338d2013-07-26 13:11:31 -0700889
Adam Lesinski182f73f2013-12-05 16:48:06 -0800890 void dumpImpl(PrintWriter pw) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 synchronized (mLock) {
892 pw.println("Current Alarm Manager state:");
Christopher Tatee0a22b32013-07-11 14:43:13 -0700893 final long nowRTC = System.currentTimeMillis();
894 final long nowELAPSED = SystemClock.elapsedRealtime();
895 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
896
897 pw.print("nowRTC="); pw.print(nowRTC);
898 pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
Christopher Tate81f98822014-12-04 18:27:16 -0800899 pw.print(" nowELAPSED="); pw.print(nowELAPSED);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700900 pw.println();
901 if (!mInteractive) {
902 pw.print("Time since non-interactive: ");
903 TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw);
904 pw.println();
905 pw.print("Max wakeup delay: ");
906 TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
907 pw.println();
908 pw.print("Time since last dispatch: ");
909 TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
910 pw.println();
911 pw.print("Next non-wakeup delivery time: ");
912 TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
913 pw.println();
914 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700915
916 long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
917 long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700918 pw.print("Next non-wakeup alarm: ");
919 TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700920 pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700921 pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700922 pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
Dianne Hackborn998e6082014-09-11 19:13:23 -0700923 pw.print("Num time change events: "); pw.println(mNumTimeChanged);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700924
925 if (mAlarmBatches.size() > 0) {
926 pw.println();
927 pw.print("Pending alarm batches: ");
928 pw.println(mAlarmBatches.size());
929 for (Batch b : mAlarmBatches) {
930 pw.print(b); pw.println(':');
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700931 dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800934
935 pw.println();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700936 pw.print("Past-due non-wakeup alarms: ");
937 if (mPendingNonWakeupAlarms.size() > 0) {
938 pw.println(mPendingNonWakeupAlarms.size());
939 dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf);
940 } else {
941 pw.println("(none)");
942 }
943 pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms);
944 pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw);
945 pw.println();
946 pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw);
947 pw.print(", max non-interactive time: ");
948 TimeUtils.formatDuration(mNonInteractiveTime, pw);
949 pw.println();
950
951 pw.println();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700952 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
Dianne Hackborn81038902012-11-26 17:04:09 -0800953 pw.println();
954
955 if (mLog.dump(pw, " Recent problems", " ")) {
956 pw.println();
957 }
958
959 final FilterStats[] topFilters = new FilterStats[10];
960 final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
961 @Override
962 public int compare(FilterStats lhs, FilterStats rhs) {
963 if (lhs.aggregateTime < rhs.aggregateTime) {
964 return 1;
965 } else if (lhs.aggregateTime > rhs.aggregateTime) {
966 return -1;
967 }
968 return 0;
969 }
970 };
971 int len = 0;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800972 for (int iu=0; iu<mBroadcastStats.size(); iu++) {
973 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
974 for (int ip=0; ip<uidStats.size(); ip++) {
975 BroadcastStats bs = uidStats.valueAt(ip);
976 for (int is=0; is<bs.filterStats.size(); is++) {
977 FilterStats fs = bs.filterStats.valueAt(is);
978 int pos = len > 0
979 ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
980 if (pos < 0) {
981 pos = -pos - 1;
Dianne Hackborn81038902012-11-26 17:04:09 -0800982 }
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800983 if (pos < topFilters.length) {
984 int copylen = topFilters.length - pos - 1;
985 if (copylen > 0) {
986 System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
987 }
988 topFilters[pos] = fs;
989 if (len < topFilters.length) {
990 len++;
991 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800992 }
993 }
994 }
995 }
996 if (len > 0) {
997 pw.println(" Top Alarms:");
998 for (int i=0; i<len; i++) {
999 FilterStats fs = topFilters[i];
1000 pw.print(" ");
1001 if (fs.nesting > 0) pw.print("*ACTIVE* ");
1002 TimeUtils.formatDuration(fs.aggregateTime, pw);
1003 pw.print(" running, "); pw.print(fs.numWakeup);
1004 pw.print(" wakeups, "); pw.print(fs.count);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001005 pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
1006 pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
Dianne Hackborn81038902012-11-26 17:04:09 -08001007 pw.println();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001008 pw.print(" "); pw.print(fs.mTag);
Dianne Hackborn81038902012-11-26 17:04:09 -08001009 pw.println();
1010 }
1011 }
1012
1013 pw.println(" ");
1014 pw.println(" Alarm Stats:");
1015 final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001016 for (int iu=0; iu<mBroadcastStats.size(); iu++) {
1017 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
1018 for (int ip=0; ip<uidStats.size(); ip++) {
1019 BroadcastStats bs = uidStats.valueAt(ip);
1020 pw.print(" ");
1021 if (bs.nesting > 0) pw.print("*ACTIVE* ");
1022 UserHandle.formatUid(pw, bs.mUid);
1023 pw.print(":");
1024 pw.print(bs.mPackageName);
1025 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
1026 pw.print(" running, "); pw.print(bs.numWakeup);
1027 pw.println(" wakeups:");
1028 tmpFilters.clear();
1029 for (int is=0; is<bs.filterStats.size(); is++) {
1030 tmpFilters.add(bs.filterStats.valueAt(is));
1031 }
1032 Collections.sort(tmpFilters, comparator);
1033 for (int i=0; i<tmpFilters.size(); i++) {
1034 FilterStats fs = tmpFilters.get(i);
1035 pw.print(" ");
1036 if (fs.nesting > 0) pw.print("*ACTIVE* ");
1037 TimeUtils.formatDuration(fs.aggregateTime, pw);
1038 pw.print(" "); pw.print(fs.numWakeup);
1039 pw.print(" wakes " ); pw.print(fs.count);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001040 pw.print(" alarms: ");
1041 pw.print(fs.mTag);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001042 pw.println();
1043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 }
1045 }
Christopher Tate18a75f12013-07-01 18:18:59 -07001046
1047 if (WAKEUP_STATS) {
1048 pw.println();
1049 pw.println(" Recent Wakeup History:");
Christopher Tate18a75f12013-07-01 18:18:59 -07001050 long last = -1;
1051 for (WakeupEvent event : mRecentWakeups) {
1052 pw.print(" "); pw.print(sdf.format(new Date(event.when)));
1053 pw.print('|');
1054 if (last < 0) {
1055 pw.print('0');
1056 } else {
1057 pw.print(event.when - last);
1058 }
1059 last = event.when;
1060 pw.print('|'); pw.print(event.uid);
1061 pw.print('|'); pw.print(event.action);
1062 pw.println();
1063 }
1064 pw.println();
1065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 }
1067 }
1068
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001069 private void logBatchesLocked(SimpleDateFormat sdf) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001070 ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
1071 PrintWriter pw = new PrintWriter(bs);
1072 final long nowRTC = System.currentTimeMillis();
1073 final long nowELAPSED = SystemClock.elapsedRealtime();
1074 final int NZ = mAlarmBatches.size();
1075 for (int iz = 0; iz < NZ; iz++) {
1076 Batch bz = mAlarmBatches.get(iz);
1077 pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001078 dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC, sdf);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001079 pw.flush();
1080 Slog.v(TAG, bs.toString());
1081 bs.reset();
1082 }
1083 }
1084
1085 private boolean validateConsistencyLocked() {
1086 if (DEBUG_VALIDATE) {
1087 long lastTime = Long.MIN_VALUE;
1088 final int N = mAlarmBatches.size();
1089 for (int i = 0; i < N; i++) {
1090 Batch b = mAlarmBatches.get(i);
1091 if (b.start >= lastTime) {
1092 // duplicate start times are okay because of standalone batches
1093 lastTime = b.start;
1094 } else {
1095 Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001096 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
1097 logBatchesLocked(sdf);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001098 return false;
1099 }
1100 }
1101 }
1102 return true;
1103 }
1104
Jose Lima235510e2014-08-13 12:50:01 -07001105 private AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
Adrian Roosc42a1e12014-07-07 23:35:53 +02001106 synchronized (mLock) {
1107 return mNextAlarmClockForUser.get(userId);
1108 }
1109 }
1110
1111 /**
1112 * Recomputes the next alarm clock for all users.
1113 */
1114 private void updateNextAlarmClockLocked() {
1115 if (!mNextAlarmClockMayChange) {
1116 return;
1117 }
1118 mNextAlarmClockMayChange = false;
1119
Jose Lima235510e2014-08-13 12:50:01 -07001120 SparseArray<AlarmManager.AlarmClockInfo> nextForUser = mTmpSparseAlarmClockArray;
Adrian Roosc42a1e12014-07-07 23:35:53 +02001121 nextForUser.clear();
1122
1123 final int N = mAlarmBatches.size();
1124 for (int i = 0; i < N; i++) {
1125 ArrayList<Alarm> alarms = mAlarmBatches.get(i).alarms;
1126 final int M = alarms.size();
1127
1128 for (int j = 0; j < M; j++) {
1129 Alarm a = alarms.get(j);
1130 if (a.alarmClock != null) {
1131 final int userId = a.userId;
1132
1133 if (DEBUG_ALARM_CLOCK) {
1134 Log.v(TAG, "Found AlarmClockInfo at " +
Selim Cinek9c4a7072014-11-21 17:44:34 +01001135 formatNextAlarm(getContext(), a.alarmClock, userId) +
Adrian Roosc42a1e12014-07-07 23:35:53 +02001136 " for user " + userId);
1137 }
1138
1139 // Alarms and batches are sorted by time, no need to compare times here.
1140 if (nextForUser.get(userId) == null) {
1141 nextForUser.put(userId, a.alarmClock);
1142 }
1143 }
1144 }
1145 }
1146
1147 // Update mNextAlarmForUser with new values.
1148 final int NN = nextForUser.size();
1149 for (int i = 0; i < NN; i++) {
Jose Lima235510e2014-08-13 12:50:01 -07001150 AlarmManager.AlarmClockInfo newAlarm = nextForUser.valueAt(i);
Adrian Roosc42a1e12014-07-07 23:35:53 +02001151 int userId = nextForUser.keyAt(i);
Jose Lima235510e2014-08-13 12:50:01 -07001152 AlarmManager.AlarmClockInfo currentAlarm = mNextAlarmClockForUser.get(userId);
Adrian Roosc42a1e12014-07-07 23:35:53 +02001153 if (!newAlarm.equals(currentAlarm)) {
1154 updateNextAlarmInfoForUserLocked(userId, newAlarm);
1155 }
1156 }
1157
1158 // Remove users without any alarm clocks scheduled.
1159 final int NNN = mNextAlarmClockForUser.size();
1160 for (int i = NNN - 1; i >= 0; i--) {
1161 int userId = mNextAlarmClockForUser.keyAt(i);
1162 if (nextForUser.get(userId) == null) {
1163 updateNextAlarmInfoForUserLocked(userId, null);
1164 }
1165 }
1166 }
1167
Jose Lima235510e2014-08-13 12:50:01 -07001168 private void updateNextAlarmInfoForUserLocked(int userId,
1169 AlarmManager.AlarmClockInfo alarmClock) {
Adrian Roosc42a1e12014-07-07 23:35:53 +02001170 if (alarmClock != null) {
1171 if (DEBUG_ALARM_CLOCK) {
1172 Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): " +
Selim Cinek9c4a7072014-11-21 17:44:34 +01001173 formatNextAlarm(getContext(), alarmClock, userId));
Adrian Roosc42a1e12014-07-07 23:35:53 +02001174 }
1175 mNextAlarmClockForUser.put(userId, alarmClock);
1176 } else {
1177 if (DEBUG_ALARM_CLOCK) {
1178 Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): None");
1179 }
1180 mNextAlarmClockForUser.remove(userId);
1181 }
1182
1183 mPendingSendNextAlarmClockChangedForUser.put(userId, true);
1184 mHandler.removeMessages(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED);
1185 mHandler.sendEmptyMessage(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED);
1186 }
1187
1188 /**
1189 * Updates NEXT_ALARM_FORMATTED and sends NEXT_ALARM_CLOCK_CHANGED_INTENT for all users
1190 * for which alarm clocks have changed since the last call to this.
1191 *
1192 * Do not call with a lock held. Only call from mHandler's thread.
1193 *
1194 * @see AlarmHandler#SEND_NEXT_ALARM_CLOCK_CHANGED
1195 */
1196 private void sendNextAlarmClockChanged() {
Jose Lima235510e2014-08-13 12:50:01 -07001197 SparseArray<AlarmManager.AlarmClockInfo> pendingUsers = mHandlerSparseAlarmClockArray;
Adrian Roosc42a1e12014-07-07 23:35:53 +02001198 pendingUsers.clear();
1199
1200 synchronized (mLock) {
1201 final int N = mPendingSendNextAlarmClockChangedForUser.size();
1202 for (int i = 0; i < N; i++) {
1203 int userId = mPendingSendNextAlarmClockChangedForUser.keyAt(i);
1204 pendingUsers.append(userId, mNextAlarmClockForUser.get(userId));
1205 }
1206 mPendingSendNextAlarmClockChangedForUser.clear();
1207 }
1208
1209 final int N = pendingUsers.size();
1210 for (int i = 0; i < N; i++) {
1211 int userId = pendingUsers.keyAt(i);
Jose Lima235510e2014-08-13 12:50:01 -07001212 AlarmManager.AlarmClockInfo alarmClock = pendingUsers.valueAt(i);
Adrian Roosc42a1e12014-07-07 23:35:53 +02001213 Settings.System.putStringForUser(getContext().getContentResolver(),
1214 Settings.System.NEXT_ALARM_FORMATTED,
Selim Cinek9c4a7072014-11-21 17:44:34 +01001215 formatNextAlarm(getContext(), alarmClock, userId),
Adrian Roosc42a1e12014-07-07 23:35:53 +02001216 userId);
1217
1218 getContext().sendBroadcastAsUser(NEXT_ALARM_CLOCK_CHANGED_INTENT,
1219 new UserHandle(userId));
1220 }
1221 }
1222
1223 /**
1224 * Formats an alarm like platform/packages/apps/DeskClock used to.
1225 */
Selim Cinek9c4a7072014-11-21 17:44:34 +01001226 private static String formatNextAlarm(final Context context, AlarmManager.AlarmClockInfo info,
1227 int userId) {
1228 String skeleton = DateFormat.is24HourFormat(context, userId) ? "EHm" : "Ehma";
Adrian Roosc42a1e12014-07-07 23:35:53 +02001229 String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
1230 return (info == null) ? "" :
1231 DateFormat.format(pattern, info.getTriggerTime()).toString();
1232 }
1233
Adam Lesinski182f73f2013-12-05 16:48:06 -08001234 void rescheduleKernelAlarmsLocked() {
1235 // Schedule the next upcoming wakeup alarm. If there is a deliverable batch
1236 // prior to that which contains no wakeups, we schedule that as well.
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001237 long nextNonWakeup = 0;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001238 if (mAlarmBatches.size() > 0) {
Christopher Tate81f98822014-12-04 18:27:16 -08001239 // Find the first wakeup alarm and note the following batch as well. We'll be
1240 // choosing a fuzzed delivery time within the first's allowable interval but
1241 // ensuring that it does not encroach on the second's start time, to minimize
1242 // alarm reordering.
1243 Batch firstWakeup = null, nextAfterWakeup = null;
1244 final int N = mAlarmBatches.size();
1245 for (int i = 0; i < N; i++) {
1246 Batch b = mAlarmBatches.get(i);
1247 if (b.hasWakeups()) {
1248 firstWakeup = b;
1249 if (i < N-1) {
1250 nextAfterWakeup = mAlarmBatches.get(i+1);
1251 }
1252 break;
1253 }
1254 }
1255
1256 // There's a subtlety here: we depend on the invariant that if two batches
1257 // exist with the same start time, the one with the shorter delivery window
1258 // is sorted before the other. This guarantees us that we need only look
1259 // at the first [relevant] batch in the queue in order to schedule an alarm
1260 // appropriately.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001261 final Batch firstBatch = mAlarmBatches.get(0);
Christopher Tate81f98822014-12-04 18:27:16 -08001262 if (firstWakeup != null && mNextWakeupBatchStart != firstWakeup.start) {
1263 mNextWakeupBatchStart = mNextWakeup = firstWakeup.start;
1264 final long windowEnd = (nextAfterWakeup == null)
1265 ? firstWakeup.end
1266 : Math.min(firstWakeup.end, nextAfterWakeup.start);
1267 final long interval = windowEnd - firstWakeup.start;
1268 // if the interval is over maxint we're into crazy land anyway, but
1269 // just in case we check and don't fuzz if the conversion to int for
1270 // random-number purposes would blow up
1271 if (interval > 0 && interval < Integer.MAX_VALUE) {
1272 mNextWakeup += mFuzzer.nextInt((int) interval);
1273 }
1274 setLocked(ELAPSED_REALTIME_WAKEUP, mNextWakeup);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001275 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001276 if (firstBatch != firstWakeup) {
1277 nextNonWakeup = firstBatch.start;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001278 }
1279 }
Christopher Tate81f98822014-12-04 18:27:16 -08001280
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001281 if (mPendingNonWakeupAlarms.size() > 0) {
1282 if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
1283 nextNonWakeup = mNextNonWakeupDeliveryTime;
1284 }
1285 }
1286 if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) {
1287 mNextNonWakeup = nextNonWakeup;
1288 setLocked(ELAPSED_REALTIME, nextNonWakeup);
1289 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001290 }
1291
1292 private void removeLocked(PendingIntent operation) {
1293 boolean didRemove = false;
1294 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1295 Batch b = mAlarmBatches.get(i);
1296 didRemove |= b.remove(operation);
1297 if (b.size() == 0) {
1298 mAlarmBatches.remove(i);
1299 }
1300 }
1301
1302 if (didRemove) {
1303 if (DEBUG_BATCH) {
1304 Slog.v(TAG, "remove(operation) changed bounds; rebatching");
1305 }
1306 rebatchAllAlarmsLocked(true);
1307 rescheduleKernelAlarmsLocked();
Adrian Roosc42a1e12014-07-07 23:35:53 +02001308 updateNextAlarmClockLocked();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001309 }
1310 }
1311
1312 void removeLocked(String packageName) {
1313 boolean didRemove = false;
1314 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1315 Batch b = mAlarmBatches.get(i);
1316 didRemove |= b.remove(packageName);
1317 if (b.size() == 0) {
1318 mAlarmBatches.remove(i);
1319 }
1320 }
1321
1322 if (didRemove) {
1323 if (DEBUG_BATCH) {
1324 Slog.v(TAG, "remove(package) changed bounds; rebatching");
1325 }
1326 rebatchAllAlarmsLocked(true);
1327 rescheduleKernelAlarmsLocked();
Adrian Roosc42a1e12014-07-07 23:35:53 +02001328 updateNextAlarmClockLocked();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001329 }
1330 }
1331
1332 void removeUserLocked(int userHandle) {
1333 boolean didRemove = false;
1334 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1335 Batch b = mAlarmBatches.get(i);
1336 didRemove |= b.remove(userHandle);
1337 if (b.size() == 0) {
1338 mAlarmBatches.remove(i);
1339 }
1340 }
1341
1342 if (didRemove) {
1343 if (DEBUG_BATCH) {
1344 Slog.v(TAG, "remove(user) changed bounds; rebatching");
1345 }
1346 rebatchAllAlarmsLocked(true);
1347 rescheduleKernelAlarmsLocked();
Adrian Roosc42a1e12014-07-07 23:35:53 +02001348 updateNextAlarmClockLocked();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001349 }
1350 }
1351
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001352 void interactiveStateChangedLocked(boolean interactive) {
1353 if (mInteractive != interactive) {
1354 mInteractive = interactive;
1355 final long nowELAPSED = SystemClock.elapsedRealtime();
1356 if (interactive) {
1357 if (mPendingNonWakeupAlarms.size() > 0) {
1358 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1359 mTotalDelayTime += thisDelayTime;
1360 if (mMaxDelayTime < thisDelayTime) {
1361 mMaxDelayTime = thisDelayTime;
1362 }
1363 deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
1364 mPendingNonWakeupAlarms.clear();
1365 }
1366 if (mNonInteractiveStartTime > 0) {
1367 long dur = nowELAPSED - mNonInteractiveStartTime;
1368 if (dur > mNonInteractiveTime) {
1369 mNonInteractiveTime = dur;
1370 }
1371 }
1372 } else {
1373 mNonInteractiveStartTime = nowELAPSED;
1374 }
1375 }
1376 }
1377
Adam Lesinski182f73f2013-12-05 16:48:06 -08001378 boolean lookForPackageLocked(String packageName) {
1379 for (int i = 0; i < mAlarmBatches.size(); i++) {
1380 Batch b = mAlarmBatches.get(i);
1381 if (b.hasPackage(packageName)) {
1382 return true;
1383 }
1384 }
1385 return false;
1386 }
1387
1388 private void setLocked(int type, long when) {
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -08001389 if (mNativeData != 0) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001390 // The kernel never triggers alarms with negative wakeup times
1391 // so we ensure they are positive.
1392 long alarmSeconds, alarmNanoseconds;
1393 if (when < 0) {
1394 alarmSeconds = 0;
1395 alarmNanoseconds = 0;
1396 } else {
1397 alarmSeconds = when / 1000;
1398 alarmNanoseconds = (when % 1000) * 1000 * 1000;
1399 }
1400
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -08001401 set(mNativeData, type, alarmSeconds, alarmNanoseconds);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001402 } else {
1403 Message msg = Message.obtain();
1404 msg.what = ALARM_EVENT;
1405
1406 mHandler.removeMessages(ALARM_EVENT);
1407 mHandler.sendMessageAtTime(msg, when);
1408 }
1409 }
1410
Dianne Hackborn043fcd92010-10-06 14:27:34 -07001411 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001412 String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 for (int i=list.size()-1; i>=0; i--) {
1414 Alarm a = list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001415 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1416 pw.print(": "); pw.println(a);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001417 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 }
1419 }
Christopher Tatee0a22b32013-07-11 14:43:13 -07001420
1421 private static final String labelForType(int type) {
1422 switch (type) {
1423 case RTC: return "RTC";
1424 case RTC_WAKEUP : return "RTC_WAKEUP";
1425 case ELAPSED_REALTIME : return "ELAPSED";
1426 case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
1427 default:
1428 break;
1429 }
1430 return "--unknown--";
1431 }
1432
1433 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001434 String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) {
Christopher Tatee0a22b32013-07-11 14:43:13 -07001435 for (int i=list.size()-1; i>=0; i--) {
1436 Alarm a = list.get(i);
1437 final String label = labelForType(a.type);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001438 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1439 pw.print(": "); pw.println(a);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001440 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001441 }
1442 }
1443
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001444 private native long init();
1445 private native void close(long nativeData);
1446 private native void set(long nativeData, int type, long seconds, long nanoseconds);
1447 private native int waitForAlarm(long nativeData);
Greg Hackmann38bf5142014-02-19 16:39:36 -08001448 private native int setKernelTime(long nativeData, long millis);
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001449 private native int setKernelTimezone(long nativeData, int minuteswest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001451 boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001452 final long nowRTC) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001453 boolean hasWakeup = false;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001454 // batches are temporally sorted, so we need only pull from the
1455 // start of the list until we either empty it or hit a batch
1456 // that is not yet deliverable
Christopher Tate6578ad12013-09-24 17:12:46 -07001457 while (mAlarmBatches.size() > 0) {
1458 Batch batch = mAlarmBatches.get(0);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001459 if (batch.start > nowELAPSED) {
1460 // Everything else is scheduled for the future
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 break;
1462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463
Christopher Tatee0a22b32013-07-11 14:43:13 -07001464 // We will (re)schedule some alarms now; don't let that interfere
1465 // with delivery of this current batch
1466 mAlarmBatches.remove(0);
Dianne Hackborn390517b2013-05-30 15:03:32 -07001467
Christopher Tatee0a22b32013-07-11 14:43:13 -07001468 final int N = batch.size();
1469 for (int i = 0; i < N; i++) {
1470 Alarm alarm = batch.get(i);
1471 alarm.count = 1;
1472 triggerList.add(alarm);
1473
1474 // Recurring alarms may have passed several alarm intervals while the
1475 // phone was asleep or off, so pass a trigger count when sending them.
1476 if (alarm.repeatInterval > 0) {
1477 // this adjustment will be zero if we're late by
1478 // less than one full repeat interval
1479 alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
1480
1481 // Also schedule its next recurrence
1482 final long delta = alarm.count * alarm.repeatInterval;
1483 final long nextElapsed = alarm.whenElapsed + delta;
Christopher Tate3e04b472013-10-21 17:51:31 -07001484 setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
Christopher Tatee0a22b32013-07-11 14:43:13 -07001485 maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
David Christieebe51fc2013-07-26 13:23:29 -07001486 alarm.repeatInterval, alarm.operation, batch.standalone, true,
Adrian Roosc42a1e12014-07-07 23:35:53 +02001487 alarm.workSource, alarm.alarmClock, alarm.userId);
Christopher Tate864d42e2014-12-02 11:48:53 -08001488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489
Christopher Tate864d42e2014-12-02 11:48:53 -08001490 if (alarm.wakeup) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001491 hasWakeup = true;
1492 }
Adrian Roosc42a1e12014-07-07 23:35:53 +02001493
1494 // We removed an alarm clock. Let the caller recompute the next alarm clock.
1495 if (alarm.alarmClock != null) {
1496 mNextAlarmClockMayChange = true;
1497 }
Dianne Hackborn390517b2013-05-30 15:03:32 -07001498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 }
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001500
Christopher Tate1590f1e2014-10-02 17:27:57 -07001501 // This is a new alarm delivery set; bump the sequence number to indicate that
1502 // all apps' alarm delivery classes should be recalculated.
1503 mCurrentSeq++;
1504 calculateDeliveryPriorities(triggerList);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001505 Collections.sort(triggerList, mAlarmDispatchComparator);
1506
1507 if (localLOGV) {
1508 for (int i=0; i<triggerList.size(); i++) {
1509 Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
1510 }
1511 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001512
1513 return hasWakeup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 }
Christopher Tatee0a22b32013-07-11 14:43:13 -07001515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 /**
1517 * This Comparator sorts Alarms into increasing time order.
1518 */
1519 public static class IncreasingTimeOrder implements Comparator<Alarm> {
1520 public int compare(Alarm a1, Alarm a2) {
1521 long when1 = a1.when;
1522 long when2 = a2.when;
1523 if (when1 - when2 > 0) {
1524 return 1;
1525 }
1526 if (when1 - when2 < 0) {
1527 return -1;
1528 }
1529 return 0;
1530 }
1531 }
1532
1533 private static class Alarm {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001534 public final int type;
1535 public final boolean wakeup;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001536 public final PendingIntent operation;
1537 public final String tag;
1538 public final WorkSource workSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 public int count;
1540 public long when;
Christopher Tate3e04b472013-10-21 17:51:31 -07001541 public long windowLength;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001542 public long whenElapsed; // 'when' in the elapsed time base
1543 public long maxWhen; // also in the elapsed time base
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 public long repeatInterval;
Jose Lima235510e2014-08-13 12:50:01 -07001545 public final AlarmManager.AlarmClockInfo alarmClock;
Adrian Roosc42a1e12014-07-07 23:35:53 +02001546 public final int userId;
Christopher Tate1590f1e2014-10-02 17:27:57 -07001547 public PriorityClass priorityClass;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001548
Christopher Tate3e04b472013-10-21 17:51:31 -07001549 public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
Jose Lima235510e2014-08-13 12:50:01 -07001550 long _interval, PendingIntent _op, WorkSource _ws,
1551 AlarmManager.AlarmClockInfo _info, int _userId) {
Christopher Tatee0a22b32013-07-11 14:43:13 -07001552 type = _type;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001553 wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
1554 || _type == AlarmManager.RTC_WAKEUP;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001555 when = _when;
1556 whenElapsed = _whenElapsed;
Christopher Tate3e04b472013-10-21 17:51:31 -07001557 windowLength = _windowLength;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001558 maxWhen = _maxWhen;
1559 repeatInterval = _interval;
1560 operation = _op;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001561 tag = makeTag(_op, _type);
David Christieebe51fc2013-07-26 13:23:29 -07001562 workSource = _ws;
Adrian Roosc42a1e12014-07-07 23:35:53 +02001563 alarmClock = _info;
1564 userId = _userId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 }
Christopher Tatee0a22b32013-07-11 14:43:13 -07001566
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001567 public static String makeTag(PendingIntent pi, int type) {
1568 return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
1569 ? "*walarm*:" : "*alarm*:");
1570 }
1571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 @Override
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001573 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001574 StringBuilder sb = new StringBuilder(128);
1575 sb.append("Alarm{");
1576 sb.append(Integer.toHexString(System.identityHashCode(this)));
1577 sb.append(" type ");
1578 sb.append(type);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001579 sb.append(" when ");
1580 sb.append(when);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001581 sb.append(" ");
1582 sb.append(operation.getTargetPackage());
1583 sb.append('}');
1584 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 }
1586
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001587 public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
1588 SimpleDateFormat sdf) {
1589 final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
1590 pw.print(prefix); pw.print("tag="); pw.println(tag);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001591 pw.print(prefix); pw.print("type="); pw.print(type);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001592 pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
1593 nowELAPSED, pw);
1594 if (isRtc) {
1595 pw.print(" when="); pw.print(sdf.format(new Date(when)));
1596 } else {
1597 pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw);
1598 }
1599 pw.println();
1600 pw.print(prefix); pw.print("window="); pw.print(windowLength);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001601 pw.print(" repeatInterval="); pw.print(repeatInterval);
1602 pw.print(" count="); pw.println(count);
1603 pw.print(prefix); pw.print("operation="); pw.println(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
1605 }
Christopher Tate18a75f12013-07-01 18:18:59 -07001606
Christopher Tatee0a22b32013-07-11 14:43:13 -07001607 void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
1608 final int numBatches = batches.size();
Christopher Tatee982faf2013-07-19 14:51:44 -07001609 for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
1610 Batch b = batches.get(nextBatch);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001611 if (b.start > nowELAPSED) {
Christopher Tate18a75f12013-07-01 18:18:59 -07001612 break;
1613 }
1614
Christopher Tatee0a22b32013-07-11 14:43:13 -07001615 final int numAlarms = b.alarms.size();
Christopher Tatee982faf2013-07-19 14:51:44 -07001616 for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
1617 Alarm a = b.alarms.get(nextAlarm);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001618 WakeupEvent e = new WakeupEvent(nowRTC,
1619 a.operation.getCreatorUid(),
1620 a.operation.getIntent().getAction());
1621 mRecentWakeups.add(e);
1622 }
Christopher Tate18a75f12013-07-01 18:18:59 -07001623 }
1624 }
1625
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001626 long currentNonWakeupFuzzLocked(long nowELAPSED) {
1627 long timeSinceOn = nowELAPSED - mNonInteractiveStartTime;
1628 if (timeSinceOn < 5*60*1000) {
1629 // If the screen has been off for 5 minutes, only delay by at most two minutes.
1630 return 2*60*1000;
1631 } else if (timeSinceOn < 30*60*1000) {
1632 // If the screen has been off for 30 minutes, only delay by at most 15 minutes.
1633 return 15*60*1000;
1634 } else {
1635 // Otherwise, we will delay by at most an hour.
1636 return 60*60*1000;
1637 }
1638 }
1639
1640 boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
1641 if (mInteractive) {
1642 return false;
1643 }
1644 if (mLastAlarmDeliveryTime <= 0) {
1645 return false;
1646 }
1647 if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) {
1648 // This is just a little paranoia, if somehow we have pending non-wakeup alarms
1649 // and the next delivery time is in the past, then just deliver them all. This
1650 // avoids bugs where we get stuck in a loop trying to poll for alarms.
1651 return false;
1652 }
1653 long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime;
1654 return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED);
1655 }
1656
1657 void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
1658 mLastAlarmDeliveryTime = nowELAPSED;
1659 for (int i=0; i<triggerList.size(); i++) {
1660 Alarm alarm = triggerList.get(i);
1661 try {
Christopher Tate2ff5a732014-09-18 13:47:57 -07001662 if (localLOGV) {
1663 Slog.v(TAG, "sending alarm " + alarm);
1664 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001665 alarm.operation.send(getContext(), 0,
1666 mBackgroundIntent.putExtra(
1667 Intent.EXTRA_ALARM_COUNT, alarm.count),
1668 mResultReceiver, mHandler);
1669
1670 // we have an active broadcast so stay awake.
1671 if (mBroadcastRefCount == 0) {
1672 setWakelockWorkSource(alarm.operation, alarm.workSource,
1673 alarm.type, alarm.tag, true);
1674 mWakeLock.acquire();
1675 }
1676 final InFlight inflight = new InFlight(AlarmManagerService.this,
1677 alarm.operation, alarm.workSource, alarm.type, alarm.tag);
1678 mInFlight.add(inflight);
1679 mBroadcastRefCount++;
1680
1681 final BroadcastStats bs = inflight.mBroadcastStats;
1682 bs.count++;
1683 if (bs.nesting == 0) {
1684 bs.nesting = 1;
1685 bs.startTime = nowELAPSED;
1686 } else {
1687 bs.nesting++;
1688 }
1689 final FilterStats fs = inflight.mFilterStats;
1690 fs.count++;
1691 if (fs.nesting == 0) {
1692 fs.nesting = 1;
1693 fs.startTime = nowELAPSED;
1694 } else {
1695 fs.nesting++;
1696 }
1697 if (alarm.type == ELAPSED_REALTIME_WAKEUP
1698 || alarm.type == RTC_WAKEUP) {
1699 bs.numWakeup++;
1700 fs.numWakeup++;
1701 if (alarm.workSource != null && alarm.workSource.size() > 0) {
1702 for (int wi=0; wi<alarm.workSource.size(); wi++) {
1703 ActivityManagerNative.noteWakeupAlarm(
1704 alarm.operation, alarm.workSource.get(wi),
1705 alarm.workSource.getName(wi));
1706 }
1707 } else {
1708 ActivityManagerNative.noteWakeupAlarm(
1709 alarm.operation, -1, null);
1710 }
1711 }
1712 } catch (PendingIntent.CanceledException e) {
1713 if (alarm.repeatInterval > 0) {
1714 // This IntentSender is no longer valid, but this
1715 // is a repeating alarm, so toss the hoser.
1716 removeImpl(alarm.operation);
1717 }
1718 } catch (RuntimeException e) {
1719 Slog.w(TAG, "Failure sending alarm.", e);
1720 }
1721 }
1722 }
1723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 private class AlarmThread extends Thread
1725 {
1726 public AlarmThread()
1727 {
1728 super("AlarmManager");
1729 }
1730
1731 public void run()
1732 {
Dianne Hackborn390517b2013-05-30 15:03:32 -07001733 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 while (true)
1736 {
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001737 int result = waitForAlarm(mNativeData);
Dianne Hackborn390517b2013-05-30 15:03:32 -07001738
1739 triggerList.clear();
1740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 if ((result & TIME_CHANGED_MASK) != 0) {
Christopher Tate385e4982013-07-23 18:22:29 -07001742 if (DEBUG_BATCH) {
Christopher Tate4cb338d2013-07-26 13:11:31 -07001743 Slog.v(TAG, "Time changed notification from kernel; rebatching");
Christopher Tate385e4982013-07-23 18:22:29 -07001744 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001745 removeImpl(mTimeTickSender);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001746 rebatchAllAlarms();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 mClockReceiver.scheduleTimeTickEvent();
Dianne Hackborn998e6082014-09-11 19:13:23 -07001748 synchronized (mLock) {
1749 mNumTimeChanged++;
1750 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001751 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
Dianne Hackborn89ba6752011-01-23 16:51:16 -08001752 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
1753 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001754 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756
1757 synchronized (mLock) {
1758 final long nowRTC = System.currentTimeMillis();
1759 final long nowELAPSED = SystemClock.elapsedRealtime();
Joe Onorato8a9b2202010-02-26 18:56:32 -08001760 if (localLOGV) Slog.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 TAG, "Checking for alarms... rtc=" + nowRTC
1762 + ", elapsed=" + nowELAPSED);
1763
Christopher Tate18a75f12013-07-01 18:18:59 -07001764 if (WAKEUP_STATS) {
1765 if ((result & IS_WAKEUP_MASK) != 0) {
1766 long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
1767 int n = 0;
1768 for (WakeupEvent event : mRecentWakeups) {
1769 if (event.when > newEarliest) break;
1770 n++; // number of now-stale entries at the list head
1771 }
1772 for (int i = 0; i < n; i++) {
1773 mRecentWakeups.remove();
1774 }
1775
Christopher Tatee0a22b32013-07-11 14:43:13 -07001776 recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
Christopher Tate18a75f12013-07-01 18:18:59 -07001777 }
1778 }
1779
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001780 boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1781 if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
1782 // if there are no wakeup alarms and the screen is off, we can
1783 // delay what we have so far until the future.
1784 if (mPendingNonWakeupAlarms.size() == 0) {
1785 mStartCurrentDelayTime = nowELAPSED;
1786 mNextNonWakeupDeliveryTime = nowELAPSED
1787 + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001789 mPendingNonWakeupAlarms.addAll(triggerList);
1790 mNumDelayedAlarms += triggerList.size();
1791 rescheduleKernelAlarmsLocked();
Adrian Roosc42a1e12014-07-07 23:35:53 +02001792 updateNextAlarmClockLocked();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001793 } else {
1794 // now deliver the alarm intents; if there are pending non-wakeup
1795 // alarms, we need to merge them in to the list. note we don't
1796 // just deliver them first because we generally want non-wakeup
1797 // alarms delivered after wakeup alarms.
1798 rescheduleKernelAlarmsLocked();
Adrian Roosc42a1e12014-07-07 23:35:53 +02001799 updateNextAlarmClockLocked();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001800 if (mPendingNonWakeupAlarms.size() > 0) {
Christopher Tate1590f1e2014-10-02 17:27:57 -07001801 calculateDeliveryPriorities(mPendingNonWakeupAlarms);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001802 triggerList.addAll(mPendingNonWakeupAlarms);
1803 Collections.sort(triggerList, mAlarmDispatchComparator);
1804 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1805 mTotalDelayTime += thisDelayTime;
1806 if (mMaxDelayTime < thisDelayTime) {
1807 mMaxDelayTime = thisDelayTime;
1808 }
1809 mPendingNonWakeupAlarms.clear();
1810 }
1811 deliverAlarmsLocked(triggerList, nowELAPSED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 }
1813 }
1814 }
1815 }
1816 }
Christopher Tatec4a07d12012-04-06 14:19:13 -07001817
David Christieebe51fc2013-07-26 13:23:29 -07001818 /**
1819 * Attribute blame for a WakeLock.
1820 * @param pi PendingIntent to attribute blame to if ws is null.
1821 * @param ws WorkSource to attribute blame.
1822 */
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001823 void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
1824 boolean first) {
Christopher Tatec4a07d12012-04-06 14:19:13 -07001825 try {
Dianne Hackborna1bd7922014-03-21 11:07:11 -07001826 final boolean unimportant = pi == mTimeTickSender;
1827 mWakeLock.setUnimportantForLogging(unimportant);
Dianne Hackborn4590e522014-03-24 13:36:46 -07001828 if (first || mLastWakeLockUnimportantForLogging) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001829 mWakeLock.setHistoryTag(tag);
Dianne Hackborn4590e522014-03-24 13:36:46 -07001830 } else {
1831 mWakeLock.setHistoryTag(null);
1832 }
1833 mLastWakeLockUnimportantForLogging = unimportant;
David Christieebe51fc2013-07-26 13:23:29 -07001834 if (ws != null) {
1835 mWakeLock.setWorkSource(ws);
1836 return;
1837 }
1838
Christopher Tatec4a07d12012-04-06 14:19:13 -07001839 final int uid = ActivityManagerNative.getDefault()
1840 .getUidForIntentSender(pi.getTarget());
1841 if (uid >= 0) {
1842 mWakeLock.setWorkSource(new WorkSource(uid));
1843 return;
1844 }
1845 } catch (Exception e) {
1846 }
1847
1848 // Something went wrong; fall back to attributing the lock to the OS
1849 mWakeLock.setWorkSource(null);
1850 }
1851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 private class AlarmHandler extends Handler {
1853 public static final int ALARM_EVENT = 1;
1854 public static final int MINUTE_CHANGE_EVENT = 2;
1855 public static final int DATE_CHANGE_EVENT = 3;
Adrian Roosc42a1e12014-07-07 23:35:53 +02001856 public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857
1858 public AlarmHandler() {
1859 }
1860
1861 public void handleMessage(Message msg) {
1862 if (msg.what == ALARM_EVENT) {
1863 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1864 synchronized (mLock) {
1865 final long nowRTC = System.currentTimeMillis();
Christopher Tatee0a22b32013-07-11 14:43:13 -07001866 final long nowELAPSED = SystemClock.elapsedRealtime();
1867 triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
Adrian Roosc42a1e12014-07-07 23:35:53 +02001868 updateNextAlarmClockLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 }
Adrian Roosc42a1e12014-07-07 23:35:53 +02001870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 // now trigger the alarms without the lock held
Dianne Hackborn390517b2013-05-30 15:03:32 -07001872 for (int i=0; i<triggerList.size(); i++) {
1873 Alarm alarm = triggerList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 try {
1875 alarm.operation.send();
1876 } catch (PendingIntent.CanceledException e) {
1877 if (alarm.repeatInterval > 0) {
1878 // This IntentSender is no longer valid, but this
1879 // is a repeating alarm, so toss the hoser.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001880 removeImpl(alarm.operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 }
1882 }
1883 }
Adrian Roosc42a1e12014-07-07 23:35:53 +02001884 } else if (msg.what == SEND_NEXT_ALARM_CLOCK_CHANGED) {
1885 sendNextAlarmClockChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 }
1887 }
1888 }
1889
1890 class ClockReceiver extends BroadcastReceiver {
1891 public ClockReceiver() {
1892 IntentFilter filter = new IntentFilter();
1893 filter.addAction(Intent.ACTION_TIME_TICK);
1894 filter.addAction(Intent.ACTION_DATE_CHANGED);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001895 getContext().registerReceiver(this, filter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 }
1897
1898 @Override
1899 public void onReceive(Context context, Intent intent) {
1900 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
Christopher Tate385e4982013-07-23 18:22:29 -07001901 if (DEBUG_BATCH) {
1902 Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
1903 }
1904 scheduleTimeTickEvent();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
1906 // Since the kernel does not keep track of DST, we need to
1907 // reset the TZ information at the beginning of each day
1908 // based off of the current Zone gmt offset + userspace tracked
1909 // daylight savings information.
1910 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
Lavettacn Xiaoc84cc4f2010-08-30 12:47:23 +02001911 int gmtOffset = zone.getOffset(System.currentTimeMillis());
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001912 setKernelTimezone(mNativeData, -(gmtOffset / 60000));
Christopher Tate385e4982013-07-23 18:22:29 -07001913 scheduleDateChangedEvent();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 }
1915 }
1916
1917 public void scheduleTimeTickEvent() {
Paul Westbrook51608a52011-08-25 13:18:54 -07001918 final long currentTime = System.currentTimeMillis();
Sungmin Choi563914a2013-01-10 17:28:40 +09001919 final long nextTime = 60000 * ((currentTime / 60000) + 1);
Paul Westbrook51608a52011-08-25 13:18:54 -07001920
1921 // Schedule this event for the amount of time that it would take to get to
1922 // the top of the next minute.
Sungmin Choi563914a2013-01-10 17:28:40 +09001923 final long tickEventDelay = nextTime - currentTime;
Paul Westbrook51608a52011-08-25 13:18:54 -07001924
David Christieebe51fc2013-07-26 13:23:29 -07001925 final WorkSource workSource = null; // Let system take blame for time tick events.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001926 setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
Adrian Roosc42a1e12014-07-07 23:35:53 +02001927 0, mTimeTickSender, true, workSource, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 }
Christopher Tate385e4982013-07-23 18:22:29 -07001929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 public void scheduleDateChangedEvent() {
1931 Calendar calendar = Calendar.getInstance();
1932 calendar.setTimeInMillis(System.currentTimeMillis());
1933 calendar.set(Calendar.HOUR, 0);
1934 calendar.set(Calendar.MINUTE, 0);
1935 calendar.set(Calendar.SECOND, 0);
1936 calendar.set(Calendar.MILLISECOND, 0);
1937 calendar.add(Calendar.DAY_OF_MONTH, 1);
David Christieebe51fc2013-07-26 13:23:29 -07001938
1939 final WorkSource workSource = null; // Let system take blame for date change events.
Adrian Roosc42a1e12014-07-07 23:35:53 +02001940 setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource,
1941 null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 }
1943 }
1944
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001945 class InteractiveStateReceiver extends BroadcastReceiver {
1946 public InteractiveStateReceiver() {
1947 IntentFilter filter = new IntentFilter();
1948 filter.addAction(Intent.ACTION_SCREEN_OFF);
1949 filter.addAction(Intent.ACTION_SCREEN_ON);
1950 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
1951 getContext().registerReceiver(this, filter);
1952 }
1953
1954 @Override
1955 public void onReceive(Context context, Intent intent) {
1956 synchronized (mLock) {
1957 interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
1958 }
1959 }
1960 }
1961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 class UninstallReceiver extends BroadcastReceiver {
1963 public UninstallReceiver() {
1964 IntentFilter filter = new IntentFilter();
1965 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1966 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001967 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 filter.addDataScheme("package");
Adam Lesinski182f73f2013-12-05 16:48:06 -08001969 getContext().registerReceiver(this, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001970 // Register for events related to sdcard installation.
1971 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001972 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001973 sdFilter.addAction(Intent.ACTION_USER_STOPPED);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001974 getContext().registerReceiver(this, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 }
1976
1977 @Override
1978 public void onReceive(Context context, Intent intent) {
1979 synchronized (mLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001980 String action = intent.getAction();
1981 String pkgList[] = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001982 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
1983 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1984 for (String packageName : pkgList) {
1985 if (lookForPackageLocked(packageName)) {
1986 setResultCode(Activity.RESULT_OK);
1987 return;
1988 }
1989 }
1990 return;
1991 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001992 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001993 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
1994 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1995 if (userHandle >= 0) {
1996 removeUserLocked(userHandle);
1997 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001998 } else {
Dianne Hackborn409578f2010-03-10 17:23:43 -08001999 if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
2000 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
2001 // This package is being updated; don't kill its alarms.
2002 return;
2003 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002004 Uri data = intent.getData();
2005 if (data != null) {
2006 String pkg = data.getSchemeSpecificPart();
2007 if (pkg != null) {
2008 pkgList = new String[]{pkg};
2009 }
2010 }
2011 }
2012 if (pkgList != null && (pkgList.length > 0)) {
2013 for (String pkg : pkgList) {
2014 removeLocked(pkg);
Christopher Tate1590f1e2014-10-02 17:27:57 -07002015 mPriorities.remove(pkg);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08002016 for (int i=mBroadcastStats.size()-1; i>=0; i--) {
2017 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
2018 if (uidStats.remove(pkg) != null) {
2019 if (uidStats.size() <= 0) {
2020 mBroadcastStats.removeAt(i);
2021 }
2022 }
2023 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002024 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 }
2026 }
2027 }
2028 }
2029
2030 private final BroadcastStats getStatsLocked(PendingIntent pi) {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08002031 String pkg = pi.getCreatorPackage();
2032 int uid = pi.getCreatorUid();
2033 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
2034 if (uidStats == null) {
2035 uidStats = new ArrayMap<String, BroadcastStats>();
2036 mBroadcastStats.put(uid, uidStats);
2037 }
2038 BroadcastStats bs = uidStats.get(pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039 if (bs == null) {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08002040 bs = new BroadcastStats(uid, pkg);
2041 uidStats.put(pkg, bs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 }
2043 return bs;
2044 }
Dianne Hackborn81038902012-11-26 17:04:09 -08002045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 class ResultReceiver implements PendingIntent.OnFinished {
2047 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
2048 String resultData, Bundle resultExtras) {
2049 synchronized (mLock) {
Dianne Hackborn81038902012-11-26 17:04:09 -08002050 InFlight inflight = null;
2051 for (int i=0; i<mInFlight.size(); i++) {
2052 if (mInFlight.get(i).mPendingIntent == pi) {
2053 inflight = mInFlight.remove(i);
2054 break;
2055 }
2056 }
2057 if (inflight != null) {
2058 final long nowELAPSED = SystemClock.elapsedRealtime();
2059 BroadcastStats bs = inflight.mBroadcastStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 bs.nesting--;
2061 if (bs.nesting <= 0) {
2062 bs.nesting = 0;
Dianne Hackborn81038902012-11-26 17:04:09 -08002063 bs.aggregateTime += nowELAPSED - bs.startTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 }
Dianne Hackborn81038902012-11-26 17:04:09 -08002065 FilterStats fs = inflight.mFilterStats;
2066 fs.nesting--;
2067 if (fs.nesting <= 0) {
2068 fs.nesting = 0;
2069 fs.aggregateTime += nowELAPSED - fs.startTime;
2070 }
2071 } else {
2072 mLog.w("No in-flight alarm for " + pi + " " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 }
2074 mBroadcastRefCount--;
2075 if (mBroadcastRefCount == 0) {
2076 mWakeLock.release();
Dianne Hackborn81038902012-11-26 17:04:09 -08002077 if (mInFlight.size() > 0) {
2078 mLog.w("Finished all broadcasts with " + mInFlight.size()
2079 + " remaining inflights");
2080 for (int i=0; i<mInFlight.size(); i++) {
2081 mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
2082 }
2083 mInFlight.clear();
2084 }
Christopher Tatec4a07d12012-04-06 14:19:13 -07002085 } else {
2086 // the next of our alarms is now in flight. reattribute the wakelock.
Dianne Hackborn81038902012-11-26 17:04:09 -08002087 if (mInFlight.size() > 0) {
David Christieebe51fc2013-07-26 13:23:29 -07002088 InFlight inFlight = mInFlight.get(0);
Dianne Hackborne5167ca2014-03-08 14:39:10 -08002089 setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07002090 inFlight.mAlarmType, inFlight.mTag, false);
Christopher Tatec4a07d12012-04-06 14:19:13 -07002091 } else {
2092 // should never happen
Dianne Hackborn81038902012-11-26 17:04:09 -08002093 mLog.w("Alarm wakelock still held but sent queue empty");
Christopher Tatec4a07d12012-04-06 14:19:13 -07002094 mWakeLock.setWorkSource(null);
2095 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 }
2097 }
2098 }
2099 }
2100}