PageRenderTime 94ms CodeModel.GetById 16ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/services/java/com/android/server/AlarmManagerService.java

https://github.com/aizuzi/platform_frameworks_base
Java | 1506 lines | 1267 code | 149 blank | 90 comment | 246 complexity | c5c0b9c78b9aa393110d4af774731447 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   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
  19import android.app.Activity;
  20import android.app.ActivityManagerNative;
  21import android.app.AlarmManager;
  22import android.app.IAlarmManager;
  23import android.app.PendingIntent;
  24import android.content.BroadcastReceiver;
  25import android.content.ComponentName;
  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;
  34import android.os.Message;
  35import android.os.PowerManager;
  36import android.os.SystemClock;
  37import android.os.SystemProperties;
  38import android.os.UserHandle;
  39import android.os.WorkSource;
  40import android.text.TextUtils;
  41import android.util.Pair;
  42import android.util.Slog;
  43import android.util.TimeUtils;
  44
  45import java.io.ByteArrayOutputStream;
  46import java.io.FileDescriptor;
  47import java.io.PrintWriter;
  48import java.text.SimpleDateFormat;
  49import java.util.ArrayList;
  50import java.util.Arrays;
  51import java.util.Calendar;
  52import java.util.Collections;
  53import java.util.Comparator;
  54import java.util.Date;
  55import java.util.HashMap;
  56import java.util.LinkedList;
  57import java.util.Map;
  58import java.util.TimeZone;
  59
  60import static android.app.AlarmManager.RTC_WAKEUP;
  61import static android.app.AlarmManager.RTC;
  62import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
  63import static android.app.AlarmManager.ELAPSED_REALTIME;
  64
  65import com.android.internal.util.LocalLog;
  66
  67class AlarmManagerService extends IAlarmManager.Stub {
  68    // The threshold for how long an alarm can be late before we print a
  69    // warning message.  The time duration is in milliseconds.
  70    private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
  71
  72    private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
  73    private static final int RTC_MASK = 1 << RTC;
  74    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; 
  75    private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
  76    private static final int TIME_CHANGED_MASK = 1 << 16;
  77    private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
  78
  79    // Mask for testing whether a given alarm type is wakeup vs non-wakeup
  80    private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
  81
  82    private static final String TAG = "AlarmManager";
  83    private static final String ClockReceiver_TAG = "ClockReceiver";
  84    private static final boolean localLOGV = false;
  85    private static final boolean DEBUG_BATCH = localLOGV || false;
  86    private static final boolean DEBUG_VALIDATE = localLOGV || false;
  87    private static final int ALARM_EVENT = 1;
  88    private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
  89    
  90    private static final Intent mBackgroundIntent
  91            = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
  92    private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
  93    
  94    private static final boolean WAKEUP_STATS = false;
  95
  96    private final Context mContext;
  97
  98    private final LocalLog mLog = new LocalLog(TAG);
  99
 100    private Object mLock = new Object();
 101
 102    private long mNativeData;
 103    private long mNextWakeup;
 104    private long mNextNonWakeup;
 105    private int mBroadcastRefCount = 0;
 106    private PowerManager.WakeLock mWakeLock;
 107    private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
 108    private final AlarmThread mWaitThread = new AlarmThread();
 109    private final AlarmHandler mHandler = new AlarmHandler();
 110    private ClockReceiver mClockReceiver;
 111    private UninstallReceiver mUninstallReceiver;
 112    private final ResultReceiver mResultReceiver = new ResultReceiver();
 113    private final PendingIntent mTimeTickSender;
 114    private final PendingIntent mDateChangeSender;
 115
 116    class WakeupEvent {
 117        public long when;
 118        public int uid;
 119        public String action;
 120
 121        public WakeupEvent(long theTime, int theUid, String theAction) {
 122            when = theTime;
 123            uid = theUid;
 124            action = theAction;
 125        }
 126    }
 127
 128    private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
 129    private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
 130
 131    static final class Batch {
 132        long start;     // These endpoints are always in ELAPSED
 133        long end;
 134        boolean standalone; // certain "batches" don't participate in coalescing
 135
 136        final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
 137
 138        Batch() {
 139            start = 0;
 140            end = Long.MAX_VALUE;
 141        }
 142
 143        Batch(Alarm seed) {
 144            start = seed.whenElapsed;
 145            end = seed.maxWhen;
 146            alarms.add(seed);
 147        }
 148
 149        int size() {
 150            return alarms.size();
 151        }
 152
 153        Alarm get(int index) {
 154            return alarms.get(index);
 155        }
 156
 157        boolean canHold(long whenElapsed, long maxWhen) {
 158            return (end >= whenElapsed) && (start <= maxWhen);
 159        }
 160
 161        boolean add(Alarm alarm) {
 162            boolean newStart = false;
 163            // narrows the batch if necessary; presumes that canHold(alarm) is true
 164            int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder);
 165            if (index < 0) {
 166                index = 0 - index - 1;
 167            }
 168            alarms.add(index, alarm);
 169            if (DEBUG_BATCH) {
 170                Slog.v(TAG, "Adding " + alarm + " to " + this);
 171            }
 172            if (alarm.whenElapsed > start) {
 173                start = alarm.whenElapsed;
 174                newStart = true;
 175            }
 176            if (alarm.maxWhen < end) {
 177                end = alarm.maxWhen;
 178            }
 179
 180            if (DEBUG_BATCH) {
 181                Slog.v(TAG, "    => now " + this);
 182            }
 183            return newStart;
 184        }
 185
 186        boolean remove(final PendingIntent operation) {
 187            boolean didRemove = false;
 188            long newStart = 0;  // recalculate endpoints as we go
 189            long newEnd = Long.MAX_VALUE;
 190            for (int i = 0; i < alarms.size(); ) {
 191                Alarm alarm = alarms.get(i);
 192                if (alarm.operation.equals(operation)) {
 193                    alarms.remove(i);
 194                    didRemove = true;
 195                } else {
 196                    if (alarm.whenElapsed > newStart) {
 197                        newStart = alarm.whenElapsed;
 198                    }
 199                    if (alarm.maxWhen < newEnd) {
 200                        newEnd = alarm.maxWhen;
 201                    }
 202                    i++;
 203                }
 204            }
 205            if (didRemove) {
 206                // commit the new batch bounds
 207                start = newStart;
 208                end = newEnd;
 209            }
 210            return didRemove;
 211        }
 212
 213        boolean remove(final String packageName) {
 214            boolean didRemove = false;
 215            long newStart = 0;  // recalculate endpoints as we go
 216            long newEnd = Long.MAX_VALUE;
 217            for (int i = 0; i < alarms.size(); ) {
 218                Alarm alarm = alarms.get(i);
 219                if (alarm.operation.getTargetPackage().equals(packageName)) {
 220                    alarms.remove(i);
 221                    didRemove = true;
 222                } else {
 223                    if (alarm.whenElapsed > newStart) {
 224                        newStart = alarm.whenElapsed;
 225                    }
 226                    if (alarm.maxWhen < newEnd) {
 227                        newEnd = alarm.maxWhen;
 228                    }
 229                    i++;
 230                }
 231            }
 232            if (didRemove) {
 233                // commit the new batch bounds
 234                start = newStart;
 235                end = newEnd;
 236            }
 237            return didRemove;
 238        }
 239
 240        boolean remove(final int userHandle) {
 241            boolean didRemove = false;
 242            long newStart = 0;  // recalculate endpoints as we go
 243            long newEnd = Long.MAX_VALUE;
 244            for (int i = 0; i < alarms.size(); ) {
 245                Alarm alarm = alarms.get(i);
 246                if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
 247                    alarms.remove(i);
 248                    didRemove = true;
 249                } else {
 250                    if (alarm.whenElapsed > newStart) {
 251                        newStart = alarm.whenElapsed;
 252                    }
 253                    if (alarm.maxWhen < newEnd) {
 254                        newEnd = alarm.maxWhen;
 255                    }
 256                    i++;
 257                }
 258            }
 259            if (didRemove) {
 260                // commit the new batch bounds
 261                start = newStart;
 262                end = newEnd;
 263            }
 264            return didRemove;
 265        }
 266
 267        boolean hasPackage(final String packageName) {
 268            final int N = alarms.size();
 269            for (int i = 0; i < N; i++) {
 270                Alarm a = alarms.get(i);
 271                if (a.operation.getTargetPackage().equals(packageName)) {
 272                    return true;
 273                }
 274            }
 275            return false;
 276        }
 277
 278        boolean hasWakeups() {
 279            final int N = alarms.size();
 280            for (int i = 0; i < N; i++) {
 281                Alarm a = alarms.get(i);
 282                // non-wakeup alarms are types 1 and 3, i.e. have the low bit set
 283                if ((a.type & TYPE_NONWAKEUP_MASK) == 0) {
 284                    return true;
 285                }
 286            }
 287            return false;
 288        }
 289
 290        @Override
 291        public String toString() {
 292            StringBuilder b = new StringBuilder(40);
 293            b.append("Batch{"); b.append(Integer.toHexString(this.hashCode()));
 294            b.append(" num="); b.append(size());
 295            b.append(" start="); b.append(start);
 296            b.append(" end="); b.append(end);
 297            if (standalone) {
 298                b.append(" STANDALONE");
 299            }
 300            b.append('}');
 301            return b.toString();
 302        }
 303    }
 304
 305    static class BatchTimeOrder implements Comparator<Batch> {
 306        public int compare(Batch b1, Batch b2) {
 307            long when1 = b1.start;
 308            long when2 = b2.start;
 309            if (when1 - when2 > 0) {
 310                return 1;
 311            }
 312            if (when1 - when2 < 0) {
 313                return -1;
 314            }
 315            return 0;
 316        }
 317    }
 318    
 319    // minimum recurrence period or alarm futurity for us to be able to fuzz it
 320    private static final long MIN_FUZZABLE_INTERVAL = 10000;
 321    private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
 322    private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
 323
 324    static long convertToElapsed(long when, int type) {
 325        final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
 326        if (isRtc) {
 327            when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
 328        }
 329        return when;
 330    }
 331
 332    // Apply a heuristic to { recurrence interval, futurity of the trigger time } to
 333    // calculate the end of our nominal delivery window for the alarm.
 334    static long maxTriggerTime(long now, long triggerAtTime, long interval) {
 335        // Current heuristic: batchable window is 75% of either the recurrence interval
 336        // [for a periodic alarm] or of the time from now to the desired delivery time,
 337        // with a minimum delay/interval of 10 seconds, under which we will simply not
 338        // defer the alarm.
 339        long futurity = (interval == 0)
 340                ? (triggerAtTime - now)
 341                : interval;
 342        if (futurity < MIN_FUZZABLE_INTERVAL) {
 343            futurity = 0;
 344        }
 345        return triggerAtTime + (long)(.75 * futurity);
 346    }
 347
 348    // returns true if the batch was added at the head
 349    static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) {
 350        int index = Collections.binarySearch(list, newBatch, sBatchOrder);
 351        if (index < 0) {
 352            index = 0 - index - 1;
 353        }
 354        list.add(index, newBatch);
 355        return (index == 0);
 356    }
 357
 358    // Return the index of the matching batch, or -1 if none found.
 359    int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
 360        final int N = mAlarmBatches.size();
 361        for (int i = 0; i < N; i++) {
 362            Batch b = mAlarmBatches.get(i);
 363            if (!b.standalone && b.canHold(whenElapsed, maxWhen)) {
 364                return i;
 365            }
 366        }
 367        return -1;
 368    }
 369
 370    // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
 371    void rebatchAllAlarms() {
 372        synchronized (mLock) {
 373            rebatchAllAlarmsLocked(true);
 374        }
 375    }
 376
 377    void rebatchAllAlarmsLocked(boolean doValidate) {
 378        ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
 379        mAlarmBatches.clear();
 380        final long nowElapsed = SystemClock.elapsedRealtime();
 381        final int oldBatches = oldSet.size();
 382        for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
 383            Batch batch = oldSet.get(batchNum);
 384            final int N = batch.size();
 385            for (int i = 0; i < N; i++) {
 386                Alarm a = batch.get(i);
 387                long whenElapsed = convertToElapsed(a.when, a.type);
 388                final long maxElapsed;
 389                if (a.whenElapsed == a.maxWhen) {
 390                    // Exact
 391                    maxElapsed = whenElapsed;
 392                } else {
 393                    // Not exact.  Preserve any explicit window, otherwise recalculate
 394                    // the window based on the alarm's new futurity.  Note that this
 395                    // reflects a policy of preferring timely to deferred delivery.
 396                    maxElapsed = (a.windowLength > 0)
 397                            ? (whenElapsed + a.windowLength)
 398                            : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
 399                }
 400                setImplLocked(a.type, a.when, whenElapsed, a.windowLength, maxElapsed,
 401                        a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource);
 402            }
 403        }
 404    }
 405
 406    private static final class InFlight extends Intent {
 407        final PendingIntent mPendingIntent;
 408        final WorkSource mWorkSource;
 409        final Pair<String, ComponentName> mTarget;
 410        final BroadcastStats mBroadcastStats;
 411        final FilterStats mFilterStats;
 412
 413        InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource) {
 414            mPendingIntent = pendingIntent;
 415            mWorkSource = workSource;
 416            Intent intent = pendingIntent.getIntent();
 417            mTarget = intent != null
 418                    ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
 419                    : null;
 420            mBroadcastStats = service.getStatsLocked(pendingIntent);
 421            FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
 422            if (fs == null) {
 423                fs = new FilterStats(mBroadcastStats, mTarget);
 424                mBroadcastStats.filterStats.put(mTarget, fs);
 425            }
 426            mFilterStats = fs;
 427        }
 428    }
 429
 430    private static final class FilterStats {
 431        final BroadcastStats mBroadcastStats;
 432        final Pair<String, ComponentName> mTarget;
 433
 434        long aggregateTime;
 435        int count;
 436        int numWakeup;
 437        long startTime;
 438        int nesting;
 439
 440        FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
 441            mBroadcastStats = broadcastStats;
 442            mTarget = target;
 443        }
 444    }
 445    
 446    private static final class BroadcastStats {
 447        final String mPackageName;
 448
 449        long aggregateTime;
 450        int count;
 451        int numWakeup;
 452        long startTime;
 453        int nesting;
 454        final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
 455                = new HashMap<Pair<String, ComponentName>, FilterStats>();
 456
 457        BroadcastStats(String packageName) {
 458            mPackageName = packageName;
 459        }
 460    }
 461    
 462    private final HashMap<String, BroadcastStats> mBroadcastStats
 463            = new HashMap<String, BroadcastStats>();
 464    
 465    public AlarmManagerService(Context context) {
 466        mContext = context;
 467        mNativeData = init();
 468        mNextWakeup = mNextNonWakeup = 0;
 469
 470        // We have to set current TimeZone info to kernel
 471        // because kernel doesn't keep this after reboot
 472        String tz = SystemProperties.get(TIMEZONE_PROPERTY);
 473        if (tz != null) {
 474            setTimeZone(tz);
 475        }
 476
 477        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
 478        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 479        
 480        mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
 481                new Intent(Intent.ACTION_TIME_TICK).addFlags(
 482                        Intent.FLAG_RECEIVER_REGISTERED_ONLY
 483                        | Intent.FLAG_RECEIVER_FOREGROUND), 0,
 484                        UserHandle.ALL);
 485        Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
 486        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
 487        mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
 488                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
 489        
 490        // now that we have initied the driver schedule the alarm
 491        mClockReceiver= new ClockReceiver();
 492        mClockReceiver.scheduleTimeTickEvent();
 493        mClockReceiver.scheduleDateChangedEvent();
 494        mUninstallReceiver = new UninstallReceiver();
 495        
 496        if (mNativeData != 0) {
 497            mWaitThread.start();
 498        } else {
 499            Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
 500        }
 501    }
 502    
 503    protected void finalize() throws Throwable {
 504        try {
 505            close(mNativeData);
 506        } finally {
 507            super.finalize();
 508        }
 509    }
 510
 511    @Override
 512    public void set(int type, long triggerAtTime, long windowLength, long interval,
 513            PendingIntent operation, WorkSource workSource) {
 514        if (workSource != null) {
 515            mContext.enforceCallingPermission(
 516                    android.Manifest.permission.UPDATE_DEVICE_STATS,
 517                    "AlarmManager.set");
 518        }
 519
 520        set(type, triggerAtTime, windowLength, interval, operation, false, workSource);
 521    }
 522
 523    public void set(int type, long triggerAtTime, long windowLength, long interval,
 524            PendingIntent operation, boolean isStandalone, WorkSource workSource) {
 525        if (operation == null) {
 526            Slog.w(TAG, "set/setRepeating ignored because there is no intent");
 527            return;
 528        }
 529
 530        // Sanity check the window length.  This will catch people mistakenly
 531        // trying to pass an end-of-window timestamp rather than a duration.
 532        if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
 533            Slog.w(TAG, "Window length " + windowLength
 534                    + "ms suspiciously long; limiting to 1 hour");
 535            windowLength = AlarmManager.INTERVAL_HOUR;
 536        }
 537
 538        if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
 539            throw new IllegalArgumentException("Invalid alarm type " + type);
 540        }
 541
 542        if (triggerAtTime < 0) {
 543            final long who = Binder.getCallingUid();
 544            final long what = Binder.getCallingPid();
 545            Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
 546                    + " pid=" + what);
 547            triggerAtTime = 0;
 548        }
 549
 550        final long nowElapsed = SystemClock.elapsedRealtime();
 551        final long triggerElapsed = convertToElapsed(triggerAtTime, type);
 552        final long maxElapsed;
 553        if (windowLength == AlarmManager.WINDOW_EXACT) {
 554            maxElapsed = triggerElapsed;
 555        } else if (windowLength < 0) {
 556            maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
 557        } else {
 558            maxElapsed = triggerElapsed + windowLength;
 559        }
 560
 561        synchronized (mLock) {
 562            if (DEBUG_BATCH) {
 563                Slog.v(TAG, "set(" + operation + ") : type=" + type
 564                        + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
 565                        + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
 566                        + " interval=" + interval + " standalone=" + isStandalone);
 567            }
 568            setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
 569                    interval, operation, isStandalone, true, workSource);
 570        }
 571    }
 572
 573    private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
 574            long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
 575            boolean doValidate, WorkSource workSource) {
 576        Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
 577                operation, workSource);
 578        removeLocked(operation);
 579
 580        int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
 581        if (whichBatch < 0) {
 582            Batch batch = new Batch(a);
 583            batch.standalone = isStandalone;
 584            addBatchLocked(mAlarmBatches, batch);
 585        } else {
 586            Batch batch = mAlarmBatches.get(whichBatch);
 587            if (batch.add(a)) {
 588                // The start time of this batch advanced, so batch ordering may
 589                // have just been broken.  Move it to where it now belongs.
 590                mAlarmBatches.remove(whichBatch);
 591                addBatchLocked(mAlarmBatches, batch);
 592            }
 593        }
 594
 595        if (DEBUG_VALIDATE) {
 596            if (doValidate && !validateConsistencyLocked()) {
 597                Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
 598                        + " when(hex)=" + Long.toHexString(when)
 599                        + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
 600                        + " interval=" + interval + " op=" + operation
 601                        + " standalone=" + isStandalone);
 602                rebatchAllAlarmsLocked(false);
 603            }
 604        }
 605
 606        rescheduleKernelAlarmsLocked();
 607    }
 608
 609    private void logBatchesLocked() {
 610        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
 611        PrintWriter pw = new PrintWriter(bs);
 612        final long nowRTC = System.currentTimeMillis();
 613        final long nowELAPSED = SystemClock.elapsedRealtime();
 614        final int NZ = mAlarmBatches.size();
 615        for (int iz = 0; iz < NZ; iz++) {
 616            Batch bz = mAlarmBatches.get(iz);
 617            pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
 618            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
 619            pw.flush();
 620            Slog.v(TAG, bs.toString());
 621            bs.reset();
 622        }
 623    }
 624
 625    private boolean validateConsistencyLocked() {
 626        if (DEBUG_VALIDATE) {
 627            long lastTime = Long.MIN_VALUE;
 628            final int N = mAlarmBatches.size();
 629            for (int i = 0; i < N; i++) {
 630                Batch b = mAlarmBatches.get(i);
 631                if (b.start >= lastTime) {
 632                    // duplicate start times are okay because of standalone batches
 633                    lastTime = b.start;
 634                } else {
 635                    Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
 636                    logBatchesLocked();
 637                    return false;
 638                }
 639            }
 640        }
 641        return true;
 642    }
 643
 644    private Batch findFirstWakeupBatchLocked() {
 645        final int N = mAlarmBatches.size();
 646        for (int i = 0; i < N; i++) {
 647            Batch b = mAlarmBatches.get(i);
 648            if (b.hasWakeups()) {
 649                return b;
 650            }
 651        }
 652        return null;
 653    }
 654
 655    private void rescheduleKernelAlarmsLocked() {
 656        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
 657        // prior to that which contains no wakeups, we schedule that as well.
 658        if (mAlarmBatches.size() > 0) {
 659            final Batch firstWakeup = findFirstWakeupBatchLocked();
 660            final Batch firstBatch = mAlarmBatches.get(0);
 661            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
 662                mNextWakeup = firstWakeup.start;
 663                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
 664            }
 665            if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
 666                mNextNonWakeup = firstBatch.start;
 667                setLocked(ELAPSED_REALTIME, firstBatch.start);
 668            }
 669        }
 670    }
 671
 672    public boolean setTime(long millis) {
 673        mContext.enforceCallingOrSelfPermission(
 674                "android.permission.SET_TIME",
 675                "setTime");
 676
 677        if (mNativeData == 0) {
 678            Slog.w(TAG, "Not setting time since no alarm driver is available.");
 679            return false;
 680        }
 681
 682        synchronized (mLock) {
 683            return setKernelTime(mNativeData, millis) == 0;
 684        }
 685    }
 686
 687    public void setTimeZone(String tz) {
 688        mContext.enforceCallingOrSelfPermission(
 689                "android.permission.SET_TIME_ZONE",
 690                "setTimeZone");
 691
 692        long oldId = Binder.clearCallingIdentity();
 693        try {
 694            if (TextUtils.isEmpty(tz)) return;
 695            TimeZone zone = TimeZone.getTimeZone(tz);
 696            // Prevent reentrant calls from stepping on each other when writing
 697            // the time zone property
 698            boolean timeZoneWasChanged = false;
 699            synchronized (this) {
 700                String current = SystemProperties.get(TIMEZONE_PROPERTY);
 701                if (current == null || !current.equals(zone.getID())) {
 702                    if (localLOGV) {
 703                        Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
 704                    }
 705                    timeZoneWasChanged = true;
 706                    SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
 707                }
 708
 709                // Update the kernel timezone information
 710                // Kernel tracks time offsets as 'minutes west of GMT'
 711                int gmtOffset = zone.getOffset(System.currentTimeMillis());
 712                setKernelTimezone(mNativeData, -(gmtOffset / 60000));
 713            }
 714
 715            TimeZone.setDefault(null);
 716
 717            if (timeZoneWasChanged) {
 718                Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
 719                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
 720                intent.putExtra("time-zone", zone.getID());
 721                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
 722            }
 723        } finally {
 724            Binder.restoreCallingIdentity(oldId);
 725        }
 726    }
 727    
 728    public void remove(PendingIntent operation) {
 729        if (operation == null) {
 730            return;
 731        }
 732        synchronized (mLock) {
 733            removeLocked(operation);
 734        }
 735    }
 736    
 737    public void removeLocked(PendingIntent operation) {
 738        boolean didRemove = false;
 739        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
 740            Batch b = mAlarmBatches.get(i);
 741            didRemove |= b.remove(operation);
 742            if (b.size() == 0) {
 743                mAlarmBatches.remove(i);
 744            }
 745        }
 746
 747        if (didRemove) {
 748            if (DEBUG_BATCH) {
 749                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
 750            }
 751            rebatchAllAlarmsLocked(true);
 752            rescheduleKernelAlarmsLocked();
 753        }
 754    }
 755
 756    public void removeLocked(String packageName) {
 757        boolean didRemove = false;
 758        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
 759            Batch b = mAlarmBatches.get(i);
 760            didRemove |= b.remove(packageName);
 761            if (b.size() == 0) {
 762                mAlarmBatches.remove(i);
 763            }
 764        }
 765
 766        if (didRemove) {
 767            if (DEBUG_BATCH) {
 768                Slog.v(TAG, "remove(package) changed bounds; rebatching");
 769            }
 770            rebatchAllAlarmsLocked(true);
 771            rescheduleKernelAlarmsLocked();
 772        }
 773    }
 774
 775    public void removeUserLocked(int userHandle) {
 776        boolean didRemove = false;
 777        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
 778            Batch b = mAlarmBatches.get(i);
 779            didRemove |= b.remove(userHandle);
 780            if (b.size() == 0) {
 781                mAlarmBatches.remove(i);
 782            }
 783        }
 784
 785        if (didRemove) {
 786            if (DEBUG_BATCH) {
 787                Slog.v(TAG, "remove(user) changed bounds; rebatching");
 788            }
 789            rebatchAllAlarmsLocked(true);
 790            rescheduleKernelAlarmsLocked();
 791        }
 792    }
 793
 794    public boolean lookForPackageLocked(String packageName) {
 795        for (int i = 0; i < mAlarmBatches.size(); i++) {
 796            Batch b = mAlarmBatches.get(i);
 797            if (b.hasPackage(packageName)) {
 798                return true;
 799            }
 800        }
 801        return false;
 802    }
 803
 804    private void setLocked(int type, long when)
 805    {
 806        if (mNativeData != 0)
 807        {
 808            // The kernel never triggers alarms with negative wakeup times
 809            // so we ensure they are positive.
 810            long alarmSeconds, alarmNanoseconds;
 811            if (when < 0) {
 812                alarmSeconds = 0;
 813                alarmNanoseconds = 0;
 814            } else {
 815                alarmSeconds = when / 1000;
 816                alarmNanoseconds = (when % 1000) * 1000 * 1000;
 817            }
 818            
 819            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
 820        }
 821        else
 822        {
 823            Message msg = Message.obtain();
 824            msg.what = ALARM_EVENT;
 825            
 826            mHandler.removeMessages(ALARM_EVENT);
 827            mHandler.sendMessageAtTime(msg, when);
 828        }
 829    }
 830    
 831    @Override
 832    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
 833        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
 834                != PackageManager.PERMISSION_GRANTED) {
 835            pw.println("Permission Denial: can't dump AlarmManager from from pid="
 836                    + Binder.getCallingPid()
 837                    + ", uid=" + Binder.getCallingUid());
 838            return;
 839        }
 840        
 841        synchronized (mLock) {
 842            pw.println("Current Alarm Manager state:");
 843            final long nowRTC = System.currentTimeMillis();
 844            final long nowELAPSED = SystemClock.elapsedRealtime();
 845            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 846
 847            pw.print("nowRTC="); pw.print(nowRTC);
 848            pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
 849            pw.print(" nowELAPSED="); pw.println(nowELAPSED);
 850
 851            long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
 852            long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
 853            pw.print("Next alarm: "); pw.print(mNextNonWakeup);
 854                    pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
 855            pw.print("Next wakeup: "); pw.print(mNextWakeup);
 856                    pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
 857
 858            if (mAlarmBatches.size() > 0) {
 859                pw.println();
 860                pw.print("Pending alarm batches: ");
 861                pw.println(mAlarmBatches.size());
 862                for (Batch b : mAlarmBatches) {
 863                    pw.print(b); pw.println(':');
 864                    dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC);
 865                }
 866            }
 867
 868            pw.println();
 869            pw.print("  Broadcast ref count: "); pw.println(mBroadcastRefCount);
 870            pw.println();
 871
 872            if (mLog.dump(pw, "  Recent problems", "    ")) {
 873                pw.println();
 874            }
 875
 876            final FilterStats[] topFilters = new FilterStats[10];
 877            final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
 878                @Override
 879                public int compare(FilterStats lhs, FilterStats rhs) {
 880                    if (lhs.aggregateTime < rhs.aggregateTime) {
 881                        return 1;
 882                    } else if (lhs.aggregateTime > rhs.aggregateTime) {
 883                        return -1;
 884                    }
 885                    return 0;
 886                }
 887            };
 888            int len = 0;
 889            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
 890                BroadcastStats bs = be.getValue();
 891                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
 892                        : bs.filterStats.entrySet()) {
 893                    FilterStats fs = fe.getValue();
 894                    int pos = len > 0
 895                            ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
 896                    if (pos < 0) {
 897                        pos = -pos - 1;
 898                    }
 899                    if (pos < topFilters.length) {
 900                        int copylen = topFilters.length - pos - 1;
 901                        if (copylen > 0) {
 902                            System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
 903                        }
 904                        topFilters[pos] = fs;
 905                        if (len < topFilters.length) {
 906                            len++;
 907                        }
 908                    }
 909                }
 910            }
 911            if (len > 0) {
 912                pw.println("  Top Alarms:");
 913                for (int i=0; i<len; i++) {
 914                    FilterStats fs = topFilters[i];
 915                    pw.print("    ");
 916                    if (fs.nesting > 0) pw.print("*ACTIVE* ");
 917                    TimeUtils.formatDuration(fs.aggregateTime, pw);
 918                    pw.print(" running, "); pw.print(fs.numWakeup);
 919                    pw.print(" wakeups, "); pw.print(fs.count);
 920                    pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
 921                    pw.println();
 922                    pw.print("      ");
 923                    if (fs.mTarget.first != null) {
 924                        pw.print(" act="); pw.print(fs.mTarget.first);
 925                    }
 926                    if (fs.mTarget.second != null) {
 927                        pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
 928                    }
 929                    pw.println();
 930                }
 931            }
 932
 933            pw.println(" ");
 934            pw.println("  Alarm Stats:");
 935            final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
 936            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
 937                BroadcastStats bs = be.getValue();
 938                pw.print("  ");
 939                if (bs.nesting > 0) pw.print("*ACTIVE* ");
 940                pw.print(be.getKey());
 941                pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
 942                        pw.print(" running, "); pw.print(bs.numWakeup);
 943                        pw.println(" wakeups:");
 944                tmpFilters.clear();
 945                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
 946                        : bs.filterStats.entrySet()) {
 947                    tmpFilters.add(fe.getValue());
 948                }
 949                Collections.sort(tmpFilters, comparator);
 950                for (int i=0; i<tmpFilters.size(); i++) {
 951                    FilterStats fs = tmpFilters.get(i);
 952                    pw.print("    ");
 953                            if (fs.nesting > 0) pw.print("*ACTIVE* ");
 954                            TimeUtils.formatDuration(fs.aggregateTime, pw);
 955                            pw.print(" "); pw.print(fs.numWakeup);
 956                            pw.print(" wakes " ); pw.print(fs.count);
 957                            pw.print(" alarms:");
 958                            if (fs.mTarget.first != null) {
 959                                pw.print(" act="); pw.print(fs.mTarget.first);
 960                            }
 961                            if (fs.mTarget.second != null) {
 962                                pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
 963                            }
 964                            pw.println();
 965                }
 966            }
 967
 968            if (WAKEUP_STATS) {
 969                pw.println();
 970                pw.println("  Recent Wakeup History:");
 971                long last = -1;
 972                for (WakeupEvent event : mRecentWakeups) {
 973                    pw.print("    "); pw.print(sdf.format(new Date(event.when)));
 974                    pw.print('|');
 975                    if (last < 0) {
 976                        pw.print('0');
 977                    } else {
 978                        pw.print(event.when - last);
 979                    }
 980                    last = event.when;
 981                    pw.print('|'); pw.print(event.uid);
 982                    pw.print('|'); pw.print(event.action);
 983                    pw.println();
 984                }
 985                pw.println();
 986            }
 987        }
 988    }
 989
 990    private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
 991            String prefix, String label, long now) {
 992        for (int i=list.size()-1; i>=0; i--) {
 993            Alarm a = list.get(i);
 994            pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
 995                    pw.print(": "); pw.println(a);
 996            a.dump(pw, prefix + "  ", now);
 997        }
 998    }
 999
1000    private static final String labelForType(int type) {
1001        switch (type) {
1002        case RTC: return "RTC";
1003        case RTC_WAKEUP : return "RTC_WAKEUP";
1004        case ELAPSED_REALTIME : return "ELAPSED";
1005        case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
1006        default:
1007            break;
1008        }
1009        return "--unknown--";
1010    }
1011
1012    private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
1013            String prefix, long nowELAPSED, long nowRTC) {
1014        for (int i=list.size()-1; i>=0; i--) {
1015            Alarm a = list.get(i);
1016            final String label = labelForType(a.type);
1017            long now = (a.type <= RTC) ? nowRTC : nowELAPSED;
1018            pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1019                    pw.print(": "); pw.println(a);
1020            a.dump(pw, prefix + "  ", now);
1021        }
1022    }
1023
1024    private native long init();
1025    private native void close(long nativeData);
1026    private native void set(long nativeData, int type, long seconds, long nanoseconds);
1027    private native int waitForAlarm(long nativeData);
1028    private native int setKernelTime(long nativeData, long millis);
1029    private native int setKernelTimezone(long nativeData, int minuteswest);
1030
1031    private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
1032        // batches are temporally sorted, so we need only pull from the
1033        // start of the list until we either empty it or hit a batch
1034        // that is not yet deliverable
1035        while (mAlarmBatches.size() > 0) {
1036            Batch batch = mAlarmBatches.get(0);
1037            if (batch.start > nowELAPSED) {
1038                // Everything else is scheduled for the future
1039                break;
1040            }
1041
1042            // We will (re)schedule some alarms now; don't let that interfere
1043            // with delivery of this current batch
1044            mAlarmBatches.remove(0);
1045
1046            final int N = batch.size();
1047            for (int i = 0; i < N; i++) {
1048                Alarm alarm = batch.get(i);
1049                alarm.count = 1;
1050                triggerList.add(alarm);
1051
1052                // Recurring alarms may have passed several alarm intervals while the
1053                // phone was asleep or off, so pass a trigger count when sending them.
1054                if (alarm.repeatInterval > 0) {
1055                    // this adjustment will be zero if we're late by
1056                    // less than one full repeat interval
1057                    alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
1058
1059                    // Also schedule its next recurrence
1060                    final long delta = alarm.count * alarm.repeatInterval;
1061                    final long nextElapsed = alarm.whenElapsed + delta;
1062                    setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
1063                            maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
1064                            alarm.repeatInterval, alarm.operation, batch.standalone, true,
1065                            alarm.workSource);
1066                }
1067
1068            }
1069        }
1070    }
1071
1072    /**
1073     * This Comparator sorts Alarms into increasing time order.
1074     */
1075    public static class IncreasingTimeOrder implements Comparator<Alarm> {
1076        public int compare(Alarm a1, Alarm a2) {
1077            long when1 = a1.when;
1078            long when2 = a2.when;
1079            if (when1 - when2 > 0) {
1080                return 1;
1081            }
1082            if (when1 - when2 < 0) {
1083                return -1;
1084            }
1085            return 0;
1086        }
1087    }
1088    
1089    private static class Alarm {
1090        public int type;
1091        public int count;
1092        public long when;
1093        public long windowLength;
1094        public long whenElapsed;    // 'when' in the elapsed time base
1095        public long maxWhen;        // also in the elapsed time base
1096        public long repeatInterval;
1097        public PendingIntent operation;
1098        public WorkSource workSource;
1099        
1100        public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
1101                long _interval, PendingIntent _op, WorkSource _ws) {
1102            type = _type;
1103            when = _when;
1104            whenElapsed = _whenElapsed;
1105            windowLength = _windowLength;
1106            maxWhen = _maxWhen;
1107            repeatInterval = _interval;
1108            operation = _op;
1109            workSource = _ws;
1110        }
1111
1112        @Override
1113        public String toString()
1114        {
1115            StringBuilder sb = new StringBuilder(128);
1116            sb.append("Alarm{");
1117            sb.append(Integer.toHexString(System.identityHashCode(this)));
1118            sb.append(" type ");
1119            sb.append(type);
1120            sb.append(" ");
1121            sb.append(operation.getTargetPackage());
1122            sb.append('}');
1123            return sb.toString();
1124        }
1125
1126        public void dump(PrintWriter pw, String prefix, long now) {
1127            pw.print(prefix); pw.print("type="); pw.print(type);
1128                    pw.print(" whenElapsed="); pw.print(whenElapsed);
1129                    pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
1130                    pw.print(" window="); pw.print(windowLength);
1131                    pw.print(" repeatInterval="); pw.print(repeatInterval);
1132                    pw.print(" count="); pw.println(count);
1133            pw.print(prefix); pw.print("operation="); pw.println(operation);
1134        }
1135    }
1136
1137    void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
1138        final int numBatches = batches.size();
1139        for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
1140            Batch b = batches.get(nextBatch);
1141            if (b.start > nowELAPSED) {
1142                break;
1143            }
1144
1145            final int numAlarms = b.alarms.size();
1146            for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
1147                Alarm a = b.alarms.get(nextAlarm);
1148                WakeupEvent e = new WakeupEvent(nowRTC,
1149                        a.operation.getCreatorUid(),
1150                        a.operation.getIntent().getAction());
1151                mRecentWakeups.add(e);
1152            }
1153        }
1154    }
1155
1156    private class AlarmThread extends Thread
1157    {
1158        public AlarmThread()
1159        {
1160            super("AlarmManager");
1161        }
1162        
1163        public void run()
1164        {
1165            ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1166
1167            while (true)
1168            {
1169                int result = waitForAlarm(mNativeData);
1170
1171                triggerList.clear();
1172
1173                if ((result & TIME_CHANGED_MASK) != 0) {
1174                    if (DEBUG_BATCH) {
1175                        Slog.v(TAG, "Time changed notification from kernel; rebatching");
1176                    }
1177                    remove(mTimeTickSender);
1178                    rebatchAllAlarms();
1179                    mClockReceiver.scheduleTimeTickEvent();
1180                    Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
1181                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
1182                            | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1183                    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1184                }
1185                
1186                synchronized (mLock) {
1187                    final long nowRTC = System.currentTimeMillis();
1188                    final long nowELAPSED = SystemClock.elapsedRealtime();
1189                    if (localLOGV) Slog.v(
1190                        TAG, "Checking for alarms... rtc=" + nowRTC
1191                        + ", elapsed=" + nowELAPSED);
1192
1193                    if (WAKEUP_STATS) {
1194                        if ((result & IS_WAKEUP_MASK) != 0) {
1195                            long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
1196                            int n = 0;
1197                            for (WakeupEvent event : mRecentWakeups) {
1198                                if (event.when > newEarliest) break;
1199                                n++; // number of now-stale entries at the list head
1200                            }
1201                            for (int i = 0; i < n; i++) {
1202                                mRecentWakeups.remove();
1203                            }
1204
1205                            recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
1206                        }
1207                    }
1208
1209                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1210                    rescheduleKernelAlarmsLocked();
1211
1212                    // now deliver the alarm intents
1213                    for (int i=0; i<triggerList.size(); i++) {
1214                        Alarm alarm = triggerList.get(i);
1215                        try {
1216                            if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
1217                            alarm.operation.send(mContext, 0,
1218                                    mBackgroundIntent.putExtra(
1219                                            Intent.EXTRA_ALARM_COUNT, alarm.count),
1220                                    mResultReceiver, mHandler);
1221                            
1222                            // we have an active broadcast so stay awake.
1223                            if (mBroadcastRefCount == 0) {
1224                                setWakelockWorkSource(alarm.operation, alarm.workSource);
1225                                mWakeLock.acquire();
1226                            }
1227                            final InFlight inflight = new InFlight(AlarmManagerService.this,
1228                                    alarm.operation, alarm.workSource);
1229                            mInFlight.add(inflight);
1230                            mBroadcastRefCount++;
1231
1232                            final BroadcastStats bs = inflight.mBroadcastStats;
1233                            bs.count++;
1234                            if (bs.nesting == 0) {
1235                                bs.nesting = 1;
1236                                bs.startTime = nowELAPSED;
1237                            } else {
1238                                bs.nesting++;
1239                            }
1240                            final FilterStats fs = inflight.mFilterStats;
1241                            fs.count++;
1242                            if (fs.nesting == 0) {
1243                                fs.nesting = 1;
1244                                fs.startTime = nowELAPSED;
1245                            } else {
1246                                fs.nesting++;
1247                            }
1248                            if (alarm.type == ELAPSED_REALTIME_WAKEUP
1249                                    || alarm.type == RTC_WAKEUP) {
1250                                bs.numWakeup++;
1251                                fs.numWakeup++;
1252                                ActivityManagerNative.noteWakeupAlarm(
1253                                        alarm.operation);
1254                            }
1255                        } catch (PendingIntent.CanceledException e) {
1256                            if (alarm.repeatInterval > 0) {
1257                                // This IntentSender is no longer valid, but this
1258                                // is a repeating alarm, so toss the hoser.
1259                                remove(alarm.operation);
1260                            }
1261                        } catch (RuntimeException e) {
1262                            Slog.w(TAG, "Failure sending alarm.", e);
1263                        }
1264                    }
1265                }
1266            }
1267        }
1268    }
1269
1270    /**
1271     * Attribute blame for a WakeLock.
1272     * @param pi PendingIntent to attribute blame to if ws is null.
1273     * @param ws WorkSource to attribute blame.
1274     */
1275    void setWakelockWorkSource(PendingIntent pi, WorkSource ws) {
1276        try {
1277            if (ws != null)

Large files files are truncated, but you can click here to view the full file