1. 背景
项目正常压力测试,system_server crash导致系统重启。查看dropbox里面的system_server_crash trace,发现是因为系统检测到system_server 的 BinderProxy累计数量超过了android系统设置的20000,认为存在BinderProxy leak,抛出异常,最终导致system_server crash。
private static final int CRASH_AT_SIZE = 20_000;
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: java.lang.AssertionError: Binder ProxyMap has too many entries: 21033 (total), 20593 (uncleared), 20480 (uncleared after GC). BinderProxy leak?
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at android.os.BinderProxy$ProxyMap.set(BinderProxy.java:230)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at android.os.BinderProxy.getInstance(BinderProxy.java:432)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at android.view.InputChannel.nativeGetToken(Native Method)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at android.view.InputChannel.getToken(InputChannel.java:185)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at com.android.server.wm.WindowState.openInputChannel(WindowState.java:2476)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at com.android.server.wm.WindowManagerService.addWindow(WindowManagerService.java:1626)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at com.android.server.wm.Session.addToDisplayAsUser(Session.java:176)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:679)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at com.android.server.wm.Session.onTransact(Session.java:139)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at android.os.Binder.execTransactInternal(Binder.java:1154)
07-27 19:14:19.587883 28713 29738 E AndroidRuntime: at android.os.Binder.execTransact(Binder.java:1123)
2. bug分析
通过打印的堆栈信息可以知道: at android.os.BinderProxy$ProxyMap.set(BinderProxy.java:230) 是BinderProxy的230行出现的异常,找到对应的源码如下:
void set(long key, @NonNull BinderProxy value) {
int myHash = hash(key);
ArrayList<WeakReference<BinderProxy>> valueArray = mMainIndexValues[myHash];
if (valueArray == null) {
valueArray = mMainIndexValues[myHash] = new ArrayList<>();
mMainIndexKeys[myHash] = new Long[1];
}
int size = valueArray.size();
WeakReference<BinderProxy> newWr = new WeakReference<>(value);
// First look for a cleared reference.
// This ensures that ArrayList size is bounded by the maximum occupancy of
// that bucket.
for (int i = 0; i < size; ++i) {
if (valueArray.get(i).get() == null) {
valueArray.set(i, newWr);
Long[] keyArray = mMainIndexKeys[myHash];
keyArray[i] = key;
if (i < size - 1) {
// "Randomly" check one of the remaining entries in [i+1, size), so that
// needlessly long buckets are eventually pruned.
int rnd = Math.floorMod(++mRandom, size - (i + 1));