Merge changes Idbacb6ad,I4e06b3f9,Iffcbbb82

* changes:
  BinderProxy: Fix up differences
  Move proxy debug info dumping back to Java.
  Dump top binder proxy interface names in dumpsys.
This commit is contained in:
Treehugger Robot
2018-11-13 22:01:56 +00:00
committed by Gerrit Code Review
3 changed files with 101 additions and 57 deletions

View File

@@ -225,10 +225,11 @@ public final class BinderProxy implements IBinder {
}
}
/**
* Dump a histogram to the logcat. Used to diagnose abnormally large proxy maps.
*/
private void dumpProxyInterfaceCounts() {
private InterfaceCount[] getSortedInterfaceCounts(int maxToReturn) {
if (maxToReturn < 0) {
throw new IllegalArgumentException("negative interface count");
}
Map<String, Integer> counts = new HashMap<>();
for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
if (a != null) {
@@ -258,13 +259,30 @@ public final class BinderProxy implements IBinder {
}
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());
int returnCount = Math.min(maxToReturn, sorted.length);
InterfaceCount[] ifaceCounts = new InterfaceCount[returnCount];
for (int i = 0; i < returnCount; i++) {
ifaceCounts[i] = new InterfaceCount(sorted[i].getKey(), sorted[i].getValue());
}
return ifaceCounts;
}
static final int MAX_NUM_INTERFACES_TO_DUMP = 10;
/**
* Dump a histogram to the logcat. Used to diagnose abnormally large proxy maps.
*/
private void dumpProxyInterfaceCounts() {
final InterfaceCount[] sorted = getSortedInterfaceCounts(MAX_NUM_INTERFACES_TO_DUMP);
Log.v(Binder.TAG, "BinderProxy descriptor histogram "
+ "(top " + Integer.toString(MAX_NUM_INTERFACES_TO_DUMP) + "):");
for (int i = 0; i < sorted.length; i++) {
Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i]);
}
}
@@ -296,30 +314,57 @@ public final class BinderProxy implements IBinder {
new ArrayList[MAIN_INDEX_SIZE];
}
private static ProxyMap sProxyMap = new ProxyMap();
@GuardedBy("sProxyMap")
private static final ProxyMap sProxyMap = new ProxyMap();
/**
* Dump proxy debug information.
*
* Note: this method is not thread-safe; callers must serialize with other
* accesses to sProxyMap, in particular {@link #getInstance(long, long)}.
*
* @hide
*/
private static void dumpProxyDebugInfo() {
* Simple pair-value class to store number of binder proxy interfaces live in this process.
*/
public static final class InterfaceCount {
private final String mInterfaceName;
private final int mCount;
InterfaceCount(String interfaceName, int count) {
mInterfaceName = interfaceName;
mCount = count;
}
@Override
public String toString() {
return mInterfaceName + " x" + Integer.toString(mCount);
}
}
/**
* Get a sorted array with entries mapping proxy interface names to the number
* of live proxies with those names.
*
* @param num maximum number of proxy interface counts to return. Use
* Integer.MAX_VALUE to retrieve all
* @hide
*/
public static InterfaceCount[] getSortedInterfaceCounts(int num) {
synchronized (sProxyMap) {
return sProxyMap.getSortedInterfaceCounts(num);
}
}
/**
* Dump proxy debug information.
*
* @hide
*/
public static void dumpProxyDebugInfo() {
if (Build.IS_DEBUGGABLE) {
sProxyMap.dumpProxyInterfaceCounts();
// Note that we don't call dumpPerUidProxyCounts(); this is because this
// method may be called as part of the uid limit being hit, and calling
// back into the UID tracking code would cause us to try to acquire a mutex
// that is held during that callback.
synchronized (sProxyMap) {
sProxyMap.dumpProxyInterfaceCounts();
sProxyMap.dumpPerUidProxyCounts();
}
}
}
/**
* Return a BinderProxy for IBinder.
* This method is thread-hostile! The (native) caller serializes getInstance() calls using
* gProxyLock.
* If we previously returned a BinderProxy bp for the same iBinder, and bp is still
* in use, then we return the same bp.
*
@@ -331,21 +376,23 @@ public final class BinderProxy implements IBinder {
*/
private static BinderProxy getInstance(long nativeData, long iBinder) {
BinderProxy result;
try {
result = sProxyMap.get(iBinder);
if (result != null) {
return result;
synchronized (sProxyMap) {
try {
result = sProxyMap.get(iBinder);
if (result != null) {
return result;
}
result = new BinderProxy(nativeData);
} catch (Throwable e) {
// We're throwing an exception (probably OOME); don't drop nativeData.
NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer,
nativeData);
throw e;
}
result = new BinderProxy(nativeData);
} catch (Throwable e) {
// We're throwing an exception (probably OOME); don't drop nativeData.
NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer,
nativeData);
throw e;
NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData);
// The registry now owns nativeData, even if registration threw an exception.
sProxyMap.set(iBinder, result);
}
NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData);
// The registry now owns nativeData, even if registration threw an exception.
sProxyMap.set(iBinder, result);
return result;
}
@@ -526,12 +573,11 @@ public final class BinderProxy implements IBinder {
}
}
private static final void sendDeathNotice(DeathRecipient recipient) {
private static void sendDeathNotice(DeathRecipient recipient) {
if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
try {
recipient.binderDied();
}
catch (RuntimeException exc) {
} catch (RuntimeException exc) {
Log.w("BinderNative", "Uncaught exception from death notification",
exc);
}

View File

@@ -110,7 +110,6 @@ static struct binderproxy_offsets_t
jclass mClass;
jmethodID mGetInstance;
jmethodID mSendDeathNotice;
jmethodID mDumpProxyDebugInfo;
// Object state.
jfieldID mNativeData; // Field holds native pointer to BinderProxyNativeData.
@@ -1038,18 +1037,6 @@ static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
static void android_os_BinderInternal_proxyLimitcallback(int uid)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
{
// Calls into BinderProxy must be serialized
AutoMutex _l(gProxyLock);
env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mDumpProxyDebugInfo);
}
if (env->ExceptionCheck()) {
ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
report_exception(env, excep.get(),
"*** Uncaught exception in dumpProxyDebugInfo");
}
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
gBinderInternalOffsets.mProxyLimitCallback,
uid);
@@ -1439,8 +1426,6 @@ static int int_register_android_os_BinderProxy(JNIEnv* env)
"(JJ)Landroid/os/BinderProxy;");
gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
"(Landroid/os/IBinder$DeathRecipient;)V");
gBinderProxyOffsets.mDumpProxyDebugInfo = GetStaticMethodIDOrDie(env, clazz, "dumpProxyDebugInfo",
"()V");
gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
clazz = FindClassOrDie(env, "java/lang/Class");

View File

@@ -318,6 +318,7 @@ import android.net.ProxyInfo;
import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.BinderProxy;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
@@ -15210,6 +15211,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public void onLimitReached(int uid) {
Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ Process.myUid());
BinderProxy.dumpProxyDebugInfo();
if (uid == Process.SYSTEM_UID) {
Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
} else {
@@ -16061,8 +16063,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
} else if ("binder-proxies".equals(cmd)) {
if (opti >= args.length) {
dumpBinderProxyInterfaceCounts(pw,
"Top proxy interface names held by SYSTEM");
dumpBinderProxiesCounts(pw, BinderInternal.nGetBinderProxyPerUidCounts(),
"Counts of Binder Proxies held by SYSTEM");
"Number of proxies per uid held by SYSTEM");
} else {
String uid = args[opti];
opti++;
@@ -16565,6 +16569,15 @@ public class ActivityManagerService extends IActivityManager.Stub
return printed;
}
void dumpBinderProxyInterfaceCounts(PrintWriter pw, String header) {
final BinderProxy.InterfaceCount[] proxyCounts = BinderProxy.getSortedInterfaceCounts(50);
pw.println(header);
for (int i = 0; i < proxyCounts.length; i++) {
pw.println(" #" + (i + 1) + ": " + proxyCounts[i]);
}
}
boolean dumpBinderProxiesCounts(PrintWriter pw, SparseIntArray counts, String header) {
if(counts != null) {
pw.println(header);