Crash排查系列第六篇|记一次厂商兼容问题处理

837 阅读4分钟

crash问题千奇百怪,涉及到厂商相关的代码我们该如何去分析。

  • 如何通过现有crash信息分析尝试复现crash?
  • 如何快速获取到厂商crash相关代码?
  • 如何通过反编译和trace手段快速分析代码逻辑?
  • 如何利用hook手段做crash保护?

下面通过一个案例和大家分享一下我这边的排查定位保护过程。

image.png

分析解决

  1. 从crash大盘中找到该crash出现频率较多的系统版本和设备型号。

  2. 从crash的url分布发现相关页top1页面,结合分析工具路径我们尝试复现该堆栈。

  3. 复现堆栈后不一定crash,但是我们可以通过打印堆栈dex location的方式找到代码所在磁盘位置并拉取代码。 线下class location获取方式

    1. 线下获取class dex location方式 ,这点有在widget内存优化文章也有提到。 找到gLogVerbosity这个全局属性后修改class_linker为true

image.png

image.png 线上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();

}
  1. 反编译代码 查看里面相关的文件 猜测功能,其实这边通过堆栈包名也能猜到 往这个方向测试

  2. 长按 触发智慧视觉识别功能复现 crash几乎必现,而出现页面经常要长按操作,这也是该页面容易出现的原因。系统设置页面关闭智慧视觉功能后不出现。

  3. 提交日志,反馈vivo,vivo这边确认问题后回复计划推送rom解决(vivo没有回复具体原因,猜测是h5游戏页面用的组件和智慧视觉的提取图片功能一起触发的问题)

  4. crash还在一直在上涨,半夜甚至还出现了告警,后来确认是因为凌晨活动重置,玩这个游戏的用户在一个峰值。虽然这个crash不到万分之一的设备crash率,一方面不知道vivo具体推送的rom时间,一方面玩游戏的闪退的体验确实不好受。为了提升用户体验还是要想办法去解决这个问题。

  5. 一开始是想通过PLT Hook hook 这个apk文件的打开 直接返回-1。本地机器验证了确实可以,但是有个问题这个apk路径不是固定的,每个手机上都有可能不一样,而且hook的范围也可能稍大了些,所有的io可能都要过一下这个逻辑。

  6. 接下来通过class load的日志和自制的trace打点工具结合perfetto分析代码逻辑

    1. 第一个图是1秒左右 主线程处理长按事件。
    2. 第二张图是binder线程去加载contentcatcher这个apk的代码和资源
    3. 第三张图的堆栈就是导致crash的堆栈。

image.png

image.png

image.png

  1. 分析了contentcatcher的加载流程后,我们就要想办法去打破这条链路。我这边是找了第二个过程作为突破口,这个过程代码不在contentcatcher.apk 通过class load日志可以发现在vivo的一个framwork jar下 ,同样的方式拉取代码分析

    1. 发现一个hook点 可以直接修改CONTENT_CATCHER_ID 不去加载功能。直接通过反射修改。

image.png

image.png

  1. 一轮灰度后发现还有crash上报,继续分析相关机型,发现新版本 framework有修改,无法通过修改CONTENT_CATCHER_ID解决,code判断的地方直接写死了。 重新找hook点。

    1. 反射修改sViewAnalyzerClzz让其找不到类。修改后发现是个hide 字段,所以这里要用双反射绕过。

image.png

  1. 配置中心下发开关hook,crash下降。 待vivo rom推送覆盖后再打开开关。
  2. 厂商相关的问题多种多样,有很多是我们线下无法复现的。上面举的只是最近一个问题分析的例子,而且代码逻辑在我们自己进程,我们可以很方便的去获取代码分析。还有很多情况代码逻辑是在系统的其他进程的,比如也是最近遇到的,这就需要去分析相关机器system_server的代码了,hook方式也多种多样,我们也需要从稳定性以及性能上适当选择。后面章节再和大家一起分享。