Dump binder proxies interface descriptors on a separate thread.

There are apparently some processes that block getInterfaceDescriptor()
from completing, thus locking up the thread doing the binder proxy dump.
This can cause the watchdog to restart system_server. Move the calls to
a separate thread and give it some time to complete!

Bug: 174722615
Bug: 183676249
Test: adb shell am dump binder-proxies
Change-Id: Ifa79e53524197bf1d785210b7504e7f6c6ddc9b7
Merged-In: Ifa79e53524197bf1d785210b7504e7f6c6ddc9b7
(cherry picked from commit f1a22a35e8)
This commit is contained in:
Martijn Coenen
2021-02-05 11:32:44 +01:00
parent a14d76517a
commit 0110dc4836

View File

@@ -34,6 +34,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Java proxy for a native IBinder object.
@@ -262,27 +265,45 @@ public final class BinderProxy implements IBinder {
Log.e(Binder.TAG, "RemoteException while disabling app freezer");
}
for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
BinderProxy bp = weakRef.get();
String key;
if (bp == null) {
key = "<cleared weak-ref>";
} else {
try {
key = bp.getInterfaceDescriptor();
if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
key = "<proxy to dead node>";
// We run the dump on a separate thread, because there are known cases where
// a process overrides getInterfaceDescriptor() and somehow blocks on it, causing
// the calling thread (usually AMS) to hit the watchdog.
// Do the dumping on a separate thread instead, and give up after a while.
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(() -> {
for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
BinderProxy bp = weakRef.get();
String key;
if (bp == null) {
key = "<cleared weak-ref>";
} else {
try {
key = bp.getInterfaceDescriptor();
if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
key = "<proxy to dead node>";
}
} catch (Throwable t) {
key = "<exception during getDescriptor>";
}
} 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);
}
}
Integer i = counts.get(key);
if (i == null) {
counts.put(key, 1);
} else {
counts.put(key, i + 1);
});
try {
executorService.shutdown();
boolean dumpDone = executorService.awaitTermination(20, TimeUnit.SECONDS);
if (!dumpDone) {
Log.e(Binder.TAG, "Failed to complete binder proxy dump,"
+ " dumping what we have so far.");
}
} catch (InterruptedException e) {
// Ignore
}
try {
ActivityManager.getService().enableAppFreezer(true);