记一次诡异的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。

《记一次诡异的Bug修复——App自启动》 应该被销毁的SplashActivity实例数量不为0

继续深究,排查为什么SplashActivity实例还存在,此时就需要MAT上场大显身手:

3.1 使用Histogram功能检索SplashActivity的实例对象;

《记一次诡异的Bug修复——App自启动》 检索SplashActivity实例

3.2 对着SplashActivity对象实例点击右键 -> List objects -> with incoming references 查看具体实例;

《记一次诡异的Bug修复——App自启动》 查看具体SplashActivity实例

3.3 然后排除掉软引用的干扰;

《记一次诡异的Bug修复——App自启动》 注意左下角那个小圆圈

至此: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干货!

《记一次诡异的Bug修复——App自启动》 欢迎关注

    原文作者:头条祁同伟
    原文地址: https://www.jianshu.com/p/f3d90be42719
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞