一次崩溃事件的调查过程
周六晚,收到反馈称新浪微博上有数十起用户在发表话题声称启动闪退.观察对应机型后,去往对应的应用商店查看评论,发现投诉闪退用户集中在O/V平台.且多为6.0及以下用户.
通过vivo开发者平台进行真机测试,完全无法重现,一方面新版本发布在即,需要确定问题在新版本中是否还存在,另一方面崩溃还在持续产生,问题比较严重.
第二天去公司排查问题,在意见反馈平台也发现大量闪退反馈,分析反馈上来的日志多为卸载重装后产生,多数没有价值,为数不多的有效日志中发现了breakpad的dump操作,且dump size普遍大于1,说明上一次so崩溃后,启动时dump过程中又崩溃了,有dmp文件累积.
- 崩溃出现在oppo/vivo机型.
- 崩溃出现在6.0及以下机型.
- 友盟的java crash率无异常.
- 反馈上传日志中breakpad dump操作.
根据以上特征可以确定是so崩溃.
既然是so崩溃,则需要去后台的错误收集平台查看dump完成后上传的堆栈信息,可惜的是由于是启动即崩溃,很多日志都没能上传成功.
这里发现一个优化点:
由于目前崩溃日志放在Android/data目录下,卸载时会清空,导致启动即崩溃的日志无法在卸载/清除数据后得到保留,这是一个很关键的点,需要改善.
经过对意见反馈日志的筛选,终于找出少量上传成功的设备,于是根据设备id去错误收集平台查看.分析日志发现导致崩溃的是一个叫libnative_lib.so的文件导致,这个文件不在apk文件中,好像是个系统so?(由于so名字问题,这里浪费了很多时间,后面详细介绍)
由于看起来是系统so的崩溃,日志所能提供的信息就到此为止了.换个思路,从改动点查起.
检查一下最近的版本发布
1.意见反馈的都是线上最新版本,其他版本没有出现意见反馈.(由于卸载后重装一般会使用线上最新版本,所以这里并不能代表旧版本没有出现崩溃,但是当时没有考虑到这一点)
2.崩溃发生在新版本上线一周后.
这里有两个分析点:
- 新版本和上一版本在so方面有何不同?
- 上线一周后,有没有什么动态配置的信息发生了变更?
新旧版本比对
经过apk文件的so比对,发现播放器组件,下载组件,广告组件在最近版本发布中有修改.于是一边联系对应开发方确认修改点,一边着手备用方案一:
回滚携带so且有变更的sdk库,保证新版本稳定发布.
很可惜的是,根据收集到的多方sdk修改点,结合崩溃产生场景,并没有关联.再加上回滚过程中产生其他编译问题/运行问题,这条路先放一边.
配置接口变更
目前配置接口主要包含两方面:app自身的配置接口和广告配置接口.
首先找上的是广告配置接口,因为这方面由于接入广告方众多,且已确定存在第三方动态加载dex和so行为,可控性不够,嫌疑最大.首先通知广告部门依次停掉可疑的广告开关,待5分钟生效后,与联系上的用户核查是否继续崩溃,需要一些时间,而且涉及广告缓存问题需要更细致的检查.
同时app自身的配置接口也不能放下,直接联系接口开发人员咨询在那个时间点附近有无修改配置信息,得知当天正好有两个修改点.于是开始检查对应配置修改对app的影响.
可惜的是,通过本地map local未能重现.
到此为止,动态配置的可能性好像被排除了.无法重现意味着无法确认修改方式是否有效,我们甚至一度怀疑是不是某些我们集成的某些不受控sdk针对长沙地区做了特别处理…
难道除了使用自己心里也没底的回滚sdk方案,就没有别的路了么?
就在快要放弃的时候,转机来了.
获得崩溃现场
在与负责自身配置接口的后台开发人员沟通过程中,得知他的手机也是一打开app就崩溃.在再三叮嘱保存现场,千万不要卸载或者清除app之后,同事立马驱车前往取手机…
拿回手机后,确实进入app就崩溃.虽然由于是release版本,无法进入私有目录,但是插上电脑可以看到日志还是非常有价值的.
然而现实很残酷,插上手机后依然没有太多有效信息.只是确认了两个问题:
- 现在可以完全确认是so崩溃了.
- 崩溃最后在这个so:libnative_lib.so.到底是哪里来的?(名字带来的误解仍然存在)
此时与用户的沟通的过程中收到一个重要反馈:断网情况下进入app,不崩溃.
毫无疑问和某个配置有关.
具体是哪个配置呢?app启动时调用的接口多达几十个.本来想着连上charles,一个一个去hook,来查找是哪个接口原因.但是接下来的一个事实让我懵了:
手机连接charles代理,将所有接口调用都加入black list,启动app仍然崩溃.
断网不崩溃,但屏蔽所有接口又崩溃,看来是之前某个配置的缓存在”发挥作用”:
拉配置之前会检查网络状态,若无网则不请求也不使用缓存,相当于未开启该功能.但是如果通过黑名单方式使接口请求失败了,就会使用上次下载的缓存配置.
但是目前无法通过清除数据来确认这一点,唯一的现场不能丢.
到底是哪个缓存有问题呢?能否把缓存拉出来分析,或者复制到另一台手机上看是否能重现?
考虑到这是一台未root的oppo手机,中间尝试导出app私有目录下的相关文件未果.
接口breakpoint
既然不能用黑名单,那就在接口请求上面打断点好了.通过对启动接口调用使用二分法排除之后,终于确定了一个有问题的接口.

原来这个libnative_lib.so竟然是接口下发的.
libnative_lib.so并不是什么系统so.仅仅是一些c++官方教程里面喜欢拿这个当做默认名字.
在这个接口打上断点后,可以维持5s左右不崩溃了,5s后接口超时,适用接口错误场景,会加载上次缓存数据,继续崩溃.
原因找到了,接下来就是对这个配置接口做一些修改,看能否通过其开关配置停掉对应的so加载.

改了下载路径后,终于不崩溃了.
现在可以把问题抛给对应sdk提供方,让他们去寻找修复方案了.
总结一下本次事故分析过程.
分析过程改进点:
- 不要被so文件名字迷惑,对系统自带so要有了解.
- 如果能确定是某个动态下发的文件导致,可以直接在charles中的response中搜索这个名字.
app开发风险点:
- 第三方动态加载dex和so过程不可控.
- 日志不能放在apk目录,应该在/sdcard中单独使用文件夹存储,反之后续启动即崩溃的场景中,用户安装其他版本后无法保留关键日志.
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!