• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 android.os;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.FlaggedApi;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.util.ArrayMap;
26 import android.util.Slog;
27 
28 import java.io.PrintWriter;
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.Queue;
32 import java.util.concurrent.ConcurrentLinkedQueue;
33 import java.util.concurrent.Executor;
34 import java.util.function.BiConsumer;
35 import java.util.function.Consumer;
36 
37 /**
38  * Takes care of the grunt work of maintaining a list of remote interfaces,
39  * typically for the use of performing callbacks from a
40  * {@link android.app.Service} to its clients.  In particular, this:
41  *
42  * <ul>
43  * <li> Keeps track of a set of registered {@link IInterface} objects,
44  * taking care to identify them through their underlying unique {@link IBinder}
45  * (by calling {@link IInterface#asBinder IInterface.asBinder()}.
46  * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to
47  * each registered interface, so that it can be cleaned out of the list if its
48  * process goes away.
49  * <li> Performs locking of the underlying list of interfaces to deal with
50  * multithreaded incoming calls, and a thread-safe way to iterate over a
51  * snapshot of the list without holding its lock.
52  * </ul>
53  *
54  * <p>To use this class, simply create a single instance along with your
55  * service, and call its {@link #register} and {@link #unregister} methods
56  * as client register and unregister with your service.  To call back on to
57  * the registered clients, use {@link #beginBroadcast},
58  * {@link #getBroadcastItem}, and {@link #finishBroadcast}.
59  *
60  * <p>If a registered interface's process goes away, this class will take
61  * care of automatically removing it from the list.  If you want to do
62  * additional work in this situation, you can create a subclass that
63  * implements the {@link #onCallbackDied} method.
64  */
65 @android.ravenwood.annotation.RavenwoodKeepWholeClass
66 public class RemoteCallbackList<E extends IInterface> {
67     private static final String TAG = "RemoteCallbackList";
68 
69     private static final int DEFAULT_MAX_QUEUE_SIZE = 1000;
70 
71 
72     /**
73      * @hide
74      */
75     @IntDef(prefix = {"FROZEN_CALLEE_POLICY_"}, value = {
76             FROZEN_CALLEE_POLICY_UNSET,
77             FROZEN_CALLEE_POLICY_ENQUEUE_ALL,
78             FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT,
79             FROZEN_CALLEE_POLICY_DROP,
80     })
81     @Retention(RetentionPolicy.SOURCE)
82     @interface FrozenCalleePolicy {
83     }
84 
85     /**
86      * Callbacks are invoked immediately regardless of the frozen state of the target process.
87      *
88      * Not recommended. Only exists for backward-compatibility. This represents the behavior up to
89      * SDK 35. Starting with SDK 36, clients should set a policy to govern callback invocations when
90      * recipients are frozen.
91      */
92     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
93     public static final int FROZEN_CALLEE_POLICY_UNSET = 0;
94 
95     /**
96      * When the callback recipient's process is frozen, callbacks are enqueued so they're invoked
97      * after the recipient is unfrozen.
98      *
99      * This is commonly used when the recipient wants to receive all callbacks without losing any
100      * history, e.g. the recipient maintains a running count of events that occurred.
101      *
102      * Queued callbacks are invoked in the order they were originally broadcasted.
103      */
104     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
105     public static final int FROZEN_CALLEE_POLICY_ENQUEUE_ALL = 1;
106 
107     /**
108      * When the callback recipient's process is frozen, only the most recent callback is enqueued,
109      * which is later invoked after the recipient is unfrozen.
110      *
111      * This can be used when only the most recent state matters, for instance when clients are
112      * listening to screen brightness changes.
113      */
114     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
115     public static final int FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT = 2;
116 
117     /**
118      * When the callback recipient's process is frozen, callbacks are suppressed as if they never
119      * happened.
120      *
121      * This could be useful in the case where the recipient wishes to react to callbacks only when
122      * they occur while the recipient is not frozen. For example, certain network events are only
123      * worth responding to if the response can be immediate. Another example is recipients having
124      * another way of getting the latest state once it's unfrozen. Therefore there is no need to
125      * save callbacks that happened while the recipient was frozen.
126      */
127     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
128     public static final int FROZEN_CALLEE_POLICY_DROP = 3;
129 
130     @UnsupportedAppUsage
131     /*package*/ ArrayMap<IBinder, Interface> mInterfaces = new ArrayMap<IBinder, Interface>();
132     private Object[] mActiveBroadcast;
133     private int mBroadcastCount = -1;
134     private boolean mKilled = false;
135     private StringBuilder mRecentCallers;
136 
137     private final @FrozenCalleePolicy int mFrozenCalleePolicy;
138     private final int mMaxQueueSize;
139     private final Executor mExecutor;
140 
141     private final class Interface implements IBinder.DeathRecipient,
142             IBinder.FrozenStateChangeCallback {
143         final IBinder mBinder;
144         final E mInterface;
145         final Object mCookie;
146         final Queue<Consumer<E>> mCallbackQueue;
147         int mCurrentState = IBinder.FrozenStateChangeCallback.STATE_UNFROZEN;
148 
Interface(E callbackInterface, Object cookie)149         Interface(E callbackInterface, Object cookie) {
150             mBinder = callbackInterface.asBinder();
151             mInterface = callbackInterface;
152             mCookie = cookie;
153             mCallbackQueue = mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_ALL
154                 || mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT
155                 ? new ConcurrentLinkedQueue<>() : null;
156         }
157 
158         @Override
onFrozenStateChanged(@onNull IBinder who, int state)159         public synchronized void onFrozenStateChanged(@NonNull IBinder who, int state) {
160             if (state == STATE_UNFROZEN && mCallbackQueue != null) {
161                 while (!mCallbackQueue.isEmpty()) {
162                     Consumer<E> callback = mCallbackQueue.poll();
163                     callback.accept(mInterface);
164                 }
165             }
166             mCurrentState = state;
167         }
168 
addCallback(@onNull Consumer<E> callback)169         void addCallback(@NonNull Consumer<E> callback) {
170             if (mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_UNSET) {
171                 callback.accept(mInterface);
172                 return;
173             }
174             synchronized (this) {
175                 if (mCurrentState == STATE_UNFROZEN) {
176                     callback.accept(mInterface);
177                     return;
178                 }
179                 switch (mFrozenCalleePolicy) {
180                     case FROZEN_CALLEE_POLICY_ENQUEUE_ALL:
181                         if (mCallbackQueue.size() >= mMaxQueueSize) {
182                             mCallbackQueue.poll();
183                         }
184                         mCallbackQueue.offer(callback);
185                         break;
186                     case FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT:
187                         mCallbackQueue.clear();
188                         mCallbackQueue.offer(callback);
189                         break;
190                     case FROZEN_CALLEE_POLICY_DROP:
191                         // Do nothing. Just ignore the callback.
192                         break;
193                     case FROZEN_CALLEE_POLICY_UNSET:
194                         // Do nothing. Should have returned at the start of the method.
195                         break;
196                 }
197             }
198         }
199 
maybeSubscribeToFrozenCallback()200         void maybeSubscribeToFrozenCallback() throws RemoteException {
201             if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
202                 try {
203                     mBinder.addFrozenStateChangeCallback(mExecutor, this);
204                 } catch (UnsupportedOperationException e) {
205                     // The kernel does not support frozen notifications. In this case we want to
206                     // silently fall back to FROZEN_CALLEE_POLICY_UNSET. This is done by simply
207                     // ignoring the error and moving on. mCurrentState would always be
208                     // STATE_UNFROZEN and all callbacks are invoked immediately.
209                 }
210             }
211         }
212 
maybeUnsubscribeFromFrozenCallback()213         void maybeUnsubscribeFromFrozenCallback() {
214             if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
215                 try {
216                     mBinder.removeFrozenStateChangeCallback(this);
217                 } catch (UnsupportedOperationException | IllegalArgumentException e) {
218                     // The kernel does not support frozen notifications. Ignore the error and move
219                     // on.
220                 }
221             }
222         }
223 
binderDied()224         public void binderDied() {
225             synchronized (mInterfaces) {
226                 mInterfaces.remove(mBinder);
227                 maybeUnsubscribeFromFrozenCallback();
228             }
229             onCallbackDied(mInterface, mCookie);
230         }
231     }
232 
233     /**
234      * Builder for {@link RemoteCallbackList}.
235      *
236      * @param <E> The remote callback interface type.
237      */
238     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
239     public static final class Builder<E extends IInterface> {
240         private @FrozenCalleePolicy int mFrozenCalleePolicy;
241         private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
242         private InterfaceDiedCallback mInterfaceDiedCallback;
243         private Executor mExecutor;
244 
245         /**
246          * Creates a Builder for {@link RemoteCallbackList}.
247          *
248          * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
249          * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
250          * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
251          * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
252          */
Builder(@rozenCalleePolicy int frozenCalleePolicy)253         public Builder(@FrozenCalleePolicy int frozenCalleePolicy) {
254             mFrozenCalleePolicy = frozenCalleePolicy;
255         }
256 
257         /**
258          * Sets the max queue size.
259          *
260          * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
261          * recipient's process is frozen. Once the limit is reached, the oldest callback is dropped
262          * to keep the size under the limit. Should only be called for
263          * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
264          *
265          * @return This builder.
266          * @throws IllegalArgumentException if the maxQueueSize is not positive.
267          * @throws UnsupportedOperationException if frozenCalleePolicy is not
268          * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
269          */
setMaxQueueSize(int maxQueueSize)270         public @NonNull Builder setMaxQueueSize(int maxQueueSize) {
271             if (maxQueueSize <= 0) {
272                 throw new IllegalArgumentException("maxQueueSize must be positive");
273             }
274             if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_ENQUEUE_ALL) {
275                 throw new UnsupportedOperationException(
276                         "setMaxQueueSize can only be called for FROZEN_CALLEE_POLICY_ENQUEUE_ALL");
277             }
278             mMaxQueueSize = maxQueueSize;
279             return this;
280         }
281 
282         /**
283          * Sets the callback to be invoked when an interface dies.
284          */
setInterfaceDiedCallback( @onNull InterfaceDiedCallback<E> callback)285         public @NonNull Builder setInterfaceDiedCallback(
286                 @NonNull InterfaceDiedCallback<E> callback) {
287             mInterfaceDiedCallback = callback;
288             return this;
289         }
290 
291         /**
292          * Sets the executor to be used when invoking callbacks asynchronously.
293          *
294          * This is only used when callbacks need to be invoked asynchronously, e.g. when the process
295          * hosting a callback becomes unfrozen. Callbacks that can be invoked immediately run on the
296          * same thread that calls {@link #broadcast} synchronously.
297          */
setExecutor(@onNull @allbackExecutor Executor executor)298         public @NonNull Builder setExecutor(@NonNull @CallbackExecutor Executor executor) {
299             mExecutor = executor;
300             return this;
301         }
302 
303         /**
304          * For notifying when the process hosting a callback interface has died.
305          *
306          * @param <E> The remote callback interface type.
307          */
308         @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
309         public interface InterfaceDiedCallback<E extends IInterface> {
310             /**
311              * Invoked when a callback interface has died.
312              *
313              * @param remoteCallbackList the list that the interface was registered with.
314              * @param deadInterface the interface that has died.
315              * @param cookie the cookie specified on interface registration.
316              */
onInterfaceDied(@onNull RemoteCallbackList<E> remoteCallbackList, E deadInterface, @Nullable Object cookie)317             void onInterfaceDied(@NonNull RemoteCallbackList<E> remoteCallbackList,
318                     E deadInterface, @Nullable Object cookie);
319         }
320 
321         /**
322          * Builds and returns a {@link RemoteCallbackList}.
323          *
324          * @return The built {@link RemoteCallbackList} object.
325          */
build()326         public @NonNull RemoteCallbackList<E> build() {
327             Executor executor = mExecutor;
328             if (executor == null && mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
329                 // TODO Throw an exception here once the existing API caller is updated to provide
330                 // an executor.
331                 executor = new HandlerExecutor(Handler.getMain());
332             }
333             if (mInterfaceDiedCallback != null) {
334                 return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor) {
335                     @Override
336                     public void onCallbackDied(E deadInterface, Object cookie) {
337                         mInterfaceDiedCallback.onInterfaceDied(this, deadInterface, cookie);
338                     }
339                 };
340             }
341             return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor);
342         }
343     }
344 
345     /**
346      * Returns the frozen callee policy.
347      *
348      * @return The frozen callee policy.
349      */
350     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
351     public @FrozenCalleePolicy int getFrozenCalleePolicy() {
352         return mFrozenCalleePolicy;
353     }
354 
355     /**
356      * Returns the max queue size.
357      *
358      * @return The max queue size.
359      */
360     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
361     public int getMaxQueueSize() {
362         return mMaxQueueSize;
363     }
364 
365     /**
366      * Returns the executor used when invoking callbacks asynchronously.
367      *
368      * @return The executor.
369      */
370     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
371     public @Nullable Executor getExecutor() {
372         return mExecutor;
373     }
374 
375     /**
376      * Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to
377      * <pre>
378      * new RemoteCallbackList.Build(RemoteCallbackList.FROZEN_CALLEE_POLICY_UNSET).build()
379      * </pre>
380      */
381     public RemoteCallbackList() {
382         this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE, null);
383     }
384 
385     /**
386      * Creates a RemoteCallbackList with the specified frozen callee policy.
387      *
388      * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
389      * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
390      * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
391      * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
392      *
393      * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
394      * recipient's process is frozen. Once the limit is reached, the oldest callbacks would be
395      * dropped to keep the size under limit. Ignored except for
396      * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
397      *
398      * @param executor The executor used when invoking callbacks asynchronously.
399      */
400     private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize,
401             @CallbackExecutor Executor executor) {
402         mFrozenCalleePolicy = frozenCalleePolicy;
403         mMaxQueueSize = maxQueueSize;
404         mExecutor = executor;
405     }
406 
407     /**
408      * Simple version of {@link RemoteCallbackList#register(E, Object)}
409      * that does not take a cookie object.
410      */
411     public boolean register(E callbackInterface) {
412         return register(callbackInterface, null);
413     }
414 
415     /**
416      * Add a new interface to the list.  This interface will remain in the list
417      * until a corresponding call to {@link #unregister} or its hosting process
418      * goes away.  If the interface was already registered (determined by
419      * checking to see if the {@link IInterface#asBinder callbackInterface.asBinder()}
420      * object is already in the list), then it will be replaced with the new interface.
421      * Registrations are not counted; a single call to {@link #unregister}
422      * will remove an interface after any number calls to register it.
423      *
424      * @param callbackInterface The callback interface to be added to the list.  Must
425      * not be null -- passing null here will cause a NullPointerException.
426      * Most services will want to check for null before calling this with
427      * an object given from a client, so that clients can't crash the
428      * service with bad data.
429      *
430      * @param cookie Optional additional data to be associated with this
431      * interface.
432      *
433      * @return Returns true if the interface was successfully added to the list.
434      * Returns false if it was not added, either because {@link #kill} had
435      * previously been called or the interface's process has gone away.
436      *
437      * @see #unregister
438      * @see #kill
439      * @see #onCallbackDied
440      */
441     public boolean register(E callbackInterface, Object cookie) {
442         synchronized (mInterfaces) {
443             if (mKilled) {
444                 return false;
445             }
446             // Flag unusual case that could be caused by a leak. b/36778087
447             logExcessiveInterfaces();
448             IBinder binder = callbackInterface.asBinder();
449             try {
450                 Interface i = new Interface(callbackInterface, cookie);
451                 unregister(callbackInterface);
452                 binder.linkToDeath(i, 0);
453                 i.maybeSubscribeToFrozenCallback();
454                 mInterfaces.put(binder, i);
455                 return true;
456             } catch (RemoteException e) {
457                 return false;
458             }
459         }
460     }
461 
462     /**
463      * Remove from the list an interface that was previously added with
464      * {@link #register}.  This uses the
465      * {@link IInterface#asBinder callbackInterface.asBinder()} object to correctly
466      * find the previous registration.
467      * Registrations are not counted; a single unregister call will remove
468      * an interface after any number calls to {@link #register} for it.
469      *
470      * @param callbackInterface The interface to be removed from the list.  Passing
471      * null here will cause a NullPointerException, so you will generally want
472      * to check for null before calling.
473      *
474      * @return Returns true if the interface was found and unregistered.  Returns
475      * false if the given interface was not found on the list.
476      *
477      * @see #register
478      */
479     public boolean unregister(E callbackInterface) {
480         synchronized (mInterfaces) {
481             Interface i = mInterfaces.remove(callbackInterface.asBinder());
482             if (i != null) {
483                 i.mInterface.asBinder().unlinkToDeath(i, 0);
484                 i.maybeUnsubscribeFromFrozenCallback();
485                 return true;
486             }
487             return false;
488         }
489     }
490 
491     /**
492      * Disable this interface list.  All registered interfaces are unregistered,
493      * and the list is disabled so that future calls to {@link #register} will
494      * fail.  This should be used when a Service is stopping, to prevent clients
495      * from registering interfaces after it is stopped.
496      *
497      * @see #register
498      */
499     public void kill() {
500         synchronized (mInterfaces) {
501             for (int cbi = mInterfaces.size() - 1; cbi >= 0; cbi--) {
502                 Interface i = mInterfaces.valueAt(cbi);
503                 i.mInterface.asBinder().unlinkToDeath(i, 0);
504                 i.maybeUnsubscribeFromFrozenCallback();
505             }
506             mInterfaces.clear();
507             mKilled = true;
508         }
509     }
510 
511     /**
512      * Old version of {@link #onCallbackDied(E, Object)} that
513      * does not provide a cookie.
514      */
515     public void onCallbackDied(E callbackInterface) {
516     }
517 
518     /**
519      * Called when the process hosting an interface in the list has gone away.
520      * The default implementation calls {@link #onCallbackDied(E)}
521      * for backwards compatibility.
522      *
523      * @param callbackInterface The interface whose process has died.  Note that, since
524      * its process has died, you can not make any calls on to this interface.
525      * You can, however, retrieve its IBinder and compare it with another
526      * IBinder to see if it is the same object.
527      * @param cookie The cookie object original provided to
528      * {@link #register(E, Object)}.
529      *
530      * @see #register
531      */
532     public void onCallbackDied(E callbackInterface, Object cookie) {
533         onCallbackDied(callbackInterface);
534     }
535 
536     /**
537      * Use {@link #broadcast(Consumer)} instead to ensure proper handling of frozen processes.
538      *
539      * Prepare to start making calls to the currently registered interfaces.
540      * This creates a copy of the interface list, which you can retrieve items
541      * from using {@link #getBroadcastItem}.  Note that only one broadcast can
542      * be active at a time, so you must be sure to always call this from the
543      * same thread (usually by scheduling with {@link Handler}) or
544      * do your own synchronization.  You must call {@link #finishBroadcast}
545      * when done.
546      *
547      * <p>A typical loop delivering a broadcast looks like this:
548      *
549      * <pre>
550      * int i = interfaces.beginBroadcast();
551      * while (i &gt; 0) {
552      *     i--;
553      *     try {
554      *         interfaces.getBroadcastItem(i).somethingHappened();
555      *     } catch (RemoteException e) {
556      *         // The RemoteCallbackList will take care of removing
557      *         // the dead object for us.
558      *     }
559      * }
560      * interfaces.finishBroadcast();</pre>
561      *
562      * Note that this method is only supported for {@link #FROZEN_CALLEE_POLICY_UNSET}. For other
563      * policies use {@link #broadcast(Consumer)} instead.
564      *
565      * @return Returns the number of interfaces in the broadcast, to be used
566      * with {@link #getBroadcastItem} to determine the range of indices you
567      * can supply.
568      *
569      * @throws UnsupportedOperationException if an frozen callee policy is set.
570      *
571      * @see #getBroadcastItem
572      * @see #finishBroadcast
573      */
574     public int beginBroadcast() {
575         if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
576             throw new UnsupportedOperationException();
577         }
578         return beginBroadcastInternal();
579     }
580 
581     private int beginBroadcastInternal() {
582         synchronized (mInterfaces) {
583             if (mBroadcastCount > 0) {
584                 throw new IllegalStateException(
585                         "beginBroadcast() called while already in a broadcast");
586             }
587 
588             final int n = mBroadcastCount = mInterfaces.size();
589             if (n <= 0) {
590                 return 0;
591             }
592             Object[] active = mActiveBroadcast;
593             if (active == null || active.length < n) {
594                 mActiveBroadcast = active = new Object[n];
595             }
596             for (int i = 0; i < n; i++) {
597                 active[i] = mInterfaces.valueAt(i);
598             }
599             return n;
600         }
601     }
602 
603     /**
604      * Retrieve an item in the active broadcast that was previously started
605      * with {@link #beginBroadcast}.  This can <em>only</em> be called after
606      * the broadcast is started, and its data is no longer valid after
607      * calling {@link #finishBroadcast}.
608      *
609      * <p>Note that it is possible for the process of one of the returned
610      * interfaces to go away before you call it, so you will need to catch
611      * {@link RemoteException} when calling on to the returned object.
612      * The interface list itself, however, will take care of unregistering
613      * these objects once it detects that it is no longer valid, so you can
614      * handle such an exception by simply ignoring it.
615      *
616      * @param index Which of the registered interfaces you would like to
617      * retrieve.  Ranges from 0 to {@link #beginBroadcast}-1, inclusive.
618      *
619      * @return Returns the interface that you can call.  This will always be non-null.
620      *
621      * @see #beginBroadcast
622      */
623     public E getBroadcastItem(int index) {
624         return ((Interface) mActiveBroadcast[index]).mInterface;
625     }
626 
627     /**
628      * Retrieve the cookie associated with the item
629      * returned by {@link #getBroadcastItem(int)}.
630      *
631      * @see #getBroadcastItem
632      */
633     public Object getBroadcastCookie(int index) {
634         return ((Interface) mActiveBroadcast[index]).mCookie;
635     }
636 
637     /**
638      * Clean up the state of a broadcast previously initiated by calling
639      * {@link #beginBroadcast}.  This must always be called when you are done
640      * with a broadcast.
641      *
642      * @see #beginBroadcast
643      */
644     public void finishBroadcast() {
645         synchronized (mInterfaces) {
646             if (mBroadcastCount < 0) {
647                 throw new IllegalStateException(
648                         "finishBroadcast() called outside of a broadcast");
649             }
650 
651             Object[] active = mActiveBroadcast;
652             if (active != null) {
653                 final int N = mBroadcastCount;
654                 for (int i=0; i<N; i++) {
655                     active[i] = null;
656                 }
657             }
658 
659             mBroadcastCount = -1;
660         }
661     }
662 
663     /**
664      * Performs {@code callback} on each registered interface.
665      *
666      * This is equivalent to #beginBroadcast, followed by iterating over the items using
667      * #getBroadcastItem and then @finishBroadcast, except that this method supports
668      * frozen callee policies.
669      */
670     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
671     public void broadcast(@NonNull Consumer<E> callback) {
672         int itemCount = beginBroadcastInternal();
673         try {
674             for (int i = 0; i < itemCount; i++) {
675                 ((Interface) mActiveBroadcast[i]).addCallback(callback);
676             }
677         } finally {
678             finishBroadcast();
679         }
680     }
681 
682     /**
683      * Performs {@code callback} for each cookie associated with an interface, calling
684      * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
685      *
686      * @hide
687      */
688     public <C> void broadcastForEachCookie(Consumer<C> callback) {
689         int itemCount = beginBroadcast();
690         try {
691             for (int i = 0; i < itemCount; i++) {
692                 callback.accept((C) getBroadcastCookie(i));
693             }
694         } finally {
695             finishBroadcast();
696         }
697     }
698 
699     /**
700      * Performs {@code callback} on each interface and associated cookie, calling {@link
701      * #beginBroadcast()}/{@link #finishBroadcast()} before/after looping.
702      *
703      * @hide
704      */
705     public <C> void broadcast(BiConsumer<E, C> callback) {
706         int itemCount = beginBroadcast();
707         try {
708             for (int i = 0; i < itemCount; i++) {
709                 callback.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
710             }
711         } finally {
712             finishBroadcast();
713         }
714     }
715 
716     /**
717      * Returns the number of registered interfaces. Note that the number of registered
718      * interfaces may differ from the value returned by {@link #beginBroadcast()} since
719      * the former returns the number of interfaces registered at the time of the call
720      * and the second the number of interfaces to which the broadcast will be delivered.
721      * <p>
722      * This function is useful to decide whether to schedule a broadcast if this
723      * requires doing some work which otherwise would not be performed.
724      * </p>
725      *
726      * @return The size.
727      */
728     public int getRegisteredCallbackCount() {
729         synchronized (mInterfaces) {
730             if (mKilled) {
731                 return 0;
732             }
733             return mInterfaces.size();
734         }
735     }
736 
737     /**
738      * Return a currently registered interface.  Note that this is
739      * <em>not</em> the same as {@link #getBroadcastItem} and should not be used
740      * interchangeably with it.  This method returns the registered interface at the given
741      * index, not the current broadcast state.  This means that it is not itself thread-safe:
742      * any call to {@link #register} or {@link #unregister} will change these indices, so you
743      * must do your own thread safety between these to protect from such changes.
744      *
745      * @param index Index of which interface registration to return, from 0 to
746      * {@link #getRegisteredCallbackCount()} - 1.
747      *
748      * @return Returns whatever interface is associated with this index, or null if
749      * {@link #kill()} has been called.
750      */
751     public E getRegisteredCallbackItem(int index) {
752         synchronized (mInterfaces) {
753             if (mKilled) {
754                 return null;
755             }
756             return mInterfaces.valueAt(index).mInterface;
757         }
758     }
759 
760     /**
761      * Return any cookie associated with a currently registered interface.  Note that this is
762      * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
763      * interchangeably with it.  This method returns the current cookie registered at the given
764      * index, not the current broadcast state.  This means that it is not itself thread-safe:
765      * any call to {@link #register} or {@link #unregister} will change these indices, so you
766      * must do your own thread safety between these to protect from such changes.
767      *
768      * @param index Index of which registration cookie to return, from 0 to
769      * {@link #getRegisteredCallbackCount()} - 1.
770      *
771      * @return Returns whatever cookie object is associated with this index, or null if
772      * {@link #kill()} has been called.
773      */
774     public Object getRegisteredCallbackCookie(int index) {
775         synchronized (mInterfaces) {
776             if (mKilled) {
777                 return null;
778             }
779             return mInterfaces.valueAt(index).mCookie;
780         }
781     }
782 
783     /** @hide */
784     public void dump(PrintWriter pw, String prefix) {
785         synchronized (mInterfaces) {
786             pw.print(prefix); pw.print("callbacks: "); pw.println(mInterfaces.size());
787             pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
788             pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
789         }
790     }
791 
792     private void logExcessiveInterfaces() {
793         final long size = mInterfaces.size();
794         final long TOO_MANY = 3000;
795         final long MAX_CHARS = 1000;
796         if (size >= TOO_MANY) {
797             if (size == TOO_MANY && mRecentCallers == null) {
798                 mRecentCallers = new StringBuilder();
799             }
800             if (mRecentCallers != null && mRecentCallers.length() < MAX_CHARS) {
801                 mRecentCallers.append(Debug.getCallers(5));
802                 mRecentCallers.append('\n');
803                 if (mRecentCallers.length() >= MAX_CHARS) {
804                     Slog.wtf(TAG, "More than "
805                             + TOO_MANY + " remote callbacks registered. Recent callers:\n"
806                             + mRecentCallers.toString());
807                     mRecentCallers = null;
808                 }
809             }
810         }
811     }
812 }
813