Android System ANR caused SWT restart issue

1、用户直观看到的现象是System先ANR。

2、ANR之后系统重启。

通过初步分析、深入分析()我们清楚的知道了问题发生的原因:

考虑AudioService中复杂的逻辑,所以要以最小风险的改动来修复这个问题,因此这里给出的方案没有进行太大的改动,而且比较显而易见的是全部加synchronized关键字的这些出问题的代码,AOSP还有一定的优化空间。

最终针对以上问题的根本原因,我们给出以下解决方案:

在需要同步的临界代码区使用类的全局锁来代替每个实例自己的锁,从而保证多个Thread在相互穿插调用时不会发生死锁。

以上是发生死锁时锁对应的backtrace调用栈以及相应的代码,通过红线圈住部分我们可以看到发生问题时的关键调用关系和状态。

通过查看如上对应代码,发现这个方法是个synchronized的,而且方法中在满足条件时还会遍历并调用同类型但是不同实例对象的synchronized方法,因此这里被block就需要满足一个条件:调用的同类型不同实例对象的synchronized方法无法进入,即在其他thread中已经进入了这个synchronized方法。

根据这个线索继续查看SystemServer中与AudioService相关的thread的调用栈,找到Binder_2这个thread,具体的backtrace如下:

通过backtrace和对应代码我们发现Binder_2这个thread也block在了一个AudioService内部的synchronized函数中,同样的这个函数中在满足一定的条件时也会调用同类型不同实例的synchronized方法。

经过初步分析我们定位到了第一个问题点,即两个不同的Thread都block在了同一个类型的synchronized方法上,同时也产生了1个问题,接下来我们继续深入分析以期能到找到答案和问题的根本原因。

通过进一步分析和查看代码发现,由于两个Thread所执行的都是synchronized方法,如果它们由于调度和执行原因而产生了相互依赖的关系,那么就会发生同时block的现象而死锁,由于backtrace只能看到调用关系,不能知道运行时各个对象实例的状态,所以我们根据backtrace模拟systemserver中当前这两个thread的问题状态,结果完全匹配当前的问题现象,具体的模拟代码如下:

先自定义一个Thread类,接收两个TestSync类的实例并在run里面调用实例1的同步方法,同时将实例2传递过去。

接着定义一个TestSync类,并定义两个synchronized的成员函数,然后在每个函数开始的地方都先sleep 10ms,以满足进程调度切换的状态。

以上代码的执行流程大致如下:

1、新建t1,t2两个TestSync类的实例以及CThread类的实例ct1并将t1和t2传递过去

2、启动ct1这个thread

3、无论是ct1的代码流先被调度到执行还是UI主线程继续执行都会进入t1或者t2的synchronized方法。

4、这里假设ct1在start之后立马被调度到并执行了t1的synchronized方法,然后sleep 10ms,此时再次发生调度。

5、UI主线程被再次调度到,然后执行t2的synchronized方法,sleep10ms,再次调度到其它thread。

不要气馁于那前方的阴影,那只是因为我背后光芒万丈

Android System ANR caused SWT restart issue

相关文章:

你感兴趣的文章:

标签云: