crash问题千奇百怪,涉及到厂商相关的代码我们该如何去分析。
- 如何通过现有crash信息分析尝试复现crash?
- 如何快速获取到厂商crash相关代码?
- 如何通过反编译和trace手段快速分析代码逻辑?
- 如何利用hook手段做crash保护?
下面通过一个案例和大家分享一下我这边的排查定位保护过程。
分析解决
-
从crash大盘中找到该crash出现频率较多的系统版本和设备型号。
-
从crash的url分布发现相关页top1页面,结合分析工具路径我们尝试复现该堆栈。
-
复现堆栈后不一定crash,但是我们可以通过打印堆栈dex location的方式找到代码所在磁盘位置并拉取代码。 线下class location获取方式
- 线下获取class dex location方式 ,这点有在widget内存优化文章也有提到。 找到gLogVerbosity这个全局属性后修改class_linker为true
线上class location获取方式
线上不适合打开调式日志,class_linker的调式日志还是有点多的。 所以还要找个线上能获取到dex location的方式,毕竟不是每次都能够那么幸运的复现问题。观察了下mirror::class的GetLocation方法 ,其实使用java.lang.Class通过反射拿到dexCache再拿到location就可以。 这样的话线上出现一些异常堆栈我们也能根据这个拿到代码保存,然后回捞分析。
try {
Class a =Class.forName("vivo.contentcatcher.ViewAnalyzerFactory");
Field dexCahce = Class.class.getDeclaredField("dexCache");
dexCahce.setAccessible(true);
Object dexCacheInstance = dexCahce.get(a);
Method metaGetDeclaredField = Class.class.getDeclaredMethod("getDeclaredField", String.class);
Field location = (Field) metaGetDeclaredField.invoke(dexCacheInstance.getClass(), "location");
location.setAccessible(true);
Object o = location.get(dexCacheInstance);
Log.i("zzzzz",o.toString());
} catch (Throwable e) {
e.printStackTrace();
}
-
反编译代码 查看里面相关的文件 猜测功能,其实这边通过堆栈包名也能猜到 往这个方向测试
-
长按 触发智慧视觉识别功能复现 crash几乎必现,而出现页面经常要长按操作,这也是该页面容易出现的原因。系统设置页面关闭智慧视觉功能后不出现。
-
提交日志,反馈vivo,vivo这边确认问题后回复计划推送rom解决(vivo没有回复具体原因,猜测是h5游戏页面用的组件和智慧视觉的提取图片功能一起触发的问题)
-
crash还在一直在上涨,半夜甚至还出现了告警,后来确认是因为凌晨活动重置,玩这个游戏的用户在一个峰值。虽然这个crash不到万分之一的设备crash率,一方面不知道vivo具体推送的rom时间,一方面玩游戏的闪退的体验确实不好受。为了提升用户体验还是要想办法去解决这个问题。
-
一开始是想通过PLT Hook hook 这个apk文件的打开 直接返回-1。本地机器验证了确实可以,但是有个问题这个apk路径不是固定的,每个手机上都有可能不一样,而且hook的范围也可能稍大了些,所有的io可能都要过一下这个逻辑。
-
接下来通过class load的日志和自制的trace打点工具结合perfetto分析代码逻辑
- 第一个图是1秒左右 主线程处理长按事件。
- 第二张图是binder线程去加载contentcatcher这个apk的代码和资源
- 第三张图的堆栈就是导致crash的堆栈。
-
分析了contentcatcher的加载流程后,我们就要想办法去打破这条链路。我这边是找了第二个过程作为突破口,这个过程代码不在contentcatcher.apk 通过class load日志可以发现在vivo的一个framwork jar下 ,同样的方式拉取代码分析
- 发现一个hook点 可以直接修改CONTENT_CATCHER_ID 不去加载功能。直接通过反射修改。
-
一轮灰度后发现还有crash上报,继续分析相关机型,发现新版本 framework有修改,无法通过修改CONTENT_CATCHER_ID解决,code判断的地方直接写死了。 重新找hook点。
- 反射修改sViewAnalyzerClzz让其找不到类。修改后发现是个hide 字段,所以这里要用双反射绕过。
- 配置中心下发开关hook,crash下降。 待vivo rom推送覆盖后再打开开关。
- 厂商相关的问题多种多样,有很多是我们线下无法复现的。上面举的只是最近一个问题分析的例子,而且代码逻辑在我们自己进程,我们可以很方便的去获取代码分析。还有很多情况代码逻辑是在系统的其他进程的,比如也是最近遇到的,这就需要去分析相关机器system_server的代码了,hook方式也多种多样,我们也需要从稳定性以及性能上适当选择。后面章节再和大家一起分享。