前言
flutter 升级到 1.17之后,app ios 线上遇到一个crash ,通过官方的 符号表文件 flutter.dsym 还原出堆栈如下
1 | 0 auto fml::internal::CopyableLambda<flutter::Shell::OnPlatformViewCreated(std::__1::unique_ptr<flutter::Surface, std::__1::default_delete<flutter::Surface> >)::$_8>::operator()<>() const (in Flutter) (make_copyable.h:24) |
这里还只能看到crash在engine的c++代码中,具体原因未知
定位
我们根据crash 用户的 埋点日志 分析crash前的 使用路径,基本都是打开push 落地到一个flutter页面
app 的 第一个tab 也是个 flutter 页面,所以是push 唤起app,连续打开两个flutter页面。
手动打开app,点击进到flutter页面是不会crash的(这么简单的路径,如果crash,那就该死了)
很快我们就可以通过这个 路径 复现 crash ,能复现就好说。
debug engine源码,可以定位到更具体的地方
surface_ 为 null ,EXC_BAD_ACCESS 野指针
分析
定位到了具体的代码位置,接下来分析下野指针的原因
xcode中 crash 的时候,看到主线程的 堆栈记录 是从 application 的 didbecomeactive 的 notification发起的
由于是 push 唤起app ,有这个通知是对的,crash 是在 共享engine 的 raster 线程。
看代码
1 |
|
这么一路看下来,surface_怎么会变成null呢?一般情况是,执行 [self surfaceUpdated:NO] 的时候会销毁surface,断点根本都没进去。
继续看代码
1 |
|
所以原因 就是 落地页 init 的时候 重新attach 引擎,NotifyDestroyed 方法 最终会销毁 surface,这时候正好raster线程使用 surface_做方法调用。
修复
定位到原因,修复就简单了,做下空判断就好了,如果为空 就直接return
1 | void Rasterizer::Setup(std::unique_ptr<Surface> surface) { |
这里是直接修改了引擎的代码,所以需要重新编译engine 产物,替换掉就搞定了
其他
1.17之前的版本 1.12.13 的时候,不确定engine存不存在这个问题,有空再看看。
后面github提issue、PR,看看官方怎么看待这个问题,修复应该还有其他办法。