Merge "Binder: Log a histogram of binder proxies to logcat on death" am: 4b7abe301c am: 3c57709e70
am: 906d0c9375
Change-Id: I30960a4d831f420911b287145646be569423fdd0
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b7a4645..33470f3 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -35,6 +35,9 @@
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
@@ -901,17 +904,62 @@
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<String, Integer> counts = new HashMap<>();
+ for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
+ if (a != null) {
+ for (WeakReference<BinderProxy> weakRef : a) {
+ BinderProxy bp = weakRef.get();
+ String key;
+ if (bp == null) {
+ key = "<cleared weak-ref>";
+ } else {
+ try {
+ key = bp.getInterfaceDescriptor();
+ } catch (Throwable t) {
+ key = "<exception during getDescriptor>";
+ }
+ }
+ Integer i = counts.get(key);
+ if (i == null) {
+ counts.put(key, 1);
+ } else {
+ counts.put(key, i + 1);
+ }
+ }
+ }
+ }
+ Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
+ new Map.Entry[counts.size()]);
+ Arrays.sort(sorted, (Map.Entry<String, Integer> a, Map.Entry<String, Integer> 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.