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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user