背景:版本灰度出现了handler相关奇怪的crash,不管是init,poll,wake都会出现类似crash
问题分析
Looper::wake 看上去是mWakeEventFd write时出问题了
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endif
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
mWakeEventFd.get(), nWrite, strerror(errno));
}
}
}
在logcat中发现了如下日志,这个时候可以大概率确认是谁把我们的fd给close了。
到底谁把我们close呢? 线上crash率只有万分之一,想正常复现很难。
- 观察crash设备表现,都发生在启动时机。找到启动改动的点。
- Android 10以上 一般java 层使用到的fd 都有closed判断,怀疑是native的问题,找到版本改动的so
- 一顿修改代码search后 发现一个怀疑点。
这边会是去关闭两次fd的。
- 关闭上面模块代码开关后,crash不再发生了。
继续分析
虽然上面问题解决了,我们继续分析,尝试去复现一下。
成功复现
监控方案
上面的方法发现并解决这个问题 运气占很大成分,想好后续如果再出现类似问题,如何精准定位才是关键。
android.googlesource.com/platform/bi… AOSP文档
android 10以上 有专门的fdsan用于监控排错。
把fdsan level设为 ANDROID_FDSAN_ERROR_LEVEL_FATAL 报下面错误,按照下面堆栈我们就能正确找到多次close的地方了