• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 
17 package com.android.server.am;
18 
19 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
20 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
21 import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_NONE;
22 
23 import android.annotation.Nullable;
24 import android.content.Intent;
25 import android.content.pm.ResolveInfo;
26 import android.os.Handler;
27 import android.os.SystemClock;
28 import android.os.UserHandle;
29 import android.util.Slog;
30 import android.util.SparseArray;
31 import android.util.SparseBooleanArray;
32 import android.util.SparseIntArray;
33 import android.util.proto.ProtoOutputStream;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.server.AlarmManagerInternal;
37 import com.android.server.LocalServices;
38 
39 import java.io.PrintWriter;
40 import java.text.SimpleDateFormat;
41 import java.util.ArrayList;
42 import java.util.Set;
43 
44 /**
45  * Manages ordered broadcast delivery, applying policy to mitigate the effects of
46  * slow receivers.
47  */
48 public class BroadcastDispatcher {
49     private static final String TAG = "BroadcastDispatcher";
50 
51     // Deferred broadcasts to one app; times are all uptime time base like
52     // other broadcast-related timekeeping
53     static class Deferrals {
54         final int uid;
55         long deferredAt;    // when we started deferring
56         long deferredBy;    // how long did we defer by last time?
57         long deferUntil;    // when does the next element become deliverable?
58         int alarmCount;
59 
60         final ArrayList<BroadcastRecord> broadcasts;
61 
Deferrals(int uid, long now, long backoff, int count)62         Deferrals(int uid, long now, long backoff, int count) {
63             this.uid = uid;
64             this.deferredAt = now;
65             this.deferredBy = backoff;
66             this.deferUntil = now + backoff;
67             this.alarmCount = count;
68             broadcasts = new ArrayList<>();
69         }
70 
add(BroadcastRecord br)71         void add(BroadcastRecord br) {
72             broadcasts.add(br);
73         }
74 
size()75         int size() {
76             return broadcasts.size();
77         }
78 
isEmpty()79         boolean isEmpty() {
80             return broadcasts.isEmpty();
81         }
82 
dumpDebug(ProtoOutputStream proto, long fieldId)83         void dumpDebug(ProtoOutputStream proto, long fieldId) {
84             for (BroadcastRecord br : broadcasts) {
85                 br.dumpDebug(proto, fieldId);
86             }
87         }
88 
dumpLocked(Dumper d)89         void dumpLocked(Dumper d) {
90             for (BroadcastRecord br : broadcasts) {
91                 d.dump(br);
92             }
93         }
94 
95         @Override
toString()96         public String toString() {
97             StringBuilder sb = new StringBuilder(128);
98             sb.append("Deferrals{uid=");
99             sb.append(uid);
100             sb.append(", deferUntil=");
101             sb.append(deferUntil);
102             sb.append(", #broadcasts=");
103             sb.append(broadcasts.size());
104             sb.append("}");
105             return sb.toString();
106         }
107     }
108 
109     // Carrying dump formatting state across multiple concatenated datasets
110     class Dumper {
111         final PrintWriter mPw;
112         final String mQueueName;
113         final String mDumpPackage;
114         final SimpleDateFormat mSdf;
115         boolean mPrinted;
116         boolean mNeedSep;
117         String mHeading;
118         String mLabel;
119         int mOrdinal;
120 
Dumper(PrintWriter pw, String queueName, String dumpPackage, SimpleDateFormat sdf)121         Dumper(PrintWriter pw, String queueName, String dumpPackage, SimpleDateFormat sdf) {
122             mPw = pw;
123             mQueueName = queueName;
124             mDumpPackage = dumpPackage;
125             mSdf = sdf;
126 
127             mPrinted = false;
128             mNeedSep = true;
129         }
130 
setHeading(String heading)131         void setHeading(String heading) {
132             mHeading = heading;
133             mPrinted = false;
134         }
135 
setLabel(String label)136         void setLabel(String label) {
137             //"  Active Ordered Broadcast " + mQueueName + " #" + i + ":"
138             mLabel = "  " + label + " " + mQueueName + " #";
139             mOrdinal = 0;
140         }
141 
didPrint()142         boolean didPrint() {
143             return mPrinted;
144         }
145 
dump(BroadcastRecord br)146         void dump(BroadcastRecord br) {
147             if (mDumpPackage == null || mDumpPackage.equals(br.callerPackage)) {
148                 if (!mPrinted) {
149                     if (mNeedSep) {
150                         mPw.println();
151                     }
152                     mPrinted = true;
153                     mNeedSep = true;
154                     mPw.println("  " + mHeading + " [" + mQueueName + "]:");
155                 }
156                 mPw.println(mLabel + mOrdinal + ":");
157                 mOrdinal++;
158 
159                 br.dump(mPw, "    ", mSdf);
160             }
161         }
162     }
163 
164     private final Object mLock;
165     private final BroadcastQueue mQueue;
166     private final BroadcastConstants mConstants;
167     private final Handler mHandler;
168     private AlarmManagerInternal mAlarm;
169 
170     // Current alarm targets; mapping uid -> in-flight alarm count
171     final SparseIntArray mAlarmUids = new SparseIntArray();
172     final AlarmManagerInternal.InFlightListener mAlarmListener =
173             new AlarmManagerInternal.InFlightListener() {
174         @Override
175         public void broadcastAlarmPending(final int recipientUid) {
176             synchronized (mLock) {
177                 final int newCount = mAlarmUids.get(recipientUid, 0) + 1;
178                 mAlarmUids.put(recipientUid, newCount);
179                 // any deferred broadcasts to this app now get fast-tracked
180                 final int numEntries = mDeferredBroadcasts.size();
181                 for (int i = 0; i < numEntries; i++) {
182                     if (recipientUid == mDeferredBroadcasts.get(i).uid) {
183                         Deferrals d = mDeferredBroadcasts.remove(i);
184                         mAlarmBroadcasts.add(d);
185                         break;
186                     }
187                 }
188             }
189         }
190 
191         @Override
192         public void broadcastAlarmComplete(final int recipientUid) {
193             synchronized (mLock) {
194                 final int newCount = mAlarmUids.get(recipientUid, 0) - 1;
195                 if (newCount >= 0) {
196                     mAlarmUids.put(recipientUid, newCount);
197                 } else {
198                     Slog.wtf(TAG, "Undercount of broadcast alarms in flight for " + recipientUid);
199                     mAlarmUids.put(recipientUid, 0);
200                 }
201 
202                 // No longer an alarm target, so resume ordinary deferral policy
203                 if (newCount <= 0) {
204                     final int numEntries = mAlarmBroadcasts.size();
205                     for (int i = 0; i < numEntries; i++) {
206                         if (recipientUid == mAlarmBroadcasts.get(i).uid) {
207                             Deferrals d = mAlarmBroadcasts.remove(i);
208                             insertLocked(mDeferredBroadcasts, d);
209                             break;
210                         }
211                     }
212                 }
213             }
214         }
215     };
216 
217     // Queue recheck operation used to tickle broadcast delivery when appropriate
218     final Runnable mScheduleRunnable = new Runnable() {
219         @Override
220         public void run() {
221             synchronized (mLock) {
222                 if (DEBUG_BROADCAST_DEFERRAL) {
223                     Slog.v(TAG, "Deferral recheck of pending broadcasts");
224                 }
225                 mQueue.scheduleBroadcastsLocked();
226                 mRecheckScheduled = false;
227             }
228         }
229     };
230     private boolean mRecheckScheduled = false;
231 
232     // Usual issuance-order outbound queue
233     private final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
234     // General deferrals not holding up alarms
235     private final ArrayList<Deferrals> mDeferredBroadcasts = new ArrayList<>();
236     // Deferrals that *are* holding up alarms; ordered by alarm dispatch time
237     private final ArrayList<Deferrals> mAlarmBroadcasts = new ArrayList<>();
238 
239     // Next outbound broadcast, established by getNextBroadcastLocked()
240     private BroadcastRecord mCurrentBroadcast;
241 
242     // Map userId to its deferred boot completed broadcasts.
243     private SparseArray<DeferredBootCompletedBroadcastPerUser> mUser2Deferred = new SparseArray<>();
244 
245     /**
246      * Deferred LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts that is sent to a user.
247      */
248     static class DeferredBootCompletedBroadcastPerUser {
249         private int mUserId;
250         // UID that has process started at least once, ready to execute LOCKED_BOOT_COMPLETED
251         // receivers.
252         @VisibleForTesting
253         SparseBooleanArray mUidReadyForLockedBootCompletedBroadcast = new SparseBooleanArray();
254         // UID that has process started at least once, ready to execute BOOT_COMPLETED receivers.
255         @VisibleForTesting
256         SparseBooleanArray mUidReadyForBootCompletedBroadcast = new SparseBooleanArray();
257         // Map UID to deferred LOCKED_BOOT_COMPLETED broadcasts.
258         // LOCKED_BOOT_COMPLETED broadcast receivers are deferred until the first time the uid has
259         // any process started.
260         @VisibleForTesting
261         SparseArray<BroadcastRecord> mDeferredLockedBootCompletedBroadcasts = new SparseArray<>();
262         // is the LOCKED_BOOT_COMPLETED broadcast received by the user.
263         @VisibleForTesting
264         boolean mLockedBootCompletedBroadcastReceived;
265         // Map UID to deferred BOOT_COMPLETED broadcasts.
266         // BOOT_COMPLETED broadcast receivers are deferred until the first time the uid has any
267         // process started.
268         @VisibleForTesting
269         SparseArray<BroadcastRecord> mDeferredBootCompletedBroadcasts = new SparseArray<>();
270         // is the BOOT_COMPLETED broadcast received by the user.
271         @VisibleForTesting
272         boolean mBootCompletedBroadcastReceived;
273 
DeferredBootCompletedBroadcastPerUser(int userId)274         DeferredBootCompletedBroadcastPerUser(int userId) {
275             this.mUserId = userId;
276         }
277 
updateUidReady(int uid)278         public void updateUidReady(int uid) {
279             if (!mLockedBootCompletedBroadcastReceived
280                     || mDeferredLockedBootCompletedBroadcasts.size() != 0) {
281                 mUidReadyForLockedBootCompletedBroadcast.put(uid, true);
282             }
283             if (!mBootCompletedBroadcastReceived
284                     || mDeferredBootCompletedBroadcasts.size() != 0) {
285                 mUidReadyForBootCompletedBroadcast.put(uid, true);
286             }
287         }
288 
enqueueBootCompletedBroadcasts(String action, SparseArray<BroadcastRecord> deferred)289         public void enqueueBootCompletedBroadcasts(String action,
290                 SparseArray<BroadcastRecord> deferred) {
291             if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
292                 enqueueBootCompletedBroadcasts(deferred, mDeferredLockedBootCompletedBroadcasts,
293                         mUidReadyForLockedBootCompletedBroadcast);
294                 mLockedBootCompletedBroadcastReceived = true;
295                 if (DEBUG_BROADCAST_DEFERRAL) {
296                     dumpBootCompletedBroadcastRecord(mDeferredLockedBootCompletedBroadcasts);
297                 }
298             } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
299                 enqueueBootCompletedBroadcasts(deferred, mDeferredBootCompletedBroadcasts,
300                         mUidReadyForBootCompletedBroadcast);
301                 mBootCompletedBroadcastReceived = true;
302                 if (DEBUG_BROADCAST_DEFERRAL) {
303                     dumpBootCompletedBroadcastRecord(mDeferredBootCompletedBroadcasts);
304                 }
305             }
306         }
307 
308         /**
309          * Merge UID to BroadcastRecord map into {@link #mDeferredBootCompletedBroadcasts} or
310          * {@link #mDeferredLockedBootCompletedBroadcasts}
311          * @param from the UID to BroadcastRecord map.
312          * @param into The UID to list of BroadcastRecord map.
313          */
enqueueBootCompletedBroadcasts(SparseArray<BroadcastRecord> from, SparseArray<BroadcastRecord> into, SparseBooleanArray uidReadyForReceiver)314         private void enqueueBootCompletedBroadcasts(SparseArray<BroadcastRecord> from,
315                 SparseArray<BroadcastRecord> into, SparseBooleanArray uidReadyForReceiver) {
316             // remove unwanted uids from uidReadyForReceiver.
317             for (int i = uidReadyForReceiver.size() - 1; i >= 0; i--) {
318                 if (from.indexOfKey(uidReadyForReceiver.keyAt(i)) < 0) {
319                     uidReadyForReceiver.removeAt(i);
320                 }
321             }
322             for (int i = 0, size = from.size(); i < size; i++) {
323                 final int uid = from.keyAt(i);
324                 into.put(uid, from.valueAt(i));
325                 if (uidReadyForReceiver.indexOfKey(uid) < 0) {
326                     // uid is wanted but not ready.
327                     uidReadyForReceiver.put(uid, false);
328                 }
329             }
330         }
331 
dequeueDeferredBootCompletedBroadcast( boolean isAllUidReady)332         public @Nullable BroadcastRecord dequeueDeferredBootCompletedBroadcast(
333                 boolean isAllUidReady) {
334             BroadcastRecord next = dequeueDeferredBootCompletedBroadcast(
335                     mDeferredLockedBootCompletedBroadcasts,
336                     mUidReadyForLockedBootCompletedBroadcast, isAllUidReady);
337             if (next == null) {
338                 next = dequeueDeferredBootCompletedBroadcast(mDeferredBootCompletedBroadcasts,
339                         mUidReadyForBootCompletedBroadcast, isAllUidReady);
340             }
341             return next;
342         }
343 
dequeueDeferredBootCompletedBroadcast( SparseArray<BroadcastRecord> uid2br, SparseBooleanArray uidReadyForReceiver, boolean isAllUidReady)344         private @Nullable BroadcastRecord dequeueDeferredBootCompletedBroadcast(
345                 SparseArray<BroadcastRecord> uid2br, SparseBooleanArray uidReadyForReceiver,
346                 boolean isAllUidReady) {
347             for (int i = 0, size = uid2br.size(); i < size; i++) {
348                 final int uid = uid2br.keyAt(i);
349                 if (isAllUidReady || uidReadyForReceiver.get(uid)) {
350                     final BroadcastRecord br = uid2br.valueAt(i);
351                     if (DEBUG_BROADCAST_DEFERRAL) {
352                         final Object receiver = br.receivers.get(0);
353                         if (receiver instanceof BroadcastFilter) {
354                             if (DEBUG_BROADCAST_DEFERRAL) {
355                                 Slog.i(TAG, "getDeferredBootCompletedBroadcast uid:" + uid
356                                         + " BroadcastFilter:" + (BroadcastFilter) receiver
357                                         + " broadcast:" + br.intent.getAction());
358                             }
359                         } else /* if (receiver instanceof ResolveInfo) */ {
360                             ResolveInfo info = (ResolveInfo) receiver;
361                             String packageName = info.activityInfo.applicationInfo.packageName;
362                             if (DEBUG_BROADCAST_DEFERRAL) {
363                                 Slog.i(TAG, "getDeferredBootCompletedBroadcast uid:" + uid
364                                         + " packageName:" + packageName
365                                         + " broadcast:" + br.intent.getAction());
366                             }
367                         }
368                     }
369                     // remove the BroadcastRecord.
370                     uid2br.removeAt(i);
371                     if (uid2br.size() == 0) {
372                         // All deferred receivers are executed, do not need uidReadyForReceiver
373                         // any more.
374                         uidReadyForReceiver.clear();
375                     }
376                     return br;
377                 }
378             }
379             return null;
380         }
381 
getDeferredList(String action)382         private @Nullable SparseArray<BroadcastRecord> getDeferredList(String action) {
383             SparseArray<BroadcastRecord> brs = null;
384             if (action.equals(Intent.ACTION_LOCKED_BOOT_COMPLETED)) {
385                 brs = mDeferredLockedBootCompletedBroadcasts;
386             } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
387                 brs = mDeferredBootCompletedBroadcasts;
388             }
389             return brs;
390         }
391 
392         /**
393          * Return the total number of UIDs in all BroadcastRecord in
394          * {@link #mDeferredBootCompletedBroadcasts} or
395          * {@link #mDeferredLockedBootCompletedBroadcasts}
396          */
getBootCompletedBroadcastsUidsSize(String action)397         private int getBootCompletedBroadcastsUidsSize(String action) {
398             SparseArray<BroadcastRecord> brs = getDeferredList(action);
399             return brs != null ? brs.size() : 0;
400         }
401 
402         /**
403          * Return the total number of receivers in all BroadcastRecord in
404          * {@link #mDeferredBootCompletedBroadcasts} or
405          * {@link #mDeferredLockedBootCompletedBroadcasts}
406          */
getBootCompletedBroadcastsReceiversSize(String action)407         private int getBootCompletedBroadcastsReceiversSize(String action) {
408             SparseArray<BroadcastRecord> brs = getDeferredList(action);
409             if (brs == null) {
410                 return 0;
411             }
412             int size = 0;
413             for (int i = 0, s = brs.size(); i < s; i++) {
414                 size += brs.valueAt(i).receivers.size();
415             }
416             return size;
417         }
418 
dump(Dumper dumper, String action)419         public void dump(Dumper dumper, String action) {
420             SparseArray<BroadcastRecord> brs = getDeferredList(action);
421             if (brs == null) {
422                 return;
423             }
424             for (int i = 0, size = brs.size(); i < size; i++) {
425                 dumper.dump(brs.valueAt(i));
426             }
427         }
428 
dumpDebug(ProtoOutputStream proto, long fieldId)429         public void dumpDebug(ProtoOutputStream proto, long fieldId) {
430             for (int i = 0, size = mDeferredLockedBootCompletedBroadcasts.size(); i < size; i++) {
431                 mDeferredLockedBootCompletedBroadcasts.valueAt(i).dumpDebug(proto, fieldId);
432             }
433             for (int i = 0, size = mDeferredBootCompletedBroadcasts.size(); i < size; i++) {
434                 mDeferredBootCompletedBroadcasts.valueAt(i).dumpDebug(proto, fieldId);
435             }
436         }
437 
dumpBootCompletedBroadcastRecord(SparseArray<BroadcastRecord> brs)438         private void dumpBootCompletedBroadcastRecord(SparseArray<BroadcastRecord> brs) {
439             for (int i = 0, size = brs.size(); i < size; i++) {
440                 final Object receiver = brs.valueAt(i).receivers.get(0);
441                 String packageName = null;
442                 if (receiver instanceof BroadcastFilter) {
443                     BroadcastFilter recv = (BroadcastFilter) receiver;
444                     packageName = recv.receiverList.app.processName;
445                 } else /* if (receiver instanceof ResolveInfo) */ {
446                     ResolveInfo info = (ResolveInfo) receiver;
447                     packageName = info.activityInfo.applicationInfo.packageName;
448                 }
449                 Slog.i(TAG, "uid:" + brs.keyAt(i)
450                         + " packageName:" + packageName
451                         + " receivers:" + brs.valueAt(i).receivers.size());
452             }
453         }
454     }
455 
getDeferredPerUser(int userId)456     private DeferredBootCompletedBroadcastPerUser getDeferredPerUser(int userId) {
457         if (mUser2Deferred.contains(userId)) {
458             return mUser2Deferred.get(userId);
459         } else {
460             final DeferredBootCompletedBroadcastPerUser temp =
461                     new DeferredBootCompletedBroadcastPerUser(userId);
462             mUser2Deferred.put(userId, temp);
463             return temp;
464         }
465     }
466 
467     /**
468      * ActivityManagerService.attachApplication() call this method to notify that the UID is ready
469      * to accept deferred LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts.
470      * @param uid
471      */
updateUidReadyForBootCompletedBroadcastLocked(int uid)472     public void updateUidReadyForBootCompletedBroadcastLocked(int uid) {
473         getDeferredPerUser(UserHandle.getUserId(uid)).updateUidReady(uid);
474     }
475 
dequeueDeferredBootCompletedBroadcast()476     private @Nullable BroadcastRecord dequeueDeferredBootCompletedBroadcast() {
477         final boolean isAllUidReady = (mQueue.mService.mConstants.mDeferBootCompletedBroadcast
478                 == DEFER_BOOT_COMPLETED_BROADCAST_NONE);
479         BroadcastRecord next = null;
480         for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
481             next = mUser2Deferred.valueAt(i).dequeueDeferredBootCompletedBroadcast(isAllUidReady);
482             if (next != null) {
483                 break;
484             }
485         }
486         return next;
487     }
488 
489     /**
490      * Constructed & sharing a lock with its associated BroadcastQueue instance
491      */
BroadcastDispatcher(BroadcastQueue queue, BroadcastConstants constants, Handler handler, Object lock)492     public BroadcastDispatcher(BroadcastQueue queue, BroadcastConstants constants,
493             Handler handler, Object lock) {
494         mQueue = queue;
495         mConstants = constants;
496         mHandler = handler;
497         mLock = lock;
498     }
499 
500     /**
501      * Spin up the integration with the alarm manager service; done lazily to manage
502      * service availability ordering during boot.
503      */
start()504     public void start() {
505         // Set up broadcast alarm tracking
506         mAlarm = LocalServices.getService(AlarmManagerInternal.class);
507         mAlarm.registerInFlightListener(mAlarmListener);
508     }
509 
510     /**
511      * Standard contents-are-empty check
512      */
isEmpty()513     public boolean isEmpty() {
514         synchronized (mLock) {
515             return isIdle()
516                     && getBootCompletedBroadcastsUidsSize(Intent.ACTION_LOCKED_BOOT_COMPLETED) == 0
517                     && getBootCompletedBroadcastsUidsSize(Intent.ACTION_BOOT_COMPLETED) == 0;
518         }
519     }
520 
521     /**
522      * Have less check than {@link #isEmpty()}.
523      * The dispatcher is considered as idle even with deferred LOCKED_BOOT_COMPLETED/BOOT_COMPLETED
524      * broadcasts because those can be deferred until the first time the uid's process is started.
525      * @return
526      */
isIdle()527     public boolean isIdle() {
528         synchronized (mLock) {
529             return mCurrentBroadcast == null
530                     && mOrderedBroadcasts.isEmpty()
531                     && isDeferralsListEmpty(mDeferredBroadcasts)
532                     && isDeferralsListEmpty(mAlarmBroadcasts);
533         }
534     }
535 
pendingInDeferralsList(ArrayList<Deferrals> list)536     private static int pendingInDeferralsList(ArrayList<Deferrals> list) {
537         int pending = 0;
538         final int numEntries = list.size();
539         for (int i = 0; i < numEntries; i++) {
540             pending += list.get(i).size();
541         }
542         return pending;
543     }
544 
isDeferralsListEmpty(ArrayList<Deferrals> list)545     private static boolean isDeferralsListEmpty(ArrayList<Deferrals> list) {
546         return pendingInDeferralsList(list) == 0;
547     }
548 
549     /**
550      * Strictly for logging, describe the currently pending contents in a human-
551      * readable way
552      */
describeStateLocked()553     public String describeStateLocked() {
554         final StringBuilder sb = new StringBuilder(128);
555         if (mCurrentBroadcast != null) {
556             sb.append("1 in flight, ");
557         }
558         sb.append(mOrderedBroadcasts.size());
559         sb.append(" ordered");
560         int n = pendingInDeferralsList(mAlarmBroadcasts);
561         if (n > 0) {
562             sb.append(", ");
563             sb.append(n);
564             sb.append(" deferrals in alarm recipients");
565         }
566         n = pendingInDeferralsList(mDeferredBroadcasts);
567         if (n > 0) {
568             sb.append(", ");
569             sb.append(n);
570             sb.append(" deferred");
571         }
572         n = getBootCompletedBroadcastsUidsSize(Intent.ACTION_LOCKED_BOOT_COMPLETED);
573         if (n > 0) {
574             sb.append(", ");
575             sb.append(n);
576             sb.append(" deferred LOCKED_BOOT_COMPLETED/");
577             sb.append(getBootCompletedBroadcastsReceiversSize(Intent.ACTION_LOCKED_BOOT_COMPLETED));
578             sb.append(" receivers");
579         }
580 
581         n = getBootCompletedBroadcastsUidsSize(Intent.ACTION_BOOT_COMPLETED);
582         if (n > 0) {
583             sb.append(", ");
584             sb.append(n);
585             sb.append(" deferred BOOT_COMPLETED/");
586             sb.append(getBootCompletedBroadcastsReceiversSize(Intent.ACTION_BOOT_COMPLETED));
587             sb.append(" receivers");
588         }
589         return sb.toString();
590     }
591 
592     // ----------------------------------
593     // BroadcastQueue operation support
enqueueOrderedBroadcastLocked(BroadcastRecord r)594     void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
595         if (r.receivers == null || r.receivers.isEmpty()) {
596             mOrderedBroadcasts.add(r);
597             return;
598         }
599 
600         if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(r.intent.getAction())) {
601             // Create one BroadcastRecord for each UID that can be deferred.
602             final SparseArray<BroadcastRecord> deferred =
603                     r.splitDeferredBootCompletedBroadcastLocked(mQueue.mService.mInternal,
604                             mQueue.mService.mConstants.mDeferBootCompletedBroadcast);
605             getDeferredPerUser(r.userId).enqueueBootCompletedBroadcasts(
606                     Intent.ACTION_LOCKED_BOOT_COMPLETED, deferred);
607             if (!r.receivers.isEmpty()) {
608                 // The non-deferred receivers.
609                 mOrderedBroadcasts.add(r);
610                 return;
611             }
612         } else if (Intent.ACTION_BOOT_COMPLETED.equals(r.intent.getAction())) {
613             // Create one BroadcastRecord for each UID that can be deferred.
614             final SparseArray<BroadcastRecord> deferred =
615                     r.splitDeferredBootCompletedBroadcastLocked(mQueue.mService.mInternal,
616                             mQueue.mService.mConstants.mDeferBootCompletedBroadcast);
617             getDeferredPerUser(r.userId).enqueueBootCompletedBroadcasts(
618                     Intent.ACTION_BOOT_COMPLETED, deferred);
619             if (!r.receivers.isEmpty()) {
620                 // The non-deferred receivers.
621                 mOrderedBroadcasts.add(r);
622                 return;
623             }
624         } else {
625             mOrderedBroadcasts.add(r);
626         }
627     }
628 
629     /**
630      * Return the total number of UIDs in all deferred boot completed BroadcastRecord.
631      */
getBootCompletedBroadcastsUidsSize(String action)632     private int getBootCompletedBroadcastsUidsSize(String action) {
633         int size = 0;
634         for (int i = 0, s = mUser2Deferred.size(); i < s; i++) {
635             size += mUser2Deferred.valueAt(i).getBootCompletedBroadcastsUidsSize(action);
636         }
637         return size;
638     }
639 
640     /**
641      * Return the total number of receivers in all deferred boot completed BroadcastRecord.
642      */
getBootCompletedBroadcastsReceiversSize(String action)643     private int getBootCompletedBroadcastsReceiversSize(String action) {
644         int size = 0;
645         for (int i = 0, s = mUser2Deferred.size(); i < s; i++) {
646             size += mUser2Deferred.valueAt(i).getBootCompletedBroadcastsReceiversSize(action);
647         }
648         return size;
649     }
650 
651     // Returns the now-replaced broadcast record, or null if none
replaceBroadcastLocked(BroadcastRecord r, String typeForLogging)652     BroadcastRecord replaceBroadcastLocked(BroadcastRecord r, String typeForLogging) {
653         // Simple case, in the ordinary queue.
654         BroadcastRecord old = replaceBroadcastLocked(mOrderedBroadcasts, r, typeForLogging);
655 
656         // If we didn't find it, less-simple:  in a deferral queue?
657         if (old == null) {
658             old = replaceDeferredBroadcastLocked(mAlarmBroadcasts, r, typeForLogging);
659         }
660         if (old == null) {
661             old = replaceDeferredBroadcastLocked(mDeferredBroadcasts, r, typeForLogging);
662         }
663         return old;
664     }
665 
replaceDeferredBroadcastLocked(ArrayList<Deferrals> list, BroadcastRecord r, String typeForLogging)666     private BroadcastRecord replaceDeferredBroadcastLocked(ArrayList<Deferrals> list,
667             BroadcastRecord r, String typeForLogging) {
668         BroadcastRecord old;
669         final int numEntries = list.size();
670         for (int i = 0; i < numEntries; i++) {
671             final Deferrals d = list.get(i);
672             old = replaceBroadcastLocked(d.broadcasts, r, typeForLogging);
673             if (old != null) {
674                 return old;
675             }
676         }
677         return null;
678     }
679 
replaceBroadcastLocked(ArrayList<BroadcastRecord> list, BroadcastRecord r, String typeForLogging)680     private BroadcastRecord replaceBroadcastLocked(ArrayList<BroadcastRecord> list,
681             BroadcastRecord r, String typeForLogging) {
682         BroadcastRecord old;
683         final Intent intent = r.intent;
684         // Any in-flight broadcast has already been popped, and cannot be replaced.
685         // (This preserves existing behavior of the replacement API)
686         for (int i = list.size() - 1; i >= 0; i--) {
687             old = list.get(i);
688             if (old.userId == r.userId && intent.filterEquals(old.intent)) {
689                 if (DEBUG_BROADCAST) {
690                     Slog.v(TAG, "***** Replacing " + typeForLogging
691                             + " [" + mQueue.mQueueName + "]: " + intent);
692                 }
693                 // Clone deferral state too if any
694                 r.deferred = old.deferred;
695                 list.set(i, r);
696                 return old;
697             }
698         }
699         return null;
700     }
701 
cleanupDisabledPackageReceiversLocked(final String packageName, Set<String> filterByClasses, final int userId, final boolean doit)702     boolean cleanupDisabledPackageReceiversLocked(final String packageName,
703             Set<String> filterByClasses, final int userId, final boolean doit) {
704         // Note: fast short circuits when 'doit' is false, as soon as we hit any
705         // "yes we would do something" circumstance
706         boolean didSomething = cleanupBroadcastListDisabledReceiversLocked(mOrderedBroadcasts,
707                 packageName, filterByClasses, userId, doit);
708         if (doit || !didSomething) {
709             ArrayList<BroadcastRecord> lockedBootCompletedBroadcasts = new ArrayList<>();
710             for (int u = 0, usize = mUser2Deferred.size(); u < usize; u++) {
711                 SparseArray<BroadcastRecord> brs =
712                         mUser2Deferred.valueAt(u).mDeferredLockedBootCompletedBroadcasts;
713                 for (int i = 0, size = brs.size(); i < size; i++) {
714                     lockedBootCompletedBroadcasts.add(brs.valueAt(i));
715                 }
716             }
717             didSomething = cleanupBroadcastListDisabledReceiversLocked(
718                     lockedBootCompletedBroadcasts,
719                     packageName, filterByClasses, userId, doit);
720         }
721         if (doit || !didSomething) {
722             ArrayList<BroadcastRecord> bootCompletedBroadcasts = new ArrayList<>();
723             for (int u = 0, usize = mUser2Deferred.size(); u < usize; u++) {
724                 SparseArray<BroadcastRecord> brs =
725                         mUser2Deferred.valueAt(u).mDeferredBootCompletedBroadcasts;
726                 for (int i = 0, size = brs.size(); i < size; i++) {
727                     bootCompletedBroadcasts.add(brs.valueAt(i));
728                 }
729             }
730             didSomething = cleanupBroadcastListDisabledReceiversLocked(bootCompletedBroadcasts,
731                     packageName, filterByClasses, userId, doit);
732         }
733         if (doit || !didSomething) {
734             didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmBroadcasts,
735                     packageName, filterByClasses, userId, doit);
736         }
737         if (doit || !didSomething) {
738             didSomething |= cleanupDeferralsListDisabledReceiversLocked(mDeferredBroadcasts,
739                     packageName, filterByClasses, userId, doit);
740         }
741         if ((doit || !didSomething) && mCurrentBroadcast != null) {
742             didSomething |= mCurrentBroadcast.cleanupDisabledPackageReceiversLocked(
743                     packageName, filterByClasses, userId, doit);
744         }
745 
746         return didSomething;
747     }
748 
cleanupDeferralsListDisabledReceiversLocked(ArrayList<Deferrals> list, final String packageName, Set<String> filterByClasses, final int userId, final boolean doit)749     private boolean cleanupDeferralsListDisabledReceiversLocked(ArrayList<Deferrals> list,
750             final String packageName, Set<String> filterByClasses, final int userId,
751             final boolean doit) {
752         boolean didSomething = false;
753         for (Deferrals d : list) {
754             didSomething = cleanupBroadcastListDisabledReceiversLocked(d.broadcasts,
755                     packageName, filterByClasses, userId, doit);
756             if (!doit && didSomething) {
757                 return true;
758             }
759         }
760         return didSomething;
761     }
762 
cleanupBroadcastListDisabledReceiversLocked(ArrayList<BroadcastRecord> list, final String packageName, Set<String> filterByClasses, final int userId, final boolean doit)763     private boolean cleanupBroadcastListDisabledReceiversLocked(ArrayList<BroadcastRecord> list,
764             final String packageName, Set<String> filterByClasses, final int userId,
765             final boolean doit) {
766         boolean didSomething = false;
767         for (BroadcastRecord br : list) {
768             didSomething |= br.cleanupDisabledPackageReceiversLocked(packageName,
769                     filterByClasses, userId, doit);
770             if (!doit && didSomething) {
771                 return true;
772             }
773         }
774         return didSomething;
775     }
776 
777     /**
778      * Standard proto dump entry point
779      */
dumpDebug(ProtoOutputStream proto, long fieldId)780     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
781         if (mCurrentBroadcast != null) {
782             mCurrentBroadcast.dumpDebug(proto, fieldId);
783         }
784         for (Deferrals d : mAlarmBroadcasts) {
785             d.dumpDebug(proto, fieldId);
786         }
787         for (BroadcastRecord br : mOrderedBroadcasts) {
788             br.dumpDebug(proto, fieldId);
789         }
790         for (Deferrals d : mDeferredBroadcasts) {
791             d.dumpDebug(proto, fieldId);
792         }
793 
794         for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
795             mUser2Deferred.valueAt(i).dumpDebug(proto, fieldId);
796         }
797     }
798 
799     // ----------------------------------
800     // Dispatch & deferral management
801 
getActiveBroadcastLocked()802     public BroadcastRecord getActiveBroadcastLocked() {
803         return mCurrentBroadcast;
804     }
805 
806     /**
807      * If there is a deferred broadcast that is being sent to an alarm target, return
808      * that one.  If there's no deferred alarm target broadcast but there is one
809      * that has reached the end of its deferral, return that.
810      *
811      * This stages the broadcast internally until it is retired, and returns that
812      * staged record if this is called repeatedly, until retireBroadcast(r) is called.
813      */
getNextBroadcastLocked(final long now)814     public BroadcastRecord getNextBroadcastLocked(final long now) {
815         if (mCurrentBroadcast != null) {
816             return mCurrentBroadcast;
817         }
818 
819         final boolean someQueued = !mOrderedBroadcasts.isEmpty();
820 
821         BroadcastRecord next = null;
822 
823         if (next == null) {
824             next = dequeueDeferredBootCompletedBroadcast();
825         }
826 
827         if (next == null && !mAlarmBroadcasts.isEmpty()) {
828             next = popLocked(mAlarmBroadcasts);
829             if (DEBUG_BROADCAST_DEFERRAL && next != null) {
830                 Slog.i(TAG, "Next broadcast from alarm targets: " + next);
831             }
832         }
833 
834         if (next == null && !mDeferredBroadcasts.isEmpty()) {
835             // We're going to deliver either:
836             // 1. the next "overdue" deferral; or
837             // 2. the next ordinary ordered broadcast; *or*
838             // 3. the next not-yet-overdue deferral.
839 
840             for (int i = 0; i < mDeferredBroadcasts.size(); i++) {
841                 Deferrals d = mDeferredBroadcasts.get(i);
842                 if (now < d.deferUntil && someQueued) {
843                     // stop looking when we haven't hit the next time-out boundary
844                     // but only if we have un-deferred broadcasts waiting,
845                     // otherwise we can deliver whatever deferred broadcast
846                     // is next available.
847                     break;
848                 }
849 
850                 if (d.broadcasts.size() > 0) {
851                     next = d.broadcasts.remove(0);
852                     // apply deferral-interval decay policy and move this uid's
853                     // deferred broadcasts down in the delivery queue accordingly
854                     mDeferredBroadcasts.remove(i); // already 'd'
855                     d.deferredBy = calculateDeferral(d.deferredBy);
856                     d.deferUntil += d.deferredBy;
857                     insertLocked(mDeferredBroadcasts, d);
858                     if (DEBUG_BROADCAST_DEFERRAL) {
859                         Slog.i(TAG, "Next broadcast from deferrals " + next
860                                 + ", deferUntil now " + d.deferUntil);
861                     }
862                     break;
863                 }
864             }
865         }
866 
867         if (next == null && someQueued) {
868             next = mOrderedBroadcasts.remove(0);
869             if (DEBUG_BROADCAST_DEFERRAL) {
870                 Slog.i(TAG, "Next broadcast from main queue: " + next);
871             }
872         }
873 
874         mCurrentBroadcast = next;
875         return next;
876     }
877 
878     /**
879      * Called after the broadcast queue finishes processing the currently
880      * active broadcast (obtained by calling getNextBroadcastLocked()).
881      */
retireBroadcastLocked(final BroadcastRecord r)882     public void retireBroadcastLocked(final BroadcastRecord r) {
883         // ERROR if 'r' is not the active broadcast
884         if (r != mCurrentBroadcast) {
885             Slog.wtf(TAG, "Retiring broadcast " + r
886                     + " doesn't match current outgoing " + mCurrentBroadcast);
887         }
888         mCurrentBroadcast = null;
889     }
890 
891     /**
892      * Called prior to broadcast dispatch to check whether the intended
893      * recipient is currently subject to deferral policy.
894      */
isDeferringLocked(final int uid)895     public boolean isDeferringLocked(final int uid) {
896         Deferrals d = findUidLocked(uid);
897         if (d != null && d.broadcasts.isEmpty()) {
898             // once we've caught up with deferred broadcasts to this uid
899             // and time has advanced sufficiently that we wouldn't be
900             // deferring newly-enqueued ones, we're back to normal policy.
901             if (SystemClock.uptimeMillis() >= d.deferUntil) {
902                 if (DEBUG_BROADCAST_DEFERRAL) {
903                     Slog.i(TAG, "No longer deferring broadcasts to uid " + d.uid);
904                 }
905                 removeDeferral(d);
906                 return false;
907             }
908         }
909         return (d != null);
910     }
911 
912     /**
913      * Defer broadcasts for the given app.  If 'br' is non-null, this also makes
914      * sure that broadcast record is enqueued as the next upcoming broadcast for
915      * the app.
916      */
startDeferring(final int uid)917     public void startDeferring(final int uid) {
918         synchronized (mLock) {
919             Deferrals d = findUidLocked(uid);
920 
921             // If we're not yet tracking this app, set up that bookkeeping
922             if (d == null) {
923                 // Start a new deferral
924                 final long now = SystemClock.uptimeMillis();
925                 d = new Deferrals(uid,
926                         now,
927                         mConstants.DEFERRAL,
928                         mAlarmUids.get(uid, 0));
929                 if (DEBUG_BROADCAST_DEFERRAL) {
930                     Slog.i(TAG, "Now deferring broadcasts to " + uid
931                             + " until " + d.deferUntil);
932                 }
933                 // where it goes depends on whether it is coming into an alarm-related situation
934                 if (d.alarmCount == 0) {
935                     // common case, put it in the ordinary priority queue
936                     insertLocked(mDeferredBroadcasts, d);
937                     scheduleDeferralCheckLocked(true);
938                 } else {
939                     // alarm-related: strict order-encountered
940                     mAlarmBroadcasts.add(d);
941                 }
942             } else {
943                 // We're already deferring, but something was slow again.  Reset the
944                 // deferral decay progression.
945                 d.deferredBy = mConstants.DEFERRAL;
946                 if (DEBUG_BROADCAST_DEFERRAL) {
947                     Slog.i(TAG, "Uid " + uid + " slow again, deferral interval reset to "
948                             + d.deferredBy);
949                 }
950             }
951         }
952     }
953 
954     /**
955      * Key entry point when a broadcast about to be delivered is instead
956      * set aside for deferred delivery
957      */
addDeferredBroadcast(final int uid, BroadcastRecord br)958     public void addDeferredBroadcast(final int uid, BroadcastRecord br) {
959         if (DEBUG_BROADCAST_DEFERRAL) {
960             Slog.i(TAG, "Enqueuing deferred broadcast " + br);
961         }
962         synchronized (mLock) {
963             Deferrals d = findUidLocked(uid);
964             if (d == null) {
965                 Slog.wtf(TAG, "Adding deferred broadcast but not tracking " + uid);
966             } else {
967                 if (br == null) {
968                     Slog.wtf(TAG, "Deferring null broadcast to " + uid);
969                 } else {
970                     br.deferred = true;
971                     d.add(br);
972                 }
973             }
974         }
975     }
976 
977     /**
978      * When there are deferred broadcasts, we need to make sure to recheck the
979      * dispatch queue when they come due.  Alarm-sensitive deferrals get dispatched
980      * aggressively, so we only need to use the ordinary deferrals timing to figure
981      * out when to recheck.
982      */
scheduleDeferralCheckLocked(boolean force)983     public void scheduleDeferralCheckLocked(boolean force) {
984         if ((force || !mRecheckScheduled) && !mDeferredBroadcasts.isEmpty()) {
985             final Deferrals d = mDeferredBroadcasts.get(0);
986             if (!d.broadcasts.isEmpty()) {
987                 mHandler.removeCallbacks(mScheduleRunnable);
988                 mHandler.postAtTime(mScheduleRunnable, d.deferUntil);
989                 mRecheckScheduled = true;
990                 if (DEBUG_BROADCAST_DEFERRAL) {
991                     Slog.i(TAG, "Scheduling deferred broadcast recheck at " + d.deferUntil);
992                 }
993             }
994         }
995     }
996 
997     /**
998      * Cancel all current deferrals; that is, make all currently-deferred broadcasts
999      * immediately deliverable.  Used by the wait-for-broadcast-idle mechanism.
1000      */
cancelDeferralsLocked()1001     public void cancelDeferralsLocked() {
1002         zeroDeferralTimes(mAlarmBroadcasts);
1003         zeroDeferralTimes(mDeferredBroadcasts);
1004     }
1005 
zeroDeferralTimes(ArrayList<Deferrals> list)1006     private static void zeroDeferralTimes(ArrayList<Deferrals> list) {
1007         final int num = list.size();
1008         for (int i = 0; i < num; i++) {
1009             Deferrals d = list.get(i);
1010             // Safe to do this in-place because it won't break ordering
1011             d.deferUntil = d.deferredBy = 0;
1012         }
1013     }
1014 
1015     // ----------------------------------
1016 
1017     /**
1018      * If broadcasts to this uid are being deferred, find the deferrals record about it.
1019      * @return null if this uid's broadcasts are not being deferred
1020      */
findUidLocked(final int uid)1021     private Deferrals findUidLocked(final int uid) {
1022         // The common case is that they it isn't also an alarm target...
1023         Deferrals d = findUidLocked(uid, mDeferredBroadcasts);
1024         // ...but if not there, also check alarm-prioritized deferrals
1025         if (d == null) {
1026             d = findUidLocked(uid, mAlarmBroadcasts);
1027         }
1028         return d;
1029     }
1030 
1031     /**
1032      * Remove the given deferral record from whichever queue it might be in at present
1033      * @return true if the deferral was in fact found, false if this made no changes
1034      */
removeDeferral(Deferrals d)1035     private boolean removeDeferral(Deferrals d) {
1036         boolean didRemove = mDeferredBroadcasts.remove(d);
1037         if (!didRemove) {
1038             didRemove = mAlarmBroadcasts.remove(d);
1039         }
1040         return didRemove;
1041     }
1042 
1043     /**
1044      * Find the deferrals record for the given uid in the given list
1045      */
findUidLocked(final int uid, ArrayList<Deferrals> list)1046     private static Deferrals findUidLocked(final int uid, ArrayList<Deferrals> list) {
1047         final int numElements = list.size();
1048         for (int i = 0; i < numElements; i++) {
1049             Deferrals d = list.get(i);
1050             if (uid == d.uid) {
1051                 return d;
1052             }
1053         }
1054         return null;
1055     }
1056 
1057     /**
1058      * Pop the next broadcast record from the head of the given deferrals list,
1059      * if one exists.
1060      */
popLocked(ArrayList<Deferrals> list)1061     private static BroadcastRecord popLocked(ArrayList<Deferrals> list) {
1062         final Deferrals d = list.get(0);
1063         return d.broadcasts.isEmpty() ? null : d.broadcasts.remove(0);
1064     }
1065 
1066     /**
1067      * Insert the given Deferrals into the priority queue, sorted by defer-until milestone
1068      */
insertLocked(ArrayList<Deferrals> list, Deferrals d)1069     private static void insertLocked(ArrayList<Deferrals> list, Deferrals d) {
1070         // Simple linear search is appropriate here because we expect to
1071         // have very few entries in the deferral lists (i.e. very few badly-
1072         // behaving apps currently facing deferral)
1073         int i;
1074         final int numElements = list.size();
1075         for (i = 0; i < numElements; i++) {
1076             if (d.deferUntil < list.get(i).deferUntil) {
1077                 break;
1078             }
1079         }
1080         list.add(i, d);
1081     }
1082 
1083     /**
1084      * Calculate a new deferral time based on the previous time.  This should decay
1085      * toward zero, though a small nonzero floor is an option.
1086      */
calculateDeferral(long previous)1087     private long calculateDeferral(long previous) {
1088         return Math.max(mConstants.DEFERRAL_FLOOR,
1089                 (long) (previous * mConstants.DEFERRAL_DECAY_FACTOR));
1090     }
1091 
1092     // ----------------------------------
1093 
dumpLocked(PrintWriter pw, String dumpPackage, String queueName, SimpleDateFormat sdf)1094     boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName,
1095             SimpleDateFormat sdf) {
1096         final Dumper dumper = new Dumper(pw, queueName, dumpPackage, sdf);
1097         boolean printed = false;
1098 
1099         dumper.setHeading("Currently in flight");
1100         dumper.setLabel("In-Flight Ordered Broadcast");
1101         if (mCurrentBroadcast != null) {
1102             dumper.dump(mCurrentBroadcast);
1103         } else {
1104             pw.println("  (null)");
1105         }
1106 
1107         dumper.setHeading("Active ordered broadcasts");
1108         dumper.setLabel("Active Ordered Broadcast");
1109         for (Deferrals d : mAlarmBroadcasts) {
1110             d.dumpLocked(dumper);
1111         }
1112         printed |= dumper.didPrint();
1113 
1114         for (BroadcastRecord br : mOrderedBroadcasts) {
1115             dumper.dump(br);
1116         }
1117         printed |= dumper.didPrint();
1118 
1119         dumper.setHeading("Deferred ordered broadcasts");
1120         dumper.setLabel("Deferred Ordered Broadcast");
1121         for (Deferrals d : mDeferredBroadcasts) {
1122             d.dumpLocked(dumper);
1123         }
1124         printed |= dumper.didPrint();
1125 
1126         dumper.setHeading("Deferred LOCKED_BOOT_COMPLETED broadcasts");
1127         dumper.setLabel("Deferred LOCKED_BOOT_COMPLETED Broadcast");
1128         for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
1129             mUser2Deferred.valueAt(i).dump(dumper, Intent.ACTION_LOCKED_BOOT_COMPLETED);
1130         }
1131         printed |= dumper.didPrint();
1132 
1133         dumper.setHeading("Deferred BOOT_COMPLETED broadcasts");
1134         dumper.setLabel("Deferred BOOT_COMPLETED Broadcast");
1135         for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
1136             mUser2Deferred.valueAt(i).dump(dumper, Intent.ACTION_BOOT_COMPLETED);
1137         }
1138         printed |= dumper.didPrint();
1139 
1140         return printed;
1141     }
1142 }
1143