19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.os; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19390517be2d60dd6e6264150c190c372d89bb331aDianne Hackbornimport android.util.ArrayMap; 2018a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasaniimport android.util.Slog; 21390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn 22ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Suslaimport java.util.function.Consumer; 23ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Takes care of the grunt work of maintaining a list of remote interfaces, 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * typically for the use of performing callbacks from a 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.app.Service} to its clients. In particular, this: 287b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <ul> 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> Keeps track of a set of registered {@link IInterface} callbacks, 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * taking care to identify them through their underlying unique {@link IBinder} 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (by calling {@link IInterface#asBinder IInterface.asBinder()}. 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * each registered interface, so that it can be cleaned out of the list if its 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * process goes away. 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> Performs locking of the underlying list of interfaces to deal with 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multithreaded incoming calls, and a thread-safe way to iterate over a 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * snapshot of the list without holding its lock. 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </ul> 407b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>To use this class, simply create a single instance along with your 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * service, and call its {@link #register} and {@link #unregister} methods 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * as client register and unregister with your service. To call back on to 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the registered clients, use {@link #beginBroadcast}, 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #getBroadcastItem}, and {@link #finishBroadcast}. 467b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>If a registered callback's process goes away, this class will take 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * care of automatically removing it from the list. If you want to do 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * additional work in this situation, you can create a subclass that 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * implements the {@link #onCallbackDied} method. 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class RemoteCallbackList<E extends IInterface> { 5318a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani private static final String TAG = "RemoteCallbackList"; 5418a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani 55390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn /*package*/ ArrayMap<IBinder, Callback> mCallbacks 56390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn = new ArrayMap<IBinder, Callback>(); 57231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn private Object[] mActiveBroadcast; 58b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn private int mBroadcastCount = -1; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mKilled = false; 6018a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani private StringBuilder mRecentCallers; 617b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final class Callback implements IBinder.DeathRecipient { 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final E mCallback; 64231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn final Object mCookie; 6518a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani 66231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn Callback(E callback, Object cookie) { 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallback = callback; 68231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn mCookie = cookie; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 707b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void binderDied() { 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallbacks.remove(mCallback.asBinder()); 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 75231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn onCallbackDied(mCallback, mCookie); 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 787b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 80231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Simple version of {@link RemoteCallbackList#register(E, Object)} 81231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * that does not take a cookie object. 82231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */ 83231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public boolean register(E callback) { 84231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn return register(callback, null); 85231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn } 865614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn 87231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn /** 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a new callback to the list. This callback will remain in the list 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * until a corresponding call to {@link #unregister} or its hosting process 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * goes away. If the callback was already registered (determined by 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * checking to see if the {@link IInterface#asBinder callback.asBinder()} 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * object is already in the list), then it will be left as-is. 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Registrations are not counted; a single call to {@link #unregister} 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will remove a callback after any number calls to register it. 957b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param callback The callback interface to be added to the list. Must 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * not be null -- passing null here will cause a NullPointerException. 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Most services will want to check for null before calling this with 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * an object given from a client, so that clients can't crash the 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * service with bad data. 1017b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 102231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * @param cookie Optional additional data to be associated with this 103231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * callback. 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns true if the callback was successfully added to the list. 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns false if it was not added, either because {@link #kill} had 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * previously been called or the callback's process has gone away. 1087b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unregister 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #kill 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #onCallbackDied 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 113231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public boolean register(E callback, Object cookie) { 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKilled) { 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11818a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani // Flag unusual case that could be caused by a leak. b/36778087 11918a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani logExcessiveCallbacks(); 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IBinder binder = callback.asBinder(); 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 122231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn Callback cb = new Callback(callback, cookie); 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project binder.linkToDeath(cb, 0); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallbacks.put(binder, cb); 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1317b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Remove from the list a callback that was previously added with 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #register}. This uses the 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link IInterface#asBinder callback.asBinder()} object to correctly 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * find the previous registration. 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Registrations are not counted; a single unregister call will remove 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a callback after any number calls to {@link #register} for it. 1397b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param callback The callback to be removed from the list. Passing 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * null here will cause a NullPointerException, so you will generally want 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to check for null before calling. 1437b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns true if the callback was found and unregistered. Returns 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * false if the given callback was not found on the list. 1467b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #register 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean unregister(E callback) { 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Callback cb = mCallbacks.remove(callback.asBinder()); 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cb != null) { 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cb.mCallback.asBinder().unlinkToDeath(cb, 0); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1597b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Disable this callback list. All registered callbacks are unregistered, 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and the list is disabled so that future calls to {@link #register} will 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * fail. This should be used when a Service is stopping, to prevent clients 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * from registering callbacks after it is stopped. 1657b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #register 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void kill() { 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 170390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) { 171390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn Callback cb = mCallbacks.valueAt(cbi); 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cb.mCallback.asBinder().unlinkToDeath(cb, 0); 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallbacks.clear(); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKilled = true; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1787b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 180231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Old version of {@link #onCallbackDied(E, Object)} that 181231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * does not provide a cookie. 182231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */ 183231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public void onCallbackDied(E callback) { 184231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn } 185231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn 186231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn /** 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the process hosting a callback in the list has gone away. 188231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * The default implementation calls {@link #onCallbackDied(E)} 189231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * for backwards compatibility. 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param callback The callback whose process has died. Note that, since 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * its process has died, you can not make any calls on to this interface. 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You can, however, retrieve its IBinder and compare it with another 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * IBinder to see if it is the same object. 195231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * @param cookie The cookie object original provided to 196231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * {@link #register(E, Object)}. 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #register 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 200231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public void onCallbackDied(E callback, Object cookie) { 201231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn onCallbackDied(callback); 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2037b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Prepare to start making calls to the currently registered callbacks. 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This creates a copy of the callback list, which you can retrieve items 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * from using {@link #getBroadcastItem}. Note that only one broadcast can 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be active at a time, so you must be sure to always call this from the 209b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn * same thread (usually by scheduling with {@link Handler}) or 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * do your own synchronization. You must call {@link #finishBroadcast} 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when done. 2127b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>A typical loop delivering a broadcast looks like this: 2147b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 216b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn * int i = callbacks.beginBroadcast(); 217dace230043314d6fab1c5ced4b031eaccd814c25Dianne Hackborn * while (i > 0) { 218b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn * i--; 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * try { 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * callbacks.getBroadcastItem(i).somethingHappened(); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } catch (RemoteException e) { 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // The RemoteCallbackList will take care of removing 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // the dead object for us. 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * callbacks.finishBroadcast();</pre> 2277b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns the number of callbacks in the broadcast, to be used 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with {@link #getBroadcastItem} to determine the range of indices you 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can supply. 2317b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getBroadcastItem 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #finishBroadcast 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int beginBroadcast() { 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 237b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn if (mBroadcastCount > 0) { 238b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn throw new IllegalStateException( 239b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn "beginBroadcast() called while already in a broadcast"); 240b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn } 241b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn 242b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn final int N = mBroadcastCount = mCallbacks.size(); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (N <= 0) { 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 246231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn Object[] active = mActiveBroadcast; 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (active == null || active.length < N) { 248231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn mActiveBroadcast = active = new Object[N]; 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 250390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn for (int i=0; i<N; i++) { 251390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn active[i] = mCallbacks.valueAt(i); 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 253390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn return N; 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2567b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Retrieve an item in the active broadcast that was previously started 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with {@link #beginBroadcast}. This can <em>only</em> be called after 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the broadcast is started, and its data is no longer valid after 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * calling {@link #finishBroadcast}. 2627b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Note that it is possible for the process of one of the returned 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * callbacks to go away before you call it, so you will need to catch 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link RemoteException} when calling on to the returned object. 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The callback list itself, however, will take care of unregistering 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * these objects once it detects that it is no longer valid, so you can 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * handle such an exception by simply ignoring it. 2697b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param index Which of the registered callbacks you would like to 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * retrieve. Ranges from 0 to 1-{@link #beginBroadcast}. 2727b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns the callback interface that you can call. This will 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * always be non-null. 2757b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #beginBroadcast 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public E getBroadcastItem(int index) { 279231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn return ((Callback)mActiveBroadcast[index]).mCallback; 280231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn } 281231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn 282231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn /** 283231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Retrieve the cookie associated with the item 284231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * returned by {@link #getBroadcastItem(int)}. 285231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * 286231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * @see #getBroadcastItem 287231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */ 288231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public Object getBroadcastCookie(int index) { 289231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn return ((Callback)mActiveBroadcast[index]).mCookie; 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2917b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clean up the state of a broadcast previously initiated by calling 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #beginBroadcast}. This must always be called when you are done 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with a broadcast. 2967b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #beginBroadcast 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void finishBroadcast() { 3007bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki synchronized (mCallbacks) { 3017bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki if (mBroadcastCount < 0) { 3027bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki throw new IllegalStateException( 3037bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki "finishBroadcast() called outside of a broadcast"); 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3057bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki 3067bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki Object[] active = mActiveBroadcast; 3077bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki if (active != null) { 3087bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki final int N = mBroadcastCount; 3097bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki for (int i=0; i<N; i++) { 3107bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki active[i] = null; 3117bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki } 3127bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki } 3137bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki 3147bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki mBroadcastCount = -1; 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3171cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov 3181cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov /** 319ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * Performs {@code action} on each callback, calling 320ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping 321ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * 322ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * @hide 323ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla */ 324ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla public void broadcast(Consumer<E> action) { 325ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla int itemCount = beginBroadcast(); 326ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla try { 327ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla for (int i = 0; i < itemCount; i++) { 328ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla action.accept(getBroadcastItem(i)); 329ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } 330ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } finally { 331ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla finishBroadcast(); 332ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } 333ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } 334ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla 335ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla /** 3361cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * Returns the number of registered callbacks. Note that the number of registered 3371cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * callbacks may differ from the value returned by {@link #beginBroadcast()} since 3381cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * the former returns the number of callbacks registered at the time of the call 3391cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * and the second the number of callback to which the broadcast will be delivered. 3401cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * <p> 3411cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * This function is useful to decide whether to schedule a broadcast if this 3421cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * requires doing some work which otherwise would not be performed. 3431cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * </p> 3441cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * 3451cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * @return The size. 3461cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov */ 3471cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov public int getRegisteredCallbackCount() { 3481cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov synchronized (mCallbacks) { 3491cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov if (mKilled) { 3501cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov return 0; 3511cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov } 3521cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov return mCallbacks.size(); 3531cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov } 3541cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov } 3555614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn 3565614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn /** 35759359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * Return a currently registered callback. Note that this is 35859359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * <em>not</em> the same as {@link #getBroadcastItem} and should not be used 35959359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * interchangeably with it. This method returns the registered callback at the given 36059359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * index, not the current broadcast state. This means that it is not itself thread-safe: 36159359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * any call to {@link #register} or {@link #unregister} will change these indices, so you 36259359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * must do your own thread safety between these to protect from such changes. 36359359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * 36459359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * @param index Index of which callback registration to return, from 0 to 36559359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * {@link #getRegisteredCallbackCount()} - 1. 36659359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * 36759359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * @return Returns whatever callback is associated with this index, or null if 36859359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * {@link #kill()} has been called. 36959359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn */ 37059359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn public E getRegisteredCallbackItem(int index) { 37159359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn synchronized (mCallbacks) { 37259359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn if (mKilled) { 37359359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn return null; 37459359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn } 37559359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn return mCallbacks.valueAt(index).mCallback; 37659359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn } 37759359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn } 37859359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn 37959359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn /** 38059359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * Return any cookie associated with a currently registered callback. Note that this is 3815614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used 38259359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * interchangeably with it. This method returns the current cookie registered at the given 3835614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * index, not the current broadcast state. This means that it is not itself thread-safe: 3845614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * any call to {@link #register} or {@link #unregister} will change these indices, so you 3855614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * must do your own thread safety between these to protect from such changes. 3865614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * 38759359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * @param index Index of which registration cookie to return, from 0 to 38859359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * {@link #getRegisteredCallbackCount()} - 1. 3895614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * 3905614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * @return Returns whatever cookie object is associated with this index, or null if 3915614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * {@link #kill()} has been called. 3925614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn */ 3935614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn public Object getRegisteredCallbackCookie(int index) { 3945614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn synchronized (mCallbacks) { 3955614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn if (mKilled) { 3965614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn return null; 3975614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn } 3985614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn return mCallbacks.valueAt(index).mCookie; 3995614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn } 4005614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn } 40118a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani 40218a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani private void logExcessiveCallbacks() { 40318a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani final long size = mCallbacks.size(); 40418a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani final long TOO_MANY = 3000; 40518a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani final long MAX_CHARS = 1000; 40618a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani if (size >= TOO_MANY) { 40718a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani if (size == TOO_MANY && mRecentCallers == null) { 40818a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani mRecentCallers = new StringBuilder(); 40918a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani } 41018a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani if (mRecentCallers != null && mRecentCallers.length() < MAX_CHARS) { 41118a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani mRecentCallers.append(Debug.getCallers(5)); 41218a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani mRecentCallers.append('\n'); 41318a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani if (mRecentCallers.length() >= MAX_CHARS) { 41418a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani Slog.wtf(TAG, "More than " 41518a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani + TOO_MANY + " remote callbacks registered. Recent callers:\n" 41618a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani + mRecentCallers.toString()); 41718a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani mRecentCallers = null; 41818a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani } 41918a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani } 42018a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani } 42118a23f2fd8c18d812401563e1d9a847e4c2a2d93Amith Yamasani } 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 423