记录一个bug
最近遇到一个非常难搞的问题,花了蛮长的时间才算解决了,这里记录一下自己的解决过程!
图片显示一半
我们的APP里面偶尔出现图片只加载了一部分的问题,但是其他用户显示是正常的,也不算必现,就是偶尔听用户报一下,之前也没有太过关注这个bug了,没有及时去处理,作为了一个遗留问题,延后解决!
随着时间的流逝,突然一个大boss直接将这个bug反馈到我们研发,而且还是比较重要的图片,需要我们马上去处理,之前的债也得补上了!
解决过程
猜想
首先根据我们项目,做了几点思考:
图片是加密的,加密方式是AES的,有个别人只看到图片的一部分,说明:
1.图片的上行是没有问题的
2.可能是下行
3.解密出现问题
验证猜想
1.因为其他人可以正常查看,说明图片上传OK
2.确保图片下载是OK的
我们将正常用户的图片和出问题的图片进行文件大小,md5比对,发现没有异常
3.确保解密是否正常
我们将解密的图片直接保存到SD卡,然后用相册查看,发现是正常的,说明解密也是OK的
继续猜想
前面的步骤的确认没有问题,那就只有最后一步了,显示框架的问题!
我们的图片显示使用的是Glide,直接将解密后的文件流传递给Glide,这就比较难搞了,如果是Glide的问题那就真的不太好解决了,接下来的时间就比较茫然和懵逼了,不知道怎么去定位问题了!难道是传递给Glide的流可能有问题,或者流没有关闭。。。。
验证
将正常显示的图片传递给Glide的inputStream比对错误的流,发现流的大小是一样的,各种检查代码也没有什么卵用。。。。
猜想
突然一天中午起床,脑子像开了挂一样,发现了一个惊天秘密,显示图片的逻辑如下:
if(!FileUtils.isFileExist(path)){
//文件不存在,去下载
}else {
//文件存在,Glide显示
}
那如果点击预览之后,首先图片不存在,网络加载,退出预览界面,再次进入,那么此时文件已经下载了一部分了,肯定就走else的逻辑,直接显示图片,我们之前有个结论:
如果图片不完整,AES应该是解密不出来的
那么这个时候图片应该不能显示,而不是只显示一部分,和结论矛盾了
验证
抱着试一试的态度,去重现这个场景,点击预览,网络下载图片,然后退出,再次预览,发现必现该bug,那么说明这个结论是错误的:
如果文件不完整,AES也能部分解密
这样的话,这个bug就能解释的通了:
文件没有完全下载,解密只解了一部分,交给Glide也就只显示了一部分
我们又对图片做了磁盘缓存:
Glide.diskCacheStrategy(DiskCacheStrategy.RESULT).into(imageview);
这次不完整的图片就被Glide缓存了起来,以后每次预览都只显示这个缓存图片,没有机会去加载完整的图片,也就是后面就算每次传递给Glide的流是完整的,有没有去加载这个流的数据!
为了验证是Glide使用了磁盘缓存里面的图片,我直接将Glide的磁盘缓存清理掉:
Glide.get(ApplicationExt.mContext.getApplicationContext()).clearDiskCache();
果然图片正常显示了出来!知道bug出生的原因了,修改也就简单了
完善
1.确保文件完整
上传,下载都加上MD5验证,确保文件本身是没有问题
2.预览的判断
md5一致,并且文件存在才去预览