blob: 4ab8a011c995949658b117c154409c2bc61ddec0 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.ActivityManagerNative;
Christopher Tate57ceaaa2013-07-19 16:30:43 -070021import android.app.AlarmManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.app.IAlarmManager;
23import android.app.PendingIntent;
24import android.content.BroadcastReceiver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.net.Uri;
30import android.os.Binder;
31import android.os.Bundle;
32import android.os.Handler;
Adam Lesinski182f73f2013-12-05 16:48:06 -080033import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.Message;
35import android.os.PowerManager;
36import android.os.SystemClock;
37import android.os.SystemProperties;
Dianne Hackborn80a4af22012-08-27 19:18:31 -070038import android.os.UserHandle;
Christopher Tatec4a07d12012-04-06 14:19:13 -070039import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.text.TextUtils;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -080041import android.util.ArrayMap;
Joe Onorato8a9b2202010-02-26 18:56:32 -080042import android.util.Slog;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -080043import android.util.SparseArray;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070044import android.util.TimeUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045
Christopher Tate4cb338d2013-07-26 13:11:31 -070046import java.io.ByteArrayOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import java.io.FileDescriptor;
48import java.io.PrintWriter;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070049import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import java.util.ArrayList;
Dianne Hackborn81038902012-11-26 17:04:09 -080051import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import java.util.Calendar;
53import java.util.Collections;
54import java.util.Comparator;
Mike Lockwood1f7b4132009-11-20 15:12:51 -050055import java.util.Date;
Christopher Tate18a75f12013-07-01 18:18:59 -070056import java.util.LinkedList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import java.util.TimeZone;
58
Christopher Tatee0a22b32013-07-11 14:43:13 -070059import static android.app.AlarmManager.RTC_WAKEUP;
60import static android.app.AlarmManager.RTC;
61import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
62import static android.app.AlarmManager.ELAPSED_REALTIME;
63
Dianne Hackborn81038902012-11-26 17:04:09 -080064import com.android.internal.util.LocalLog;
65
Adam Lesinski182f73f2013-12-05 16:48:06 -080066class AlarmManagerService extends SystemService {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 // The threshold for how long an alarm can be late before we print a
68 // warning message. The time duration is in milliseconds.
69 private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
Christopher Tatee0a22b32013-07-11 14:43:13 -070070
71 private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
72 private static final int RTC_MASK = 1 << RTC;
Adam Lesinski182f73f2013-12-05 16:48:06 -080073 private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
Christopher Tatee0a22b32013-07-11 14:43:13 -070074 private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
Adam Lesinski182f73f2013-12-05 16:48:06 -080075 static final int TIME_CHANGED_MASK = 1 << 16;
76 static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
Christopher Tateb8849c12011-02-08 13:39:01 -080077
Christopher Tatee0a22b32013-07-11 14:43:13 -070078 // Mask for testing whether a given alarm type is wakeup vs non-wakeup
Adam Lesinski182f73f2013-12-05 16:48:06 -080079 static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
Christopher Tateb8849c12011-02-08 13:39:01 -080080
Adam Lesinski182f73f2013-12-05 16:48:06 -080081 static final String TAG = "AlarmManager";
82 static final String ClockReceiver_TAG = "ClockReceiver";
83 static final boolean localLOGV = false;
84 static final boolean DEBUG_BATCH = localLOGV || false;
85 static final boolean DEBUG_VALIDATE = localLOGV || false;
86 static final int ALARM_EVENT = 1;
87 static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
Adam Lesinski182f73f2013-12-05 16:48:06 -080089 static final Intent mBackgroundIntent
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
Adam Lesinski182f73f2013-12-05 16:48:06 -080091 static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
Adam Lesinski182f73f2013-12-05 16:48:06 -080093 static final boolean WAKEUP_STATS = false;
Christopher Tate18a75f12013-07-01 18:18:59 -070094
Adam Lesinski182f73f2013-12-05 16:48:06 -080095 final LocalLog mLog = new LocalLog(TAG);
Dianne Hackborn81038902012-11-26 17:04:09 -080096
Adam Lesinski182f73f2013-12-05 16:48:06 -080097 final Object mLock = new Object();
Dianne Hackborn81038902012-11-26 17:04:09 -080098
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -080099 long mNativeData;
Christopher Tatee0a22b32013-07-11 14:43:13 -0700100 private long mNextWakeup;
101 private long mNextNonWakeup;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800102 int mBroadcastRefCount = 0;
103 PowerManager.WakeLock mWakeLock;
Dianne Hackborna1bd7922014-03-21 11:07:11 -0700104 boolean mLastWakeLockUnimportantForLogging;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700105 ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800106 ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
107 final AlarmHandler mHandler = new AlarmHandler();
108 ClockReceiver mClockReceiver;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700109 InteractiveStateReceiver mInteractiveStateReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private UninstallReceiver mUninstallReceiver;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800111 final ResultReceiver mResultReceiver = new ResultReceiver();
112 PendingIntent mTimeTickSender;
113 PendingIntent mDateChangeSender;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700114 boolean mInteractive = true;
115 long mNonInteractiveStartTime;
116 long mNonInteractiveTime;
117 long mLastAlarmDeliveryTime;
118 long mStartCurrentDelayTime;
119 long mNextNonWakeupDeliveryTime;
Dianne Hackborn81038902012-11-26 17:04:09 -0800120
Christopher Tate18a75f12013-07-01 18:18:59 -0700121 class WakeupEvent {
122 public long when;
123 public int uid;
124 public String action;
125
126 public WakeupEvent(long theTime, int theUid, String theAction) {
127 when = theTime;
128 uid = theUid;
129 action = theAction;
130 }
131 }
132
Adam Lesinski182f73f2013-12-05 16:48:06 -0800133 final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
134 final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
Christopher Tate18a75f12013-07-01 18:18:59 -0700135
Christopher Tatee0a22b32013-07-11 14:43:13 -0700136 static final class Batch {
137 long start; // These endpoints are always in ELAPSED
138 long end;
139 boolean standalone; // certain "batches" don't participate in coalescing
140
141 final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
142
143 Batch() {
144 start = 0;
145 end = Long.MAX_VALUE;
146 }
147
148 Batch(Alarm seed) {
149 start = seed.whenElapsed;
150 end = seed.maxWhen;
151 alarms.add(seed);
152 }
153
154 int size() {
155 return alarms.size();
156 }
157
158 Alarm get(int index) {
159 return alarms.get(index);
160 }
161
162 boolean canHold(long whenElapsed, long maxWhen) {
163 return (end >= whenElapsed) && (start <= maxWhen);
164 }
165
166 boolean add(Alarm alarm) {
167 boolean newStart = false;
168 // narrows the batch if necessary; presumes that canHold(alarm) is true
169 int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder);
170 if (index < 0) {
171 index = 0 - index - 1;
172 }
173 alarms.add(index, alarm);
174 if (DEBUG_BATCH) {
175 Slog.v(TAG, "Adding " + alarm + " to " + this);
176 }
177 if (alarm.whenElapsed > start) {
178 start = alarm.whenElapsed;
179 newStart = true;
180 }
181 if (alarm.maxWhen < end) {
182 end = alarm.maxWhen;
183 }
184
185 if (DEBUG_BATCH) {
186 Slog.v(TAG, " => now " + this);
187 }
188 return newStart;
189 }
190
191 boolean remove(final PendingIntent operation) {
192 boolean didRemove = false;
193 long newStart = 0; // recalculate endpoints as we go
194 long newEnd = Long.MAX_VALUE;
Christopher Tateae269d52013-09-26 13:11:55 -0700195 for (int i = 0; i < alarms.size(); ) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700196 Alarm alarm = alarms.get(i);
197 if (alarm.operation.equals(operation)) {
198 alarms.remove(i);
199 didRemove = true;
200 } else {
201 if (alarm.whenElapsed > newStart) {
202 newStart = alarm.whenElapsed;
203 }
204 if (alarm.maxWhen < newEnd) {
205 newEnd = alarm.maxWhen;
206 }
207 i++;
208 }
209 }
210 if (didRemove) {
211 // commit the new batch bounds
212 start = newStart;
213 end = newEnd;
214 }
215 return didRemove;
216 }
217
218 boolean remove(final String packageName) {
219 boolean didRemove = false;
220 long newStart = 0; // recalculate endpoints as we go
221 long newEnd = Long.MAX_VALUE;
Christopher Tateae269d52013-09-26 13:11:55 -0700222 for (int i = 0; i < alarms.size(); ) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700223 Alarm alarm = alarms.get(i);
224 if (alarm.operation.getTargetPackage().equals(packageName)) {
225 alarms.remove(i);
226 didRemove = true;
227 } else {
228 if (alarm.whenElapsed > newStart) {
229 newStart = alarm.whenElapsed;
230 }
231 if (alarm.maxWhen < newEnd) {
232 newEnd = alarm.maxWhen;
233 }
234 i++;
235 }
236 }
237 if (didRemove) {
238 // commit the new batch bounds
239 start = newStart;
240 end = newEnd;
241 }
242 return didRemove;
243 }
244
245 boolean remove(final int userHandle) {
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 (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
252 alarms.remove(i);
253 didRemove = true;
254 } else {
255 if (alarm.whenElapsed > newStart) {
256 newStart = alarm.whenElapsed;
257 }
258 if (alarm.maxWhen < newEnd) {
259 newEnd = alarm.maxWhen;
260 }
261 i++;
262 }
263 }
264 if (didRemove) {
265 // commit the new batch bounds
266 start = newStart;
267 end = newEnd;
268 }
269 return didRemove;
270 }
271
272 boolean hasPackage(final String packageName) {
273 final int N = alarms.size();
274 for (int i = 0; i < N; i++) {
275 Alarm a = alarms.get(i);
276 if (a.operation.getTargetPackage().equals(packageName)) {
277 return true;
278 }
279 }
280 return false;
281 }
282
283 boolean hasWakeups() {
284 final int N = alarms.size();
285 for (int i = 0; i < N; i++) {
286 Alarm a = alarms.get(i);
287 // non-wakeup alarms are types 1 and 3, i.e. have the low bit set
288 if ((a.type & TYPE_NONWAKEUP_MASK) == 0) {
289 return true;
290 }
291 }
292 return false;
293 }
294
295 @Override
296 public String toString() {
297 StringBuilder b = new StringBuilder(40);
298 b.append("Batch{"); b.append(Integer.toHexString(this.hashCode()));
299 b.append(" num="); b.append(size());
300 b.append(" start="); b.append(start);
301 b.append(" end="); b.append(end);
302 if (standalone) {
303 b.append(" STANDALONE");
304 }
305 b.append('}');
306 return b.toString();
307 }
308 }
309
310 static class BatchTimeOrder implements Comparator<Batch> {
311 public int compare(Batch b1, Batch b2) {
312 long when1 = b1.start;
313 long when2 = b2.start;
314 if (when1 - when2 > 0) {
315 return 1;
316 }
317 if (when1 - when2 < 0) {
318 return -1;
319 }
320 return 0;
321 }
322 }
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800323
324 final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
325 @Override
326 public int compare(Alarm lhs, Alarm rhs) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700327 if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage()))
328 && lhs.wakeup != rhs.wakeup) {
329 // We want to put wakeup alarms before non-wakeup alarms, since they are
330 // the things that drive most activity in the alarm manager. However,
331 // alarms from the same package should always be ordered strictly by time.
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800332 return lhs.wakeup ? -1 : 1;
333 }
334 if (lhs.whenElapsed < rhs.whenElapsed) {
335 return -1;
336 } else if (lhs.whenElapsed > rhs.whenElapsed) {
337 return 1;
338 }
339 return 0;
340 }
341 };
342
Christopher Tatee0a22b32013-07-11 14:43:13 -0700343 // minimum recurrence period or alarm futurity for us to be able to fuzz it
Adam Lesinski182f73f2013-12-05 16:48:06 -0800344 static final long MIN_FUZZABLE_INTERVAL = 10000;
345 static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
346 final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
Christopher Tatee0a22b32013-07-11 14:43:13 -0700347
Jeff Brownb880d882014-02-10 19:47:07 -0800348 public AlarmManagerService(Context context) {
349 super(context);
350 }
351
Christopher Tatee0a22b32013-07-11 14:43:13 -0700352 static long convertToElapsed(long when, int type) {
353 final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
354 if (isRtc) {
355 when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
356 }
357 return when;
358 }
359
360 // Apply a heuristic to { recurrence interval, futurity of the trigger time } to
361 // calculate the end of our nominal delivery window for the alarm.
362 static long maxTriggerTime(long now, long triggerAtTime, long interval) {
363 // Current heuristic: batchable window is 75% of either the recurrence interval
364 // [for a periodic alarm] or of the time from now to the desired delivery time,
365 // with a minimum delay/interval of 10 seconds, under which we will simply not
366 // defer the alarm.
367 long futurity = (interval == 0)
368 ? (triggerAtTime - now)
369 : interval;
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700370 if (futurity < MIN_FUZZABLE_INTERVAL) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700371 futurity = 0;
372 }
373 return triggerAtTime + (long)(.75 * futurity);
374 }
375
376 // returns true if the batch was added at the head
377 static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) {
378 int index = Collections.binarySearch(list, newBatch, sBatchOrder);
379 if (index < 0) {
380 index = 0 - index - 1;
381 }
382 list.add(index, newBatch);
383 return (index == 0);
384 }
385
Christopher Tate385e4982013-07-23 18:22:29 -0700386 // Return the index of the matching batch, or -1 if none found.
387 int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700388 final int N = mAlarmBatches.size();
389 for (int i = 0; i < N; i++) {
390 Batch b = mAlarmBatches.get(i);
391 if (!b.standalone && b.canHold(whenElapsed, maxWhen)) {
Christopher Tate385e4982013-07-23 18:22:29 -0700392 return i;
Christopher Tatee0a22b32013-07-11 14:43:13 -0700393 }
394 }
Christopher Tate385e4982013-07-23 18:22:29 -0700395 return -1;
Christopher Tatee0a22b32013-07-11 14:43:13 -0700396 }
397
398 // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
399 void rebatchAllAlarms() {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700400 synchronized (mLock) {
Christopher Tate4cb338d2013-07-26 13:11:31 -0700401 rebatchAllAlarmsLocked(true);
402 }
403 }
404
405 void rebatchAllAlarmsLocked(boolean doValidate) {
406 ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
407 mAlarmBatches.clear();
408 final long nowElapsed = SystemClock.elapsedRealtime();
409 final int oldBatches = oldSet.size();
410 for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
411 Batch batch = oldSet.get(batchNum);
412 final int N = batch.size();
413 for (int i = 0; i < N; i++) {
414 Alarm a = batch.get(i);
415 long whenElapsed = convertToElapsed(a.when, a.type);
Christopher Tate3e04b472013-10-21 17:51:31 -0700416 final long maxElapsed;
417 if (a.whenElapsed == a.maxWhen) {
418 // Exact
419 maxElapsed = whenElapsed;
420 } else {
421 // Not exact. Preserve any explicit window, otherwise recalculate
422 // the window based on the alarm's new futurity. Note that this
423 // reflects a policy of preferring timely to deferred delivery.
424 maxElapsed = (a.windowLength > 0)
425 ? (whenElapsed + a.windowLength)
426 : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
427 }
428 setImplLocked(a.type, a.when, whenElapsed, a.windowLength, maxElapsed,
David Christieebe51fc2013-07-26 13:23:29 -0700429 a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700430 }
431 }
432 }
433
Adam Lesinski182f73f2013-12-05 16:48:06 -0800434 static final class InFlight extends Intent {
Dianne Hackborn81038902012-11-26 17:04:09 -0800435 final PendingIntent mPendingIntent;
David Christieebe51fc2013-07-26 13:23:29 -0700436 final WorkSource mWorkSource;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700437 final String mTag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800438 final BroadcastStats mBroadcastStats;
439 final FilterStats mFilterStats;
Dianne Hackborne5167ca2014-03-08 14:39:10 -0800440 final int mAlarmType;
Dianne Hackborn81038902012-11-26 17:04:09 -0800441
Dianne Hackborne5167ca2014-03-08 14:39:10 -0800442 InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700443 int alarmType, String tag) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800444 mPendingIntent = pendingIntent;
David Christieebe51fc2013-07-26 13:23:29 -0700445 mWorkSource = workSource;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700446 mTag = tag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800447 mBroadcastStats = service.getStatsLocked(pendingIntent);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700448 FilterStats fs = mBroadcastStats.filterStats.get(mTag);
Dianne Hackborn81038902012-11-26 17:04:09 -0800449 if (fs == null) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700450 fs = new FilterStats(mBroadcastStats, mTag);
451 mBroadcastStats.filterStats.put(mTag, fs);
Dianne Hackborn81038902012-11-26 17:04:09 -0800452 }
453 mFilterStats = fs;
Dianne Hackborne5167ca2014-03-08 14:39:10 -0800454 mAlarmType = alarmType;
Dianne Hackborn81038902012-11-26 17:04:09 -0800455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800457
Adam Lesinski182f73f2013-12-05 16:48:06 -0800458 static final class FilterStats {
Dianne Hackborn81038902012-11-26 17:04:09 -0800459 final BroadcastStats mBroadcastStats;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700460 final String mTag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 long aggregateTime;
Dianne Hackborn81038902012-11-26 17:04:09 -0800463 int count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 int numWakeup;
465 long startTime;
466 int nesting;
Dianne Hackborn81038902012-11-26 17:04:09 -0800467
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700468 FilterStats(BroadcastStats broadcastStats, String tag) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800469 mBroadcastStats = broadcastStats;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700470 mTag = tag;
Dianne Hackborn81038902012-11-26 17:04:09 -0800471 }
472 }
473
Adam Lesinski182f73f2013-12-05 16:48:06 -0800474 static final class BroadcastStats {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800475 final int mUid;
Dianne Hackborn81038902012-11-26 17:04:09 -0800476 final String mPackageName;
477
478 long aggregateTime;
479 int count;
480 int numWakeup;
481 long startTime;
482 int nesting;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700483 final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>();
Dianne Hackborn81038902012-11-26 17:04:09 -0800484
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800485 BroadcastStats(int uid, String packageName) {
486 mUid = uid;
Dianne Hackborn81038902012-11-26 17:04:09 -0800487 mPackageName = packageName;
488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800491 final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
492 = new SparseArray<ArrayMap<String, BroadcastStats>>();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700493
494 int mNumDelayedAlarms = 0;
495 long mTotalDelayTime = 0;
496 long mMaxDelayTime = 0;
497
Adam Lesinski182f73f2013-12-05 16:48:06 -0800498 @Override
499 public void onStart() {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800500 mNativeData = init();
Christopher Tatee0a22b32013-07-11 14:43:13 -0700501 mNextWakeup = mNextNonWakeup = 0;
Robert CH Chou64ba8e42009-11-04 21:38:49 +0800502
503 // We have to set current TimeZone info to kernel
504 // because kernel doesn't keep this after reboot
Adam Lesinski182f73f2013-12-05 16:48:06 -0800505 setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
Robert CH Chou64ba8e42009-11-04 21:38:49 +0800506
Adam Lesinski182f73f2013-12-05 16:48:06 -0800507 PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800508 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800509
Adam Lesinski182f73f2013-12-05 16:48:06 -0800510 mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 new Intent(Intent.ACTION_TIME_TICK).addFlags(
Dianne Hackborn3bc8f78d2013-09-19 13:34:35 -0700512 Intent.FLAG_RECEIVER_REGISTERED_ONLY
513 | Intent.FLAG_RECEIVER_FOREGROUND), 0,
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700514 UserHandle.ALL);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800515 Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
516 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800517 mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700518 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519
520 // now that we have initied the driver schedule the alarm
Adam Lesinski182f73f2013-12-05 16:48:06 -0800521 mClockReceiver = new ClockReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 mClockReceiver.scheduleTimeTickEvent();
523 mClockReceiver.scheduleDateChangedEvent();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700524 mInteractiveStateReceiver = new InteractiveStateReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 mUninstallReceiver = new UninstallReceiver();
526
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800527 if (mNativeData != 0) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800528 AlarmThread waitThread = new AlarmThread();
529 waitThread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800531 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800533
534 publishBinderService(Context.ALARM_SERVICE, mService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800536
537 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 protected void finalize() throws Throwable {
539 try {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800540 close(mNativeData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 } finally {
542 super.finalize();
543 }
544 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700545
Adam Lesinski182f73f2013-12-05 16:48:06 -0800546 void setTimeZoneImpl(String tz) {
547 if (TextUtils.isEmpty(tz)) {
548 return;
David Christieebe51fc2013-07-26 13:23:29 -0700549 }
550
Adam Lesinski182f73f2013-12-05 16:48:06 -0800551 TimeZone zone = TimeZone.getTimeZone(tz);
552 // Prevent reentrant calls from stepping on each other when writing
553 // the time zone property
554 boolean timeZoneWasChanged = false;
555 synchronized (this) {
556 String current = SystemProperties.get(TIMEZONE_PROPERTY);
557 if (current == null || !current.equals(zone.getID())) {
558 if (localLOGV) {
559 Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
560 }
561 timeZoneWasChanged = true;
562 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
563 }
564
565 // Update the kernel timezone information
566 // Kernel tracks time offsets as 'minutes west of GMT'
567 int gmtOffset = zone.getOffset(System.currentTimeMillis());
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -0800568 setKernelTimezone(mNativeData, -(gmtOffset / 60000));
Adam Lesinski182f73f2013-12-05 16:48:06 -0800569 }
570
571 TimeZone.setDefault(null);
572
573 if (timeZoneWasChanged) {
574 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
575 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
576 intent.putExtra("time-zone", zone.getID());
577 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700580
Adam Lesinski182f73f2013-12-05 16:48:06 -0800581 void removeImpl(PendingIntent operation) {
582 if (operation == null) {
583 return;
584 }
585 synchronized (mLock) {
586 removeLocked(operation);
587 }
588 }
589
590 void setImpl(int type, long triggerAtTime, long windowLength, long interval,
David Christieebe51fc2013-07-26 13:23:29 -0700591 PendingIntent operation, boolean isStandalone, WorkSource workSource) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800593 Slog.w(TAG, "set/setRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 return;
595 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700596
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700597 // Sanity check the window length. This will catch people mistakenly
598 // trying to pass an end-of-window timestamp rather than a duration.
599 if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
600 Slog.w(TAG, "Window length " + windowLength
601 + "ms suspiciously long; limiting to 1 hour");
602 windowLength = AlarmManager.INTERVAL_HOUR;
603 }
604
Christopher Tatee0a22b32013-07-11 14:43:13 -0700605 if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
606 throw new IllegalArgumentException("Invalid alarm type " + type);
607 }
608
Christopher Tate5f221e82013-07-30 17:13:15 -0700609 if (triggerAtTime < 0) {
610 final long who = Binder.getCallingUid();
611 final long what = Binder.getCallingPid();
612 Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
613 + " pid=" + what);
614 triggerAtTime = 0;
615 }
616
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700617 final long nowElapsed = SystemClock.elapsedRealtime();
618 final long triggerElapsed = convertToElapsed(triggerAtTime, type);
619 final long maxElapsed;
620 if (windowLength == AlarmManager.WINDOW_EXACT) {
621 maxElapsed = triggerElapsed;
622 } else if (windowLength < 0) {
623 maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
624 } else {
625 maxElapsed = triggerElapsed + windowLength;
626 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 synchronized (mLock) {
Christopher Tatee0a22b32013-07-11 14:43:13 -0700629 if (DEBUG_BATCH) {
630 Slog.v(TAG, "set(" + operation + ") : type=" + type
Christopher Tate57ceaaa2013-07-19 16:30:43 -0700631 + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
Christopher Tatee0a22b32013-07-11 14:43:13 -0700632 + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
633 + " interval=" + interval + " standalone=" + isStandalone);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 }
Christopher Tate3e04b472013-10-21 17:51:31 -0700635 setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
David Christieebe51fc2013-07-26 13:23:29 -0700636 interval, operation, isStandalone, true, workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 }
638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639
Christopher Tate3e04b472013-10-21 17:51:31 -0700640 private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
641 long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
642 boolean doValidate, WorkSource workSource) {
643 Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
644 operation, workSource);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700645 removeLocked(operation);
Christopher Tateb8849c12011-02-08 13:39:01 -0800646
Christopher Tate385e4982013-07-23 18:22:29 -0700647 int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
648 if (whichBatch < 0) {
649 Batch batch = new Batch(a);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700650 batch.standalone = isStandalone;
Christopher Tate7d57ed82013-10-25 20:18:03 -0700651 addBatchLocked(mAlarmBatches, batch);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 } else {
Christopher Tate385e4982013-07-23 18:22:29 -0700653 Batch batch = mAlarmBatches.get(whichBatch);
Christopher Tate7d57ed82013-10-25 20:18:03 -0700654 if (batch.add(a)) {
Christopher Tate385e4982013-07-23 18:22:29 -0700655 // The start time of this batch advanced, so batch ordering may
656 // have just been broken. Move it to where it now belongs.
657 mAlarmBatches.remove(whichBatch);
658 addBatchLocked(mAlarmBatches, batch);
659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 }
661
Christopher Tate4cb338d2013-07-26 13:11:31 -0700662 if (DEBUG_VALIDATE) {
Christopher Tate5f221e82013-07-30 17:13:15 -0700663 if (doValidate && !validateConsistencyLocked()) {
664 Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
665 + " when(hex)=" + Long.toHexString(when)
666 + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
667 + " interval=" + interval + " op=" + operation
668 + " standalone=" + isStandalone);
Christopher Tate4cb338d2013-07-26 13:11:31 -0700669 rebatchAllAlarmsLocked(false);
Christopher Tate4cb338d2013-07-26 13:11:31 -0700670 }
671 }
672
Christopher Tate7d57ed82013-10-25 20:18:03 -0700673 rescheduleKernelAlarmsLocked();
Christopher Tatee0a22b32013-07-11 14:43:13 -0700674 }
675
Adam Lesinski182f73f2013-12-05 16:48:06 -0800676 private final IBinder mService = new IAlarmManager.Stub() {
677 @Override
678 public void set(int type, long triggerAtTime, long windowLength, long interval,
679 PendingIntent operation, WorkSource workSource) {
680 if (workSource != null) {
681 getContext().enforceCallingPermission(
682 android.Manifest.permission.UPDATE_DEVICE_STATS,
683 "AlarmManager.set");
Christopher Tate89779822012-08-31 14:40:03 -0700684 }
685
Adam Lesinski182f73f2013-12-05 16:48:06 -0800686 setImpl(type, triggerAtTime, windowLength, interval, operation,
687 false, workSource);
688 }
Christopher Tate89779822012-08-31 14:40:03 -0700689
Adam Lesinski182f73f2013-12-05 16:48:06 -0800690 @Override
Greg Hackmann0cab8962014-02-21 16:35:52 -0800691 public boolean setTime(long millis) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800692 getContext().enforceCallingOrSelfPermission(
693 "android.permission.SET_TIME",
694 "setTime");
695
Greg Hackmann0cab8962014-02-21 16:35:52 -0800696 if (mNativeData == 0) {
697 Slog.w(TAG, "Not setting time since no alarm driver is available.");
698 return false;
Christopher Tate89779822012-08-31 14:40:03 -0700699 }
Greg Hackmann0cab8962014-02-21 16:35:52 -0800700
701 synchronized (mLock) {
702 return setKernelTime(mNativeData, millis) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800705
706 @Override
707 public void setTimeZone(String tz) {
708 getContext().enforceCallingOrSelfPermission(
709 "android.permission.SET_TIME_ZONE",
710 "setTimeZone");
711
712 final long oldId = Binder.clearCallingIdentity();
713 try {
714 setTimeZoneImpl(tz);
715 } finally {
716 Binder.restoreCallingIdentity(oldId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 }
718 }
Christopher Tate4cb338d2013-07-26 13:11:31 -0700719
Adam Lesinski182f73f2013-12-05 16:48:06 -0800720 @Override
721 public void remove(PendingIntent operation) {
722 removeImpl(operation);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 }
Christopher Tate4cb338d2013-07-26 13:11:31 -0700725
Adam Lesinski182f73f2013-12-05 16:48:06 -0800726 @Override
727 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
728 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
729 != PackageManager.PERMISSION_GRANTED) {
730 pw.println("Permission Denial: can't dump AlarmManager from from pid="
731 + Binder.getCallingPid()
732 + ", uid=" + Binder.getCallingUid());
733 return;
Christopher Tate4cb338d2013-07-26 13:11:31 -0700734 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700735
Adam Lesinski182f73f2013-12-05 16:48:06 -0800736 dumpImpl(pw);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700737 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800738 };
Christopher Tate4cb338d2013-07-26 13:11:31 -0700739
Adam Lesinski182f73f2013-12-05 16:48:06 -0800740 void dumpImpl(PrintWriter pw) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 synchronized (mLock) {
742 pw.println("Current Alarm Manager state:");
Christopher Tatee0a22b32013-07-11 14:43:13 -0700743 final long nowRTC = System.currentTimeMillis();
744 final long nowELAPSED = SystemClock.elapsedRealtime();
745 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
746
747 pw.print("nowRTC="); pw.print(nowRTC);
748 pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700749 pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw);
750 pw.println();
751 if (!mInteractive) {
752 pw.print("Time since non-interactive: ");
753 TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw);
754 pw.println();
755 pw.print("Max wakeup delay: ");
756 TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
757 pw.println();
758 pw.print("Time since last dispatch: ");
759 TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
760 pw.println();
761 pw.print("Next non-wakeup delivery time: ");
762 TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
763 pw.println();
764 }
Christopher Tatee0a22b32013-07-11 14:43:13 -0700765
766 long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
767 long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700768 pw.print("Next non-wakeup alarm: ");
769 TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700770 pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700771 pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
Christopher Tatee0a22b32013-07-11 14:43:13 -0700772 pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
773
774 if (mAlarmBatches.size() > 0) {
775 pw.println();
776 pw.print("Pending alarm batches: ");
777 pw.println(mAlarmBatches.size());
778 for (Batch b : mAlarmBatches) {
779 pw.print(b); pw.println(':');
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700780 dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700781 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800783
784 pw.println();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700785 pw.print("Past-due non-wakeup alarms: ");
786 if (mPendingNonWakeupAlarms.size() > 0) {
787 pw.println(mPendingNonWakeupAlarms.size());
788 dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf);
789 } else {
790 pw.println("(none)");
791 }
792 pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms);
793 pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw);
794 pw.println();
795 pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw);
796 pw.print(", max non-interactive time: ");
797 TimeUtils.formatDuration(mNonInteractiveTime, pw);
798 pw.println();
799
800 pw.println();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700801 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
Dianne Hackborn81038902012-11-26 17:04:09 -0800802 pw.println();
803
804 if (mLog.dump(pw, " Recent problems", " ")) {
805 pw.println();
806 }
807
808 final FilterStats[] topFilters = new FilterStats[10];
809 final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
810 @Override
811 public int compare(FilterStats lhs, FilterStats rhs) {
812 if (lhs.aggregateTime < rhs.aggregateTime) {
813 return 1;
814 } else if (lhs.aggregateTime > rhs.aggregateTime) {
815 return -1;
816 }
817 return 0;
818 }
819 };
820 int len = 0;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800821 for (int iu=0; iu<mBroadcastStats.size(); iu++) {
822 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
823 for (int ip=0; ip<uidStats.size(); ip++) {
824 BroadcastStats bs = uidStats.valueAt(ip);
825 for (int is=0; is<bs.filterStats.size(); is++) {
826 FilterStats fs = bs.filterStats.valueAt(is);
827 int pos = len > 0
828 ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
829 if (pos < 0) {
830 pos = -pos - 1;
Dianne Hackborn81038902012-11-26 17:04:09 -0800831 }
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800832 if (pos < topFilters.length) {
833 int copylen = topFilters.length - pos - 1;
834 if (copylen > 0) {
835 System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
836 }
837 topFilters[pos] = fs;
838 if (len < topFilters.length) {
839 len++;
840 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800841 }
842 }
843 }
844 }
845 if (len > 0) {
846 pw.println(" Top Alarms:");
847 for (int i=0; i<len; i++) {
848 FilterStats fs = topFilters[i];
849 pw.print(" ");
850 if (fs.nesting > 0) pw.print("*ACTIVE* ");
851 TimeUtils.formatDuration(fs.aggregateTime, pw);
852 pw.print(" running, "); pw.print(fs.numWakeup);
853 pw.print(" wakeups, "); pw.print(fs.count);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800854 pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
855 pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
Dianne Hackborn81038902012-11-26 17:04:09 -0800856 pw.println();
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700857 pw.print(" "); pw.print(fs.mTag);
Dianne Hackborn81038902012-11-26 17:04:09 -0800858 pw.println();
859 }
860 }
861
862 pw.println(" ");
863 pw.println(" Alarm Stats:");
864 final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800865 for (int iu=0; iu<mBroadcastStats.size(); iu++) {
866 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
867 for (int ip=0; ip<uidStats.size(); ip++) {
868 BroadcastStats bs = uidStats.valueAt(ip);
869 pw.print(" ");
870 if (bs.nesting > 0) pw.print("*ACTIVE* ");
871 UserHandle.formatUid(pw, bs.mUid);
872 pw.print(":");
873 pw.print(bs.mPackageName);
874 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
875 pw.print(" running, "); pw.print(bs.numWakeup);
876 pw.println(" wakeups:");
877 tmpFilters.clear();
878 for (int is=0; is<bs.filterStats.size(); is++) {
879 tmpFilters.add(bs.filterStats.valueAt(is));
880 }
881 Collections.sort(tmpFilters, comparator);
882 for (int i=0; i<tmpFilters.size(); i++) {
883 FilterStats fs = tmpFilters.get(i);
884 pw.print(" ");
885 if (fs.nesting > 0) pw.print("*ACTIVE* ");
886 TimeUtils.formatDuration(fs.aggregateTime, pw);
887 pw.print(" "); pw.print(fs.numWakeup);
888 pw.print(" wakes " ); pw.print(fs.count);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700889 pw.print(" alarms: ");
890 pw.print(fs.mTag);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -0800891 pw.println();
892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 }
894 }
Christopher Tate18a75f12013-07-01 18:18:59 -0700895
896 if (WAKEUP_STATS) {
897 pw.println();
898 pw.println(" Recent Wakeup History:");
Christopher Tate18a75f12013-07-01 18:18:59 -0700899 long last = -1;
900 for (WakeupEvent event : mRecentWakeups) {
901 pw.print(" "); pw.print(sdf.format(new Date(event.when)));
902 pw.print('|');
903 if (last < 0) {
904 pw.print('0');
905 } else {
906 pw.print(event.when - last);
907 }
908 last = event.when;
909 pw.print('|'); pw.print(event.uid);
910 pw.print('|'); pw.print(event.action);
911 pw.println();
912 }
913 pw.println();
914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 }
916 }
917
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700918 private void logBatchesLocked(SimpleDateFormat sdf) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800919 ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
920 PrintWriter pw = new PrintWriter(bs);
921 final long nowRTC = System.currentTimeMillis();
922 final long nowELAPSED = SystemClock.elapsedRealtime();
923 final int NZ = mAlarmBatches.size();
924 for (int iz = 0; iz < NZ; iz++) {
925 Batch bz = mAlarmBatches.get(iz);
926 pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700927 dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC, sdf);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800928 pw.flush();
929 Slog.v(TAG, bs.toString());
930 bs.reset();
931 }
932 }
933
934 private boolean validateConsistencyLocked() {
935 if (DEBUG_VALIDATE) {
936 long lastTime = Long.MIN_VALUE;
937 final int N = mAlarmBatches.size();
938 for (int i = 0; i < N; i++) {
939 Batch b = mAlarmBatches.get(i);
940 if (b.start >= lastTime) {
941 // duplicate start times are okay because of standalone batches
942 lastTime = b.start;
943 } else {
944 Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700945 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
946 logBatchesLocked(sdf);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800947 return false;
948 }
949 }
950 }
951 return true;
952 }
953
954 private Batch findFirstWakeupBatchLocked() {
955 final int N = mAlarmBatches.size();
956 for (int i = 0; i < N; i++) {
957 Batch b = mAlarmBatches.get(i);
958 if (b.hasWakeups()) {
959 return b;
960 }
961 }
962 return null;
963 }
964
965 void rescheduleKernelAlarmsLocked() {
966 // Schedule the next upcoming wakeup alarm. If there is a deliverable batch
967 // prior to that which contains no wakeups, we schedule that as well.
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700968 long nextNonWakeup = 0;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800969 if (mAlarmBatches.size() > 0) {
970 final Batch firstWakeup = findFirstWakeupBatchLocked();
971 final Batch firstBatch = mAlarmBatches.get(0);
972 if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
973 mNextWakeup = firstWakeup.start;
974 setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
975 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700976 if (firstBatch != firstWakeup) {
977 nextNonWakeup = firstBatch.start;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800978 }
979 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -0700980 if (mPendingNonWakeupAlarms.size() > 0) {
981 if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
982 nextNonWakeup = mNextNonWakeupDeliveryTime;
983 }
984 }
985 if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) {
986 mNextNonWakeup = nextNonWakeup;
987 setLocked(ELAPSED_REALTIME, nextNonWakeup);
988 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800989 }
990
991 private void removeLocked(PendingIntent operation) {
992 boolean didRemove = false;
993 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
994 Batch b = mAlarmBatches.get(i);
995 didRemove |= b.remove(operation);
996 if (b.size() == 0) {
997 mAlarmBatches.remove(i);
998 }
999 }
1000
1001 if (didRemove) {
1002 if (DEBUG_BATCH) {
1003 Slog.v(TAG, "remove(operation) changed bounds; rebatching");
1004 }
1005 rebatchAllAlarmsLocked(true);
1006 rescheduleKernelAlarmsLocked();
1007 }
1008 }
1009
1010 void removeLocked(String packageName) {
1011 boolean didRemove = false;
1012 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1013 Batch b = mAlarmBatches.get(i);
1014 didRemove |= b.remove(packageName);
1015 if (b.size() == 0) {
1016 mAlarmBatches.remove(i);
1017 }
1018 }
1019
1020 if (didRemove) {
1021 if (DEBUG_BATCH) {
1022 Slog.v(TAG, "remove(package) changed bounds; rebatching");
1023 }
1024 rebatchAllAlarmsLocked(true);
1025 rescheduleKernelAlarmsLocked();
1026 }
1027 }
1028
1029 void removeUserLocked(int userHandle) {
1030 boolean didRemove = false;
1031 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1032 Batch b = mAlarmBatches.get(i);
1033 didRemove |= b.remove(userHandle);
1034 if (b.size() == 0) {
1035 mAlarmBatches.remove(i);
1036 }
1037 }
1038
1039 if (didRemove) {
1040 if (DEBUG_BATCH) {
1041 Slog.v(TAG, "remove(user) changed bounds; rebatching");
1042 }
1043 rebatchAllAlarmsLocked(true);
1044 rescheduleKernelAlarmsLocked();
1045 }
1046 }
1047
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001048 void interactiveStateChangedLocked(boolean interactive) {
1049 if (mInteractive != interactive) {
1050 mInteractive = interactive;
1051 final long nowELAPSED = SystemClock.elapsedRealtime();
1052 if (interactive) {
1053 if (mPendingNonWakeupAlarms.size() > 0) {
1054 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1055 mTotalDelayTime += thisDelayTime;
1056 if (mMaxDelayTime < thisDelayTime) {
1057 mMaxDelayTime = thisDelayTime;
1058 }
1059 deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
1060 mPendingNonWakeupAlarms.clear();
1061 }
1062 if (mNonInteractiveStartTime > 0) {
1063 long dur = nowELAPSED - mNonInteractiveStartTime;
1064 if (dur > mNonInteractiveTime) {
1065 mNonInteractiveTime = dur;
1066 }
1067 }
1068 } else {
1069 mNonInteractiveStartTime = nowELAPSED;
1070 }
1071 }
1072 }
1073
Adam Lesinski182f73f2013-12-05 16:48:06 -08001074 boolean lookForPackageLocked(String packageName) {
1075 for (int i = 0; i < mAlarmBatches.size(); i++) {
1076 Batch b = mAlarmBatches.get(i);
1077 if (b.hasPackage(packageName)) {
1078 return true;
1079 }
1080 }
1081 return false;
1082 }
1083
1084 private void setLocked(int type, long when) {
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -08001085 if (mNativeData != 0) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001086 // The kernel never triggers alarms with negative wakeup times
1087 // so we ensure they are positive.
1088 long alarmSeconds, alarmNanoseconds;
1089 if (when < 0) {
1090 alarmSeconds = 0;
1091 alarmNanoseconds = 0;
1092 } else {
1093 alarmSeconds = when / 1000;
1094 alarmNanoseconds = (when % 1000) * 1000 * 1000;
1095 }
1096
Greg Hackmannf1bdbdd2013-12-17 11:56:22 -08001097 set(mNativeData, type, alarmSeconds, alarmNanoseconds);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001098 } else {
1099 Message msg = Message.obtain();
1100 msg.what = ALARM_EVENT;
1101
1102 mHandler.removeMessages(ALARM_EVENT);
1103 mHandler.sendMessageAtTime(msg, when);
1104 }
1105 }
1106
Dianne Hackborn043fcd92010-10-06 14:27:34 -07001107 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001108 String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 for (int i=list.size()-1; i>=0; i--) {
1110 Alarm a = list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001111 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1112 pw.print(": "); pw.println(a);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001113 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
1115 }
Christopher Tatee0a22b32013-07-11 14:43:13 -07001116
1117 private static final String labelForType(int type) {
1118 switch (type) {
1119 case RTC: return "RTC";
1120 case RTC_WAKEUP : return "RTC_WAKEUP";
1121 case ELAPSED_REALTIME : return "ELAPSED";
1122 case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
1123 default:
1124 break;
1125 }
1126 return "--unknown--";
1127 }
1128
1129 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001130 String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) {
Christopher Tatee0a22b32013-07-11 14:43:13 -07001131 for (int i=list.size()-1; i>=0; i--) {
1132 Alarm a = list.get(i);
1133 final String label = labelForType(a.type);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001134 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1135 pw.print(": "); pw.println(a);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001136 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001137 }
1138 }
1139
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001140 private native long init();
1141 private native void close(long nativeData);
1142 private native void set(long nativeData, int type, long seconds, long nanoseconds);
1143 private native int waitForAlarm(long nativeData);
Greg Hackmann38bf5142014-02-19 16:39:36 -08001144 private native int setKernelTime(long nativeData, long millis);
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001145 private native int setKernelTimezone(long nativeData, int minuteswest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001147 boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001148 final long nowRTC) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001149 boolean hasWakeup = false;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001150 // batches are temporally sorted, so we need only pull from the
1151 // start of the list until we either empty it or hit a batch
1152 // that is not yet deliverable
Christopher Tate6578ad12013-09-24 17:12:46 -07001153 while (mAlarmBatches.size() > 0) {
1154 Batch batch = mAlarmBatches.get(0);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001155 if (batch.start > nowELAPSED) {
1156 // Everything else is scheduled for the future
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 break;
1158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159
Christopher Tatee0a22b32013-07-11 14:43:13 -07001160 // We will (re)schedule some alarms now; don't let that interfere
1161 // with delivery of this current batch
1162 mAlarmBatches.remove(0);
Dianne Hackborn390517b2013-05-30 15:03:32 -07001163
Christopher Tatee0a22b32013-07-11 14:43:13 -07001164 final int N = batch.size();
1165 for (int i = 0; i < N; i++) {
1166 Alarm alarm = batch.get(i);
1167 alarm.count = 1;
1168 triggerList.add(alarm);
1169
1170 // Recurring alarms may have passed several alarm intervals while the
1171 // phone was asleep or off, so pass a trigger count when sending them.
1172 if (alarm.repeatInterval > 0) {
1173 // this adjustment will be zero if we're late by
1174 // less than one full repeat interval
1175 alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
1176
1177 // Also schedule its next recurrence
1178 final long delta = alarm.count * alarm.repeatInterval;
1179 final long nextElapsed = alarm.whenElapsed + delta;
Christopher Tate3e04b472013-10-21 17:51:31 -07001180 setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
Christopher Tatee0a22b32013-07-11 14:43:13 -07001181 maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
David Christieebe51fc2013-07-26 13:23:29 -07001182 alarm.repeatInterval, alarm.operation, batch.standalone, true,
1183 alarm.workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001185 // For now we count this as a wakeup alarm, meaning it needs to be
1186 // delivered immediately. In the future we should change this, but
1187 // that required delaying when we reschedule the repeat...!
1188 hasWakeup = false;
1189 } else if (alarm.wakeup) {
1190 hasWakeup = true;
1191 }
Dianne Hackborn390517b2013-05-30 15:03:32 -07001192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001194
1195 Collections.sort(triggerList, mAlarmDispatchComparator);
1196
1197 if (localLOGV) {
1198 for (int i=0; i<triggerList.size(); i++) {
1199 Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
1200 }
1201 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001202
1203 return hasWakeup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 }
Christopher Tatee0a22b32013-07-11 14:43:13 -07001205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 /**
1207 * This Comparator sorts Alarms into increasing time order.
1208 */
1209 public static class IncreasingTimeOrder implements Comparator<Alarm> {
1210 public int compare(Alarm a1, Alarm a2) {
1211 long when1 = a1.when;
1212 long when2 = a2.when;
1213 if (when1 - when2 > 0) {
1214 return 1;
1215 }
1216 if (when1 - when2 < 0) {
1217 return -1;
1218 }
1219 return 0;
1220 }
1221 }
1222
1223 private static class Alarm {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001224 public final int type;
1225 public final boolean wakeup;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001226 public final PendingIntent operation;
1227 public final String tag;
1228 public final WorkSource workSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 public int count;
1230 public long when;
Christopher Tate3e04b472013-10-21 17:51:31 -07001231 public long windowLength;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001232 public long whenElapsed; // 'when' in the elapsed time base
1233 public long maxWhen; // also in the elapsed time base
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 public long repeatInterval;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001235
Christopher Tate3e04b472013-10-21 17:51:31 -07001236 public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
David Christieebe51fc2013-07-26 13:23:29 -07001237 long _interval, PendingIntent _op, WorkSource _ws) {
Christopher Tatee0a22b32013-07-11 14:43:13 -07001238 type = _type;
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001239 wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
1240 || _type == AlarmManager.RTC_WAKEUP;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001241 when = _when;
1242 whenElapsed = _whenElapsed;
Christopher Tate3e04b472013-10-21 17:51:31 -07001243 windowLength = _windowLength;
Christopher Tatee0a22b32013-07-11 14:43:13 -07001244 maxWhen = _maxWhen;
1245 repeatInterval = _interval;
1246 operation = _op;
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001247 tag = makeTag(_op, _type);
David Christieebe51fc2013-07-26 13:23:29 -07001248 workSource = _ws;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 }
Christopher Tatee0a22b32013-07-11 14:43:13 -07001250
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001251 public static String makeTag(PendingIntent pi, int type) {
1252 return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
1253 ? "*walarm*:" : "*alarm*:");
1254 }
1255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 @Override
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001257 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001258 StringBuilder sb = new StringBuilder(128);
1259 sb.append("Alarm{");
1260 sb.append(Integer.toHexString(System.identityHashCode(this)));
1261 sb.append(" type ");
1262 sb.append(type);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001263 sb.append(" when ");
1264 sb.append(when);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001265 sb.append(" ");
1266 sb.append(operation.getTargetPackage());
1267 sb.append('}');
1268 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 }
1270
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001271 public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
1272 SimpleDateFormat sdf) {
1273 final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
1274 pw.print(prefix); pw.print("tag="); pw.println(tag);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001275 pw.print(prefix); pw.print("type="); pw.print(type);
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001276 pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
1277 nowELAPSED, pw);
1278 if (isRtc) {
1279 pw.print(" when="); pw.print(sdf.format(new Date(when)));
1280 } else {
1281 pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw);
1282 }
1283 pw.println();
1284 pw.print(prefix); pw.print("window="); pw.print(windowLength);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001285 pw.print(" repeatInterval="); pw.print(repeatInterval);
1286 pw.print(" count="); pw.println(count);
1287 pw.print(prefix); pw.print("operation="); pw.println(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 }
1289 }
Christopher Tate18a75f12013-07-01 18:18:59 -07001290
Christopher Tatee0a22b32013-07-11 14:43:13 -07001291 void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
1292 final int numBatches = batches.size();
Christopher Tatee982faf2013-07-19 14:51:44 -07001293 for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
1294 Batch b = batches.get(nextBatch);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001295 if (b.start > nowELAPSED) {
Christopher Tate18a75f12013-07-01 18:18:59 -07001296 break;
1297 }
1298
Christopher Tatee0a22b32013-07-11 14:43:13 -07001299 final int numAlarms = b.alarms.size();
Christopher Tatee982faf2013-07-19 14:51:44 -07001300 for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
1301 Alarm a = b.alarms.get(nextAlarm);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001302 WakeupEvent e = new WakeupEvent(nowRTC,
1303 a.operation.getCreatorUid(),
1304 a.operation.getIntent().getAction());
1305 mRecentWakeups.add(e);
1306 }
Christopher Tate18a75f12013-07-01 18:18:59 -07001307 }
1308 }
1309
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001310 long currentNonWakeupFuzzLocked(long nowELAPSED) {
1311 long timeSinceOn = nowELAPSED - mNonInteractiveStartTime;
1312 if (timeSinceOn < 5*60*1000) {
1313 // If the screen has been off for 5 minutes, only delay by at most two minutes.
1314 return 2*60*1000;
1315 } else if (timeSinceOn < 30*60*1000) {
1316 // If the screen has been off for 30 minutes, only delay by at most 15 minutes.
1317 return 15*60*1000;
1318 } else {
1319 // Otherwise, we will delay by at most an hour.
1320 return 60*60*1000;
1321 }
1322 }
1323
1324 boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
1325 if (mInteractive) {
1326 return false;
1327 }
1328 if (mLastAlarmDeliveryTime <= 0) {
1329 return false;
1330 }
1331 if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) {
1332 // This is just a little paranoia, if somehow we have pending non-wakeup alarms
1333 // and the next delivery time is in the past, then just deliver them all. This
1334 // avoids bugs where we get stuck in a loop trying to poll for alarms.
1335 return false;
1336 }
1337 long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime;
1338 return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED);
1339 }
1340
1341 void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
1342 mLastAlarmDeliveryTime = nowELAPSED;
1343 for (int i=0; i<triggerList.size(); i++) {
1344 Alarm alarm = triggerList.get(i);
1345 try {
1346 if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
1347 alarm.operation.send(getContext(), 0,
1348 mBackgroundIntent.putExtra(
1349 Intent.EXTRA_ALARM_COUNT, alarm.count),
1350 mResultReceiver, mHandler);
1351
1352 // we have an active broadcast so stay awake.
1353 if (mBroadcastRefCount == 0) {
1354 setWakelockWorkSource(alarm.operation, alarm.workSource,
1355 alarm.type, alarm.tag, true);
1356 mWakeLock.acquire();
1357 }
1358 final InFlight inflight = new InFlight(AlarmManagerService.this,
1359 alarm.operation, alarm.workSource, alarm.type, alarm.tag);
1360 mInFlight.add(inflight);
1361 mBroadcastRefCount++;
1362
1363 final BroadcastStats bs = inflight.mBroadcastStats;
1364 bs.count++;
1365 if (bs.nesting == 0) {
1366 bs.nesting = 1;
1367 bs.startTime = nowELAPSED;
1368 } else {
1369 bs.nesting++;
1370 }
1371 final FilterStats fs = inflight.mFilterStats;
1372 fs.count++;
1373 if (fs.nesting == 0) {
1374 fs.nesting = 1;
1375 fs.startTime = nowELAPSED;
1376 } else {
1377 fs.nesting++;
1378 }
1379 if (alarm.type == ELAPSED_REALTIME_WAKEUP
1380 || alarm.type == RTC_WAKEUP) {
1381 bs.numWakeup++;
1382 fs.numWakeup++;
1383 if (alarm.workSource != null && alarm.workSource.size() > 0) {
1384 for (int wi=0; wi<alarm.workSource.size(); wi++) {
1385 ActivityManagerNative.noteWakeupAlarm(
1386 alarm.operation, alarm.workSource.get(wi),
1387 alarm.workSource.getName(wi));
1388 }
1389 } else {
1390 ActivityManagerNative.noteWakeupAlarm(
1391 alarm.operation, -1, null);
1392 }
1393 }
1394 } catch (PendingIntent.CanceledException e) {
1395 if (alarm.repeatInterval > 0) {
1396 // This IntentSender is no longer valid, but this
1397 // is a repeating alarm, so toss the hoser.
1398 removeImpl(alarm.operation);
1399 }
1400 } catch (RuntimeException e) {
1401 Slog.w(TAG, "Failure sending alarm.", e);
1402 }
1403 }
1404 }
1405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 private class AlarmThread extends Thread
1407 {
1408 public AlarmThread()
1409 {
1410 super("AlarmManager");
1411 }
1412
1413 public void run()
1414 {
Dianne Hackborn390517b2013-05-30 15:03:32 -07001415 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 while (true)
1418 {
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001419 int result = waitForAlarm(mNativeData);
Dianne Hackborn390517b2013-05-30 15:03:32 -07001420
1421 triggerList.clear();
1422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 if ((result & TIME_CHANGED_MASK) != 0) {
Christopher Tate385e4982013-07-23 18:22:29 -07001424 if (DEBUG_BATCH) {
Christopher Tate4cb338d2013-07-26 13:11:31 -07001425 Slog.v(TAG, "Time changed notification from kernel; rebatching");
Christopher Tate385e4982013-07-23 18:22:29 -07001426 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001427 removeImpl(mTimeTickSender);
Christopher Tatee0a22b32013-07-11 14:43:13 -07001428 rebatchAllAlarms();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 mClockReceiver.scheduleTimeTickEvent();
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001430 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
Dianne Hackborn89ba6752011-01-23 16:51:16 -08001431 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
1432 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001433 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 }
1435
1436 synchronized (mLock) {
1437 final long nowRTC = System.currentTimeMillis();
1438 final long nowELAPSED = SystemClock.elapsedRealtime();
Joe Onorato8a9b2202010-02-26 18:56:32 -08001439 if (localLOGV) Slog.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 TAG, "Checking for alarms... rtc=" + nowRTC
1441 + ", elapsed=" + nowELAPSED);
1442
Christopher Tate18a75f12013-07-01 18:18:59 -07001443 if (WAKEUP_STATS) {
1444 if ((result & IS_WAKEUP_MASK) != 0) {
1445 long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
1446 int n = 0;
1447 for (WakeupEvent event : mRecentWakeups) {
1448 if (event.when > newEarliest) break;
1449 n++; // number of now-stale entries at the list head
1450 }
1451 for (int i = 0; i < n; i++) {
1452 mRecentWakeups.remove();
1453 }
1454
Christopher Tatee0a22b32013-07-11 14:43:13 -07001455 recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
Christopher Tate18a75f12013-07-01 18:18:59 -07001456 }
1457 }
1458
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001459 boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1460 if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
1461 // if there are no wakeup alarms and the screen is off, we can
1462 // delay what we have so far until the future.
1463 if (mPendingNonWakeupAlarms.size() == 0) {
1464 mStartCurrentDelayTime = nowELAPSED;
1465 mNextNonWakeupDeliveryTime = nowELAPSED
1466 + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 }
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001468 mPendingNonWakeupAlarms.addAll(triggerList);
1469 mNumDelayedAlarms += triggerList.size();
1470 rescheduleKernelAlarmsLocked();
1471 } else {
1472 // now deliver the alarm intents; if there are pending non-wakeup
1473 // alarms, we need to merge them in to the list. note we don't
1474 // just deliver them first because we generally want non-wakeup
1475 // alarms delivered after wakeup alarms.
1476 rescheduleKernelAlarmsLocked();
1477 if (mPendingNonWakeupAlarms.size() > 0) {
1478 triggerList.addAll(mPendingNonWakeupAlarms);
1479 Collections.sort(triggerList, mAlarmDispatchComparator);
1480 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1481 mTotalDelayTime += thisDelayTime;
1482 if (mMaxDelayTime < thisDelayTime) {
1483 mMaxDelayTime = thisDelayTime;
1484 }
1485 mPendingNonWakeupAlarms.clear();
1486 }
1487 deliverAlarmsLocked(triggerList, nowELAPSED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 }
1489 }
1490 }
1491 }
1492 }
Christopher Tatec4a07d12012-04-06 14:19:13 -07001493
David Christieebe51fc2013-07-26 13:23:29 -07001494 /**
1495 * Attribute blame for a WakeLock.
1496 * @param pi PendingIntent to attribute blame to if ws is null.
1497 * @param ws WorkSource to attribute blame.
1498 */
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001499 void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
1500 boolean first) {
Christopher Tatec4a07d12012-04-06 14:19:13 -07001501 try {
Dianne Hackborna1bd7922014-03-21 11:07:11 -07001502 final boolean unimportant = pi == mTimeTickSender;
1503 mWakeLock.setUnimportantForLogging(unimportant);
Dianne Hackborn4590e522014-03-24 13:36:46 -07001504 if (first || mLastWakeLockUnimportantForLogging) {
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001505 mWakeLock.setHistoryTag(tag);
Dianne Hackborn4590e522014-03-24 13:36:46 -07001506 } else {
1507 mWakeLock.setHistoryTag(null);
1508 }
1509 mLastWakeLockUnimportantForLogging = unimportant;
David Christieebe51fc2013-07-26 13:23:29 -07001510 if (ws != null) {
1511 mWakeLock.setWorkSource(ws);
1512 return;
1513 }
1514
Christopher Tatec4a07d12012-04-06 14:19:13 -07001515 final int uid = ActivityManagerNative.getDefault()
1516 .getUidForIntentSender(pi.getTarget());
1517 if (uid >= 0) {
1518 mWakeLock.setWorkSource(new WorkSource(uid));
1519 return;
1520 }
1521 } catch (Exception e) {
1522 }
1523
1524 // Something went wrong; fall back to attributing the lock to the OS
1525 mWakeLock.setWorkSource(null);
1526 }
1527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 private class AlarmHandler extends Handler {
1529 public static final int ALARM_EVENT = 1;
1530 public static final int MINUTE_CHANGE_EVENT = 2;
1531 public static final int DATE_CHANGE_EVENT = 3;
1532
1533 public AlarmHandler() {
1534 }
1535
1536 public void handleMessage(Message msg) {
1537 if (msg.what == ALARM_EVENT) {
1538 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1539 synchronized (mLock) {
1540 final long nowRTC = System.currentTimeMillis();
Christopher Tatee0a22b32013-07-11 14:43:13 -07001541 final long nowELAPSED = SystemClock.elapsedRealtime();
1542 triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 }
1544
1545 // now trigger the alarms without the lock held
Dianne Hackborn390517b2013-05-30 15:03:32 -07001546 for (int i=0; i<triggerList.size(); i++) {
1547 Alarm alarm = triggerList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 try {
1549 alarm.operation.send();
1550 } catch (PendingIntent.CanceledException e) {
1551 if (alarm.repeatInterval > 0) {
1552 // This IntentSender is no longer valid, but this
1553 // is a repeating alarm, so toss the hoser.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001554 removeImpl(alarm.operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
1556 }
1557 }
1558 }
1559 }
1560 }
1561
1562 class ClockReceiver extends BroadcastReceiver {
1563 public ClockReceiver() {
1564 IntentFilter filter = new IntentFilter();
1565 filter.addAction(Intent.ACTION_TIME_TICK);
1566 filter.addAction(Intent.ACTION_DATE_CHANGED);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001567 getContext().registerReceiver(this, filter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 }
1569
1570 @Override
1571 public void onReceive(Context context, Intent intent) {
1572 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
Christopher Tate385e4982013-07-23 18:22:29 -07001573 if (DEBUG_BATCH) {
1574 Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
1575 }
1576 scheduleTimeTickEvent();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
1578 // Since the kernel does not keep track of DST, we need to
1579 // reset the TZ information at the beginning of each day
1580 // based off of the current Zone gmt offset + userspace tracked
1581 // daylight savings information.
1582 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
Lavettacn Xiaoc84cc4f2010-08-30 12:47:23 +02001583 int gmtOffset = zone.getOffset(System.currentTimeMillis());
Greg Hackmanna1d6f922013-12-09 16:56:53 -08001584 setKernelTimezone(mNativeData, -(gmtOffset / 60000));
Christopher Tate385e4982013-07-23 18:22:29 -07001585 scheduleDateChangedEvent();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 }
1587 }
1588
1589 public void scheduleTimeTickEvent() {
Paul Westbrook51608a52011-08-25 13:18:54 -07001590 final long currentTime = System.currentTimeMillis();
Sungmin Choi563914a2013-01-10 17:28:40 +09001591 final long nextTime = 60000 * ((currentTime / 60000) + 1);
Paul Westbrook51608a52011-08-25 13:18:54 -07001592
1593 // Schedule this event for the amount of time that it would take to get to
1594 // the top of the next minute.
Sungmin Choi563914a2013-01-10 17:28:40 +09001595 final long tickEventDelay = nextTime - currentTime;
Paul Westbrook51608a52011-08-25 13:18:54 -07001596
David Christieebe51fc2013-07-26 13:23:29 -07001597 final WorkSource workSource = null; // Let system take blame for time tick events.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001598 setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
David Christieebe51fc2013-07-26 13:23:29 -07001599 0, mTimeTickSender, true, workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 }
Christopher Tate385e4982013-07-23 18:22:29 -07001601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 public void scheduleDateChangedEvent() {
1603 Calendar calendar = Calendar.getInstance();
1604 calendar.setTimeInMillis(System.currentTimeMillis());
1605 calendar.set(Calendar.HOUR, 0);
1606 calendar.set(Calendar.MINUTE, 0);
1607 calendar.set(Calendar.SECOND, 0);
1608 calendar.set(Calendar.MILLISECOND, 0);
1609 calendar.add(Calendar.DAY_OF_MONTH, 1);
David Christieebe51fc2013-07-26 13:23:29 -07001610
1611 final WorkSource workSource = null; // Let system take blame for date change events.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001612 setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 }
1614 }
1615
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001616 class InteractiveStateReceiver extends BroadcastReceiver {
1617 public InteractiveStateReceiver() {
1618 IntentFilter filter = new IntentFilter();
1619 filter.addAction(Intent.ACTION_SCREEN_OFF);
1620 filter.addAction(Intent.ACTION_SCREEN_ON);
1621 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
1622 getContext().registerReceiver(this, filter);
1623 }
1624
1625 @Override
1626 public void onReceive(Context context, Intent intent) {
1627 synchronized (mLock) {
1628 interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
1629 }
1630 }
1631 }
1632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 class UninstallReceiver extends BroadcastReceiver {
1634 public UninstallReceiver() {
1635 IntentFilter filter = new IntentFilter();
1636 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1637 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001638 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 filter.addDataScheme("package");
Adam Lesinski182f73f2013-12-05 16:48:06 -08001640 getContext().registerReceiver(this, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001641 // Register for events related to sdcard installation.
1642 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001643 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001644 sdFilter.addAction(Intent.ACTION_USER_STOPPED);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001645 getContext().registerReceiver(this, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 }
1647
1648 @Override
1649 public void onReceive(Context context, Intent intent) {
1650 synchronized (mLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001651 String action = intent.getAction();
1652 String pkgList[] = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001653 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
1654 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1655 for (String packageName : pkgList) {
1656 if (lookForPackageLocked(packageName)) {
1657 setResultCode(Activity.RESULT_OK);
1658 return;
1659 }
1660 }
1661 return;
1662 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001663 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001664 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
1665 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1666 if (userHandle >= 0) {
1667 removeUserLocked(userHandle);
1668 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001669 } else {
Dianne Hackborn409578f2010-03-10 17:23:43 -08001670 if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
1671 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1672 // This package is being updated; don't kill its alarms.
1673 return;
1674 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001675 Uri data = intent.getData();
1676 if (data != null) {
1677 String pkg = data.getSchemeSpecificPart();
1678 if (pkg != null) {
1679 pkgList = new String[]{pkg};
1680 }
1681 }
1682 }
1683 if (pkgList != null && (pkgList.length > 0)) {
1684 for (String pkg : pkgList) {
1685 removeLocked(pkg);
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001686 for (int i=mBroadcastStats.size()-1; i>=0; i--) {
1687 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
1688 if (uidStats.remove(pkg) != null) {
1689 if (uidStats.size() <= 0) {
1690 mBroadcastStats.removeAt(i);
1691 }
1692 }
1693 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 }
1696 }
1697 }
1698 }
1699
1700 private final BroadcastStats getStatsLocked(PendingIntent pi) {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001701 String pkg = pi.getCreatorPackage();
1702 int uid = pi.getCreatorUid();
1703 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
1704 if (uidStats == null) {
1705 uidStats = new ArrayMap<String, BroadcastStats>();
1706 mBroadcastStats.put(uid, uidStats);
1707 }
1708 BroadcastStats bs = uidStats.get(pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 if (bs == null) {
Dianne Hackborn3d658bf2014-02-05 13:38:56 -08001710 bs = new BroadcastStats(uid, pkg);
1711 uidStats.put(pkg, bs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
1713 return bs;
1714 }
Dianne Hackborn81038902012-11-26 17:04:09 -08001715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 class ResultReceiver implements PendingIntent.OnFinished {
1717 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
1718 String resultData, Bundle resultExtras) {
1719 synchronized (mLock) {
Dianne Hackborn81038902012-11-26 17:04:09 -08001720 InFlight inflight = null;
1721 for (int i=0; i<mInFlight.size(); i++) {
1722 if (mInFlight.get(i).mPendingIntent == pi) {
1723 inflight = mInFlight.remove(i);
1724 break;
1725 }
1726 }
1727 if (inflight != null) {
1728 final long nowELAPSED = SystemClock.elapsedRealtime();
1729 BroadcastStats bs = inflight.mBroadcastStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 bs.nesting--;
1731 if (bs.nesting <= 0) {
1732 bs.nesting = 0;
Dianne Hackborn81038902012-11-26 17:04:09 -08001733 bs.aggregateTime += nowELAPSED - bs.startTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
Dianne Hackborn81038902012-11-26 17:04:09 -08001735 FilterStats fs = inflight.mFilterStats;
1736 fs.nesting--;
1737 if (fs.nesting <= 0) {
1738 fs.nesting = 0;
1739 fs.aggregateTime += nowELAPSED - fs.startTime;
1740 }
1741 } else {
1742 mLog.w("No in-flight alarm for " + pi + " " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
1744 mBroadcastRefCount--;
1745 if (mBroadcastRefCount == 0) {
1746 mWakeLock.release();
Dianne Hackborn81038902012-11-26 17:04:09 -08001747 if (mInFlight.size() > 0) {
1748 mLog.w("Finished all broadcasts with " + mInFlight.size()
1749 + " remaining inflights");
1750 for (int i=0; i<mInFlight.size(); i++) {
1751 mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
1752 }
1753 mInFlight.clear();
1754 }
Christopher Tatec4a07d12012-04-06 14:19:13 -07001755 } else {
1756 // the next of our alarms is now in flight. reattribute the wakelock.
Dianne Hackborn81038902012-11-26 17:04:09 -08001757 if (mInFlight.size() > 0) {
David Christieebe51fc2013-07-26 13:23:29 -07001758 InFlight inFlight = mInFlight.get(0);
Dianne Hackborne5167ca2014-03-08 14:39:10 -08001759 setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
Dianne Hackbornd4e6d462014-05-16 16:32:37 -07001760 inFlight.mAlarmType, inFlight.mTag, false);
Christopher Tatec4a07d12012-04-06 14:19:13 -07001761 } else {
1762 // should never happen
Dianne Hackborn81038902012-11-26 17:04:09 -08001763 mLog.w("Alarm wakelock still held but sent queue empty");
Christopher Tatec4a07d12012-04-06 14:19:13 -07001764 mWakeLock.setWorkSource(null);
1765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 }
1767 }
1768 }
1769 }
1770}