本期专门介绍一个线上bug的排查跟修复过程,首先看下崩溃路径
1 #00 pc 00000000003ff65c /system/lib64/libhwui.so (SkPathRef::growForVerb(int, float)+336) [arm64-v8a]
2 #01 pc 00000000003fdb60 /system/lib64/libhwui.so (SkPath::conicTo(float, float, float, float, float)+144) [arm64-v8a]
3 #02 pc 000000000044c6d0 /system/lib64/libhwui.so (SkPath::addOval(SkRect const&, SkPath::Direction, unsigned int)+372) [arm64-v8a]
4 #03 pc 000000000019c05c /system/lib64/libhwui.so (SkPath::addCircle(float, float, float, SkPath::Direction)+76) [arm64-v8a]
5 #04 pc 00000000004220a8 /system/framework/arm64/boot-framework.oat [arm64-v8a]
6 java:
7 android.graphics.Path.addCircle(Path.java:593)
8 com.meitu.app.meitucamera.e.d.w(CameraAroundBlur.java:1172)
9 com.meitu.app.meitucamera.e.d.u(CameraAroundBlur.java:1049)
10 com.meitu.app.meitucamera.e.d.a(CameraAroundBlur.java:271)
接下来看下实际崩溃的代码(历史代码,有删减,实现这部分代码的人已离职)
private Path mPathFullRingBlurArea = new Path();
mPathFullRingBlurArea.reset();
mPathFullRingBlurArea.addRect(new RectF(mBlurRect), Path.Direction.CCW);
mPathFullRingBlurArea.addCircle(mCenterPoint.x + left, mCenterPoint.y + top, mOuterRadius, Path.Direction.CW);
mPathFullRingBlurArea.close();
可以很明显的看到,就是addCircle方法发生的崩溃,崩溃的地方是系统类Path的方法
还有崩溃2,数量也比较高,崩溃log如下
# AppExecutors-mt(32487)SIGSEGV(SEGV_MAPERR)
1 #00 pc 000000000025cf00 /system/lib64/libhwui.so (SkPathRef::growForVerb(int, float)+456) [arm64-v8a]
2 #01 pc 00000000003483e4 /system/lib64/libhwui.so (SkPath::addOval(SkRect const&, SkPath::Direction, unsigned int)+472) [arm64-v8a]
3 #02 pc 00000000003481e4 /system/lib64/libhwui.so (SkPath::addCircle(float, float, float, SkPath::Direction)+72) [arm64-v8a]
4 #03 pc 00000000002e17e8 /system/framework/arm64/boot-framework.oat [arm64-v8a]
5 java:
6 [Failed to get Java stack]
只有native层的log,不过有显示SkPath::addCircle
信息,怀疑是同个崩溃(后来也证实,确实是同个崩溃)
当然,看到这里,就可以直接大概猜到崩溃原因的大神,请收下打的膝盖,不过自己的资历不够,于是继续分析
接下来看下其他维度的信息,看下可否辅助定位
崩溃数量:也比较高,影响了上万个用户了
崩溃设备:主要是10的系统,华为的机型
还有其他几个维度的信息,也都没有直接有助于定位问题的
接下来,尝试自己复现,发现本地无法复现,也有让测试配合验证,也没有复现,经内部讨论,怀疑会不会path的参数有问题,于是增加了参数埋点上报,跟着下个版本上线,看下线上实际崩溃时候的参数
发版后,收集log,发现线上崩溃时候的参数,跟本地自测的参数一样,没有异常,这里,初步排除参数异常问题
接下来,继续本地排查,path其实很多地方都在用,其他地方都没有问题,排除是系统Path类的异常,对代码继续断点跟打log验证,发现一个可疑的现象 出问题的这个方法,存在多线程调用的现象
可以发现,有主线程跟异步线程在调用这个方法,时间间隔几十毫秒,path类是用于canvas绘制的,绘制必定是主线程,path本身也不是线程安全的类,由此分析,多线程去操作同一个path实例,本身是不合理的,应该统一放主线程操作,于是做下如下修复
private void updateDiscontinuousBlurAreaPaths() {
if (Looper.getMainLooper() != Looper.myLooper()) {
//path不是线程安全的类,如果不是主线程调用,统一改成主线程调用
AppExecutors.executeMain(new Runnable() {
@Override
public void run() {
updateDiscontinuousBlurAreaPaths();
}
});
return;
}
//省略该方法的其他代码
}
修改后,由于无法本地验证,所以等到了下个版本上线后,看了下崩溃情况
发版后发现,最新版本没有再出现了,随着新版本逐渐覆盖上去,整体崩溃持续下降,由此确定问题已修复。
行数:63
字数:846
主题:默认主题