diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index 6656b00d457cd..2281fb6d5cc27 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -17,6 +17,7 @@ package android.os; import android.util.ArrayMap; +import android.util.Slog; import java.util.function.Consumer; @@ -49,16 +50,19 @@ import java.util.function.Consumer; * implements the {@link #onCallbackDied} method. */ public class RemoteCallbackList { + private static final String TAG = "RemoteCallbackList"; + /*package*/ ArrayMap mCallbacks = new ArrayMap(); private Object[] mActiveBroadcast; private int mBroadcastCount = -1; private boolean mKilled = false; + private StringBuilder mRecentCallers; private final class Callback implements IBinder.DeathRecipient { final E mCallback; final Object mCookie; - + Callback(E callback, Object cookie) { mCallback = callback; mCookie = cookie; @@ -111,6 +115,8 @@ public class RemoteCallbackList { if (mKilled) { return false; } + // Flag unusual case that could be caused by a leak. b/36778087 + logExcessiveCallbacks(); IBinder binder = callback.asBinder(); try { Callback cb = new Callback(callback, cookie); @@ -392,4 +398,25 @@ public class RemoteCallbackList { return mCallbacks.valueAt(index).mCookie; } } + + private void logExcessiveCallbacks() { + final long size = mCallbacks.size(); + final long TOO_MANY = 3000; + final long MAX_CHARS = 1000; + if (size >= TOO_MANY) { + if (size == TOO_MANY && mRecentCallers == null) { + mRecentCallers = new StringBuilder(); + } + if (mRecentCallers != null && mRecentCallers.length() < MAX_CHARS) { + mRecentCallers.append(Debug.getCallers(5)); + mRecentCallers.append('\n'); + if (mRecentCallers.length() >= MAX_CHARS) { + Slog.wtf(TAG, "More than " + + TOO_MANY + " remote callbacks registered. Recent callers:\n" + + mRecentCallers.toString()); + mRecentCallers = null; + } + } + } + } }