blob: 6165146ece0a2e311a425dc7edd5b0ba68790546 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.os;
18
Andrei Onea24ec3212019-03-15 17:35:05 +000019import android.annotation.UnsupportedAppUsage;
Dianne Hackborn390517b2013-05-30 15:03:32 -070020import android.util.ArrayMap;
Amith Yamasani18a23f22017-04-06 10:29:33 -070021import android.util.Slog;
Dianne Hackborn390517b2013-05-30 15:03:32 -070022
Koji Fukuiccec6a62017-10-18 17:48:40 +090023import java.io.PrintWriter;
Eugene Suslaef4351c2017-01-18 11:07:06 -080024import java.util.function.Consumer;
25
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026/**
27 * Takes care of the grunt work of maintaining a list of remote interfaces,
28 * typically for the use of performing callbacks from a
29 * {@link android.app.Service} to its clients. In particular, this:
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -070030 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031 * <ul>
32 * <li> Keeps track of a set of registered {@link IInterface} callbacks,
33 * taking care to identify them through their underlying unique {@link IBinder}
34 * (by calling {@link IInterface#asBinder IInterface.asBinder()}.
35 * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to
36 * each registered interface, so that it can be cleaned out of the list if its
37 * process goes away.
38 * <li> Performs locking of the underlying list of interfaces to deal with
39 * multithreaded incoming calls, and a thread-safe way to iterate over a
40 * snapshot of the list without holding its lock.
41 * </ul>
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -070042 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 * <p>To use this class, simply create a single instance along with your
44 * service, and call its {@link #register} and {@link #unregister} methods
45 * as client register and unregister with your service. To call back on to
46 * the registered clients, use {@link #beginBroadcast},
47 * {@link #getBroadcastItem}, and {@link #finishBroadcast}.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -070048 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 * <p>If a registered callback's process goes away, this class will take
50 * care of automatically removing it from the list. If you want to do
51 * additional work in this situation, you can create a subclass that
52 * implements the {@link #onCallbackDied} method.
53 */
54public class RemoteCallbackList<E extends IInterface> {
Amith Yamasani18a23f22017-04-06 10:29:33 -070055 private static final String TAG = "RemoteCallbackList";
56
Andrei Onea24ec3212019-03-15 17:35:05 +000057 @UnsupportedAppUsage
Dianne Hackborn390517b2013-05-30 15:03:32 -070058 /*package*/ ArrayMap<IBinder, Callback> mCallbacks
59 = new ArrayMap<IBinder, Callback>();
Dianne Hackborn231cc602009-04-27 17:10:36 -070060 private Object[] mActiveBroadcast;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070061 private int mBroadcastCount = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 private boolean mKilled = false;
Amith Yamasani18a23f22017-04-06 10:29:33 -070063 private StringBuilder mRecentCallers;
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -070064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 private final class Callback implements IBinder.DeathRecipient {
66 final E mCallback;
Dianne Hackborn231cc602009-04-27 17:10:36 -070067 final Object mCookie;
Amith Yamasani18a23f22017-04-06 10:29:33 -070068
Dianne Hackborn231cc602009-04-27 17:10:36 -070069 Callback(E callback, Object cookie) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 mCallback = callback;
Dianne Hackborn231cc602009-04-27 17:10:36 -070071 mCookie = cookie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -070073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 public void binderDied() {
75 synchronized (mCallbacks) {
76 mCallbacks.remove(mCallback.asBinder());
77 }
Dianne Hackborn231cc602009-04-27 17:10:36 -070078 onCallbackDied(mCallback, mCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 }
80 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -070081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 /**
Dianne Hackborn231cc602009-04-27 17:10:36 -070083 * Simple version of {@link RemoteCallbackList#register(E, Object)}
84 * that does not take a cookie object.
85 */
86 public boolean register(E callback) {
87 return register(callback, null);
88 }
Dianne Hackborn5614bf52016-11-07 17:26:41 -080089
Dianne Hackborn231cc602009-04-27 17:10:36 -070090 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 * Add a new callback to the list. This callback will remain in the list
92 * until a corresponding call to {@link #unregister} or its hosting process
93 * goes away. If the callback was already registered (determined by
94 * checking to see if the {@link IInterface#asBinder callback.asBinder()}
95 * object is already in the list), then it will be left as-is.
96 * Registrations are not counted; a single call to {@link #unregister}
97 * will remove a callback after any number calls to register it.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -070098 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 * @param callback The callback interface to be added to the list. Must
100 * not be null -- passing null here will cause a NullPointerException.
101 * Most services will want to check for null before calling this with
102 * an object given from a client, so that clients can't crash the
103 * service with bad data.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700104 *
Dianne Hackborn231cc602009-04-27 17:10:36 -0700105 * @param cookie Optional additional data to be associated with this
106 * callback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 *
108 * @return Returns true if the callback was successfully added to the list.
109 * Returns false if it was not added, either because {@link #kill} had
110 * previously been called or the callback's process has gone away.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700111 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 * @see #unregister
113 * @see #kill
114 * @see #onCallbackDied
115 */
Dianne Hackborn231cc602009-04-27 17:10:36 -0700116 public boolean register(E callback, Object cookie) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 synchronized (mCallbacks) {
118 if (mKilled) {
119 return false;
120 }
Amith Yamasani18a23f22017-04-06 10:29:33 -0700121 // Flag unusual case that could be caused by a leak. b/36778087
122 logExcessiveCallbacks();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 IBinder binder = callback.asBinder();
124 try {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700125 Callback cb = new Callback(callback, cookie);
Kyeongkab.Namd40b5ce2019-04-22 18:14:45 +0900126 unregister(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 binder.linkToDeath(cb, 0);
128 mCallbacks.put(binder, cb);
129 return true;
130 } catch (RemoteException e) {
131 return false;
132 }
133 }
134 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 /**
137 * Remove from the list a callback that was previously added with
138 * {@link #register}. This uses the
139 * {@link IInterface#asBinder callback.asBinder()} object to correctly
140 * find the previous registration.
141 * Registrations are not counted; a single unregister call will remove
142 * a callback after any number calls to {@link #register} for it.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700143 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 * @param callback The callback to be removed from the list. Passing
145 * null here will cause a NullPointerException, so you will generally want
146 * to check for null before calling.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700147 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 * @return Returns true if the callback was found and unregistered. Returns
149 * false if the given callback was not found on the list.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700150 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 * @see #register
152 */
153 public boolean unregister(E callback) {
154 synchronized (mCallbacks) {
155 Callback cb = mCallbacks.remove(callback.asBinder());
156 if (cb != null) {
157 cb.mCallback.asBinder().unlinkToDeath(cb, 0);
158 return true;
159 }
160 return false;
161 }
162 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 /**
165 * Disable this callback list. All registered callbacks are unregistered,
166 * and the list is disabled so that future calls to {@link #register} will
167 * fail. This should be used when a Service is stopping, to prevent clients
168 * from registering callbacks after it is stopped.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700169 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 * @see #register
171 */
172 public void kill() {
173 synchronized (mCallbacks) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700174 for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) {
175 Callback cb = mCallbacks.valueAt(cbi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 cb.mCallback.asBinder().unlinkToDeath(cb, 0);
177 }
178 mCallbacks.clear();
179 mKilled = true;
180 }
181 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 /**
Dianne Hackborn231cc602009-04-27 17:10:36 -0700184 * Old version of {@link #onCallbackDied(E, Object)} that
185 * does not provide a cookie.
186 */
187 public void onCallbackDied(E callback) {
188 }
189
190 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 * Called when the process hosting a callback in the list has gone away.
Dianne Hackborn231cc602009-04-27 17:10:36 -0700192 * The default implementation calls {@link #onCallbackDied(E)}
193 * for backwards compatibility.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 *
195 * @param callback The callback whose process has died. Note that, since
196 * its process has died, you can not make any calls on to this interface.
197 * You can, however, retrieve its IBinder and compare it with another
198 * IBinder to see if it is the same object.
Dianne Hackborn231cc602009-04-27 17:10:36 -0700199 * @param cookie The cookie object original provided to
200 * {@link #register(E, Object)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 *
202 * @see #register
203 */
Dianne Hackborn231cc602009-04-27 17:10:36 -0700204 public void onCallbackDied(E callback, Object cookie) {
205 onCallbackDied(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 /**
209 * Prepare to start making calls to the currently registered callbacks.
210 * This creates a copy of the callback list, which you can retrieve items
211 * from using {@link #getBroadcastItem}. Note that only one broadcast can
212 * be active at a time, so you must be sure to always call this from the
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700213 * same thread (usually by scheduling with {@link Handler}) or
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 * do your own synchronization. You must call {@link #finishBroadcast}
215 * when done.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700216 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 * <p>A typical loop delivering a broadcast looks like this:
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700218 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 * <pre>
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700220 * int i = callbacks.beginBroadcast();
Dianne Hackborndace2302009-07-14 12:51:00 -0700221 * while (i &gt; 0) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700222 * i--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 * try {
224 * callbacks.getBroadcastItem(i).somethingHappened();
225 * } catch (RemoteException e) {
226 * // The RemoteCallbackList will take care of removing
227 * // the dead object for us.
228 * }
229 * }
230 * callbacks.finishBroadcast();</pre>
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700231 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 * @return Returns the number of callbacks in the broadcast, to be used
233 * with {@link #getBroadcastItem} to determine the range of indices you
234 * can supply.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700235 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 * @see #getBroadcastItem
237 * @see #finishBroadcast
238 */
239 public int beginBroadcast() {
240 synchronized (mCallbacks) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700241 if (mBroadcastCount > 0) {
242 throw new IllegalStateException(
243 "beginBroadcast() called while already in a broadcast");
244 }
245
246 final int N = mBroadcastCount = mCallbacks.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 if (N <= 0) {
248 return 0;
249 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700250 Object[] active = mActiveBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 if (active == null || active.length < N) {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700252 mActiveBroadcast = active = new Object[N];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 }
Dianne Hackborn390517b2013-05-30 15:03:32 -0700254 for (int i=0; i<N; i++) {
255 active[i] = mCallbacks.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 }
Dianne Hackborn390517b2013-05-30 15:03:32 -0700257 return N;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 }
259 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 /**
262 * Retrieve an item in the active broadcast that was previously started
263 * with {@link #beginBroadcast}. This can <em>only</em> be called after
264 * the broadcast is started, and its data is no longer valid after
265 * calling {@link #finishBroadcast}.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700266 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 * <p>Note that it is possible for the process of one of the returned
268 * callbacks to go away before you call it, so you will need to catch
269 * {@link RemoteException} when calling on to the returned object.
270 * The callback list itself, however, will take care of unregistering
271 * these objects once it detects that it is no longer valid, so you can
272 * handle such an exception by simply ignoring it.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700273 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 * @param index Which of the registered callbacks you would like to
275 * retrieve. Ranges from 0 to 1-{@link #beginBroadcast}.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700276 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 * @return Returns the callback interface that you can call. This will
278 * always be non-null.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700279 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 * @see #beginBroadcast
281 */
282 public E getBroadcastItem(int index) {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700283 return ((Callback)mActiveBroadcast[index]).mCallback;
284 }
285
286 /**
287 * Retrieve the cookie associated with the item
288 * returned by {@link #getBroadcastItem(int)}.
289 *
290 * @see #getBroadcastItem
291 */
292 public Object getBroadcastCookie(int index) {
293 return ((Callback)mActiveBroadcast[index]).mCookie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 }
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 /**
297 * Clean up the state of a broadcast previously initiated by calling
298 * {@link #beginBroadcast}. This must always be called when you are done
299 * with a broadcast.
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700300 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 * @see #beginBroadcast
302 */
303 public void finishBroadcast() {
Makoto Onuki7bdb9ce2016-09-15 12:52:57 -0700304 synchronized (mCallbacks) {
305 if (mBroadcastCount < 0) {
306 throw new IllegalStateException(
307 "finishBroadcast() called outside of a broadcast");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 }
Makoto Onuki7bdb9ce2016-09-15 12:52:57 -0700309
310 Object[] active = mActiveBroadcast;
311 if (active != null) {
312 final int N = mBroadcastCount;
313 for (int i=0; i<N; i++) {
314 active[i] = null;
315 }
316 }
317
318 mBroadcastCount = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 }
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -0700321
322 /**
Eugene Suslaef4351c2017-01-18 11:07:06 -0800323 * Performs {@code action} on each callback, calling
324 * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
325 *
326 * @hide
327 */
328 public void broadcast(Consumer<E> action) {
329 int itemCount = beginBroadcast();
330 try {
331 for (int i = 0; i < itemCount; i++) {
332 action.accept(getBroadcastItem(i));
333 }
334 } finally {
335 finishBroadcast();
336 }
337 }
338
339 /**
Eugene Susla4b7c919e2017-12-07 11:23:50 -0800340 * Performs {@code action} for each cookie associated with a callback, calling
341 * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
342 *
343 * @hide
344 */
345 public <C> void broadcastForEachCookie(Consumer<C> action) {
346 int itemCount = beginBroadcast();
347 try {
348 for (int i = 0; i < itemCount; i++) {
349 action.accept((C) getBroadcastCookie(i));
350 }
351 } finally {
352 finishBroadcast();
353 }
354 }
355
356 /**
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -0700357 * Returns the number of registered callbacks. Note that the number of registered
358 * callbacks may differ from the value returned by {@link #beginBroadcast()} since
359 * the former returns the number of callbacks registered at the time of the call
360 * and the second the number of callback to which the broadcast will be delivered.
361 * <p>
362 * This function is useful to decide whether to schedule a broadcast if this
363 * requires doing some work which otherwise would not be performed.
364 * </p>
365 *
366 * @return The size.
367 */
368 public int getRegisteredCallbackCount() {
369 synchronized (mCallbacks) {
370 if (mKilled) {
371 return 0;
372 }
373 return mCallbacks.size();
374 }
375 }
Dianne Hackborn5614bf52016-11-07 17:26:41 -0800376
377 /**
Dianne Hackborn59359d02017-03-03 16:03:01 -0800378 * Return a currently registered callback. Note that this is
379 * <em>not</em> the same as {@link #getBroadcastItem} and should not be used
380 * interchangeably with it. This method returns the registered callback at the given
Dianne Hackborn5614bf52016-11-07 17:26:41 -0800381 * index, not the current broadcast state. This means that it is not itself thread-safe:
382 * any call to {@link #register} or {@link #unregister} will change these indices, so you
383 * must do your own thread safety between these to protect from such changes.
384 *
Dianne Hackborn59359d02017-03-03 16:03:01 -0800385 * @param index Index of which callback registration to return, from 0 to
386 * {@link #getRegisteredCallbackCount()} - 1.
387 *
388 * @return Returns whatever callback is associated with this index, or null if
389 * {@link #kill()} has been called.
390 */
391 public E getRegisteredCallbackItem(int index) {
392 synchronized (mCallbacks) {
393 if (mKilled) {
394 return null;
395 }
396 return mCallbacks.valueAt(index).mCallback;
397 }
398 }
399
400 /**
401 * Return any cookie associated with a currently registered callback. Note that this is
402 * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
403 * interchangeably with it. This method returns the current cookie registered at the given
404 * index, not the current broadcast state. This means that it is not itself thread-safe:
405 * any call to {@link #register} or {@link #unregister} will change these indices, so you
406 * must do your own thread safety between these to protect from such changes.
407 *
408 * @param index Index of which registration cookie to return, from 0 to
409 * {@link #getRegisteredCallbackCount()} - 1.
Dianne Hackborn5614bf52016-11-07 17:26:41 -0800410 *
411 * @return Returns whatever cookie object is associated with this index, or null if
412 * {@link #kill()} has been called.
413 */
414 public Object getRegisteredCallbackCookie(int index) {
415 synchronized (mCallbacks) {
416 if (mKilled) {
417 return null;
418 }
419 return mCallbacks.valueAt(index).mCookie;
420 }
421 }
Amith Yamasani18a23f22017-04-06 10:29:33 -0700422
Koji Fukuiccec6a62017-10-18 17:48:40 +0900423 /** @hide */
424 public void dump(PrintWriter pw, String prefix) {
Wei Wang356a75a2018-11-01 16:07:38 -0700425 synchronized (mCallbacks) {
426 pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
427 pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
428 pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
429 }
Koji Fukuiccec6a62017-10-18 17:48:40 +0900430 }
431
Amith Yamasani18a23f22017-04-06 10:29:33 -0700432 private void logExcessiveCallbacks() {
433 final long size = mCallbacks.size();
434 final long TOO_MANY = 3000;
435 final long MAX_CHARS = 1000;
436 if (size >= TOO_MANY) {
437 if (size == TOO_MANY && mRecentCallers == null) {
438 mRecentCallers = new StringBuilder();
439 }
440 if (mRecentCallers != null && mRecentCallers.length() < MAX_CHARS) {
441 mRecentCallers.append(Debug.getCallers(5));
442 mRecentCallers.append('\n');
443 if (mRecentCallers.length() >= MAX_CHARS) {
444 Slog.wtf(TAG, "More than "
445 + TOO_MANY + " remote callbacks registered. Recent callers:\n"
446 + mRecentCallers.toString());
447 mRecentCallers = null;
448 }
449 }
450 }
451 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452}