记一次诡异的Bug修复——App自启动
1、前言
在上一版本App临发版之前,QA和PM同学同时报了一个严重的Bug:App退出之后会自动重新启动,也就是用户关不了App。开发者梦寐以求的应用常驻就这么被莫名其妙的实现了!当然这是句玩笑,估计用户会直接了当卸载才是真的。
我们项目里确实也有应用保活的策略,但是并不流氓,更不会无厘头的在用户主动关闭App的时候重启。
2、分析
最初进行了两点分析:
- RD在App退出的方法里加了重启的代码,自测使用却提交到了代码仓库;
- App崩溃导致的重启,因为项目里有崩溃之后自动重启的逻辑;
但是查看代码之后否定了以上分析:
- App退出的方法里没有被修改;
- 确认应用没有崩溃,而且项目里也有崩溃保护策略,不会无限次、任意时间都可以重启。
而且在开发阶段其实发现过这个Bug,但是每当闲下来追踪的时候会发现Bug又不复现了。可以得出结论:这是一个非必现、场景复现的Bug。
3、解决
一筹莫展之际,我采用打Log的方式观察App的启动过程,没有发现启动的异常,但发现了启动页Activity的onDestroy()方法没有执行。大喜过望的我马上Dump了当前的堆栈信息,AndroidStudio打开之后按照包名的方式去查找启动类SplashActivity,发现应该被销毁的SplashActivity实例数量不为0。
应该被销毁的SplashActivity实例数量不为0继续深究,排查为什么SplashActivity实例还存在,此时就需要MAT上场大显身手:
3.1 使用Histogram功能检索SplashActivity的实例对象;
检索SplashActivity实例3.2 对着SplashActivity对象实例点击右键 -> List objects -> with incoming references 查看具体实例;
查看具体SplashActivity实例3.3 然后排除掉软引用的干扰;
注意左下角那个小圆圈至此:SplashActivity实例不被销毁的原因找到了:ShowAdInstance中持有了SplashActivity的引用,ShowAdInstance不被销毁,那么SplashActivity也无法被销毁。
那么ShowAdInstance为什么不被释放呢?ShowAdInstance中封装了广告页下载、展示的逻辑,持有了SplashActivity的引用,但是明明也是有注销的啊。反复查看代码逻辑最终定位到有一处判断漏调了注销的方法,导致SplashActivity对象没有被销毁,App杀掉进程之后由于SplashActivity的存在导致应用直接重启。
而上面也说到了:这是个场景复现的Bug,这个场景就是下载了开机闪屏图但是没有到显示时间。而这个场景出现的原因是开机闪屏图有预上线的策略。
至此,真相大白,果然在此处逻辑判断里加上了注销的代码之后App的退出又重启功能就不见了。
4、总结
4.1 思路
遇到这种诡异Bug的一个思路:猜测原因,快速验证;辅助Log,抓住一点持续突破。
4.2 其它
对一些开发工具的使用,例如文中所讲对内存泄漏来说有用的Memory Monitor、MAT。类如MAT的使用,很容易忘记;但是之前我写过此类文章,因此我直接去找了之前的文章(强势广告来一发:参见《Android性能优化(四)之内存优化实战》一文),很快速的回忆起了使用步骤,很快的定位到了问题。
三个字:多总结!
备注:为什么此处没有使用LeakCanary来验证猜想呢?因为事发在临上线前,我们已经关掉了LeakCanary,因此直接撸起袖子就是干,使用了这俩相对操作复杂的工具。
欢迎关注微信公众号:定期分享Java、Android干货!
欢迎关注