diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 1b707bdf73a95..5c4a40e503dbc 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -35,6 +35,9 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; /** * Base class for a remotable object, the core part of a lightweight @@ -888,17 +891,62 @@ final class BinderProxy implements IBinder { keyArray[size] = key; } if (size >= mWarnBucketSize) { - final int total_size = size(); + final int totalSize = size(); Log.v(Binder.TAG, "BinderProxy map growth! bucket size = " + size - + " total = " + total_size); + + " total = " + totalSize); mWarnBucketSize += WARN_INCREMENT; - if (Build.IS_DEBUGGABLE && total_size > CRASH_AT_SIZE) { - throw new AssertionError("Binder ProxyMap has too many entries. " - + "BinderProxy leak?"); + if (Build.IS_DEBUGGABLE && totalSize > CRASH_AT_SIZE) { + diagnosticCrash(); } } } + /** + * Dump a histogram to the logcat, then throw an assertion error. Used to diagnose + * abnormally large proxy maps. + */ + private void diagnosticCrash() { + Map counts = new HashMap<>(); + for (ArrayList> a : mMainIndexValues) { + if (a != null) { + for (WeakReference weakRef : a) { + BinderProxy bp = weakRef.get(); + String key; + if (bp == null) { + key = ""; + } else { + try { + key = bp.getInterfaceDescriptor(); + } catch (Throwable t) { + key = ""; + } + } + Integer i = counts.get(key); + if (i == null) { + counts.put(key, 1); + } else { + counts.put(key, i + 1); + } + } + } + } + Map.Entry[] sorted = counts.entrySet().toArray( + new Map.Entry[counts.size()]); + Arrays.sort(sorted, (Map.Entry a, Map.Entry b) + -> b.getValue().compareTo(a.getValue())); + Log.v(Binder.TAG, "BinderProxy descriptor histogram (top ten):"); + int printLength = Math.min(10, sorted.length); + for (int i = 0; i < printLength; i++) { + Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i].getKey() + " x" + + sorted[i].getValue()); + } + + // Now throw an assertion. + final int totalSize = size(); + throw new AssertionError("Binder ProxyMap has too many entries: " + totalSize + + ". BinderProxy leak?"); + } + // Corresponding ArrayLists in the following two arrays always have the same size. // They contain no empty entries. However WeakReferences in the values ArrayLists // may have been cleared.