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 > 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