Android System ANR caused SWT restart issue

一、问题现象

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

2、ANR之后系统重启。

测试方法:

在录音的界面不停的滑动音量进度条,同时座机给测试机打电话,电话没有接通,只见界面冻结,弹出ANR,接着系统重启。

Platform:MT6732

Android版本:4.4.4KK

BuildType:user

系统软件版本:SWA3A+UMA0

系统RAM:1GB

问题概率:≈2%

参考机行为:

1、低概率问题,暂无参考机行为。

二、解决方案

通过初步分析、深入分析(具体分析过程、关键代码和log在下面会附上)我们清楚的知道了问题发生的原因:

1、SystemServer进程中的AudioService相关的setindex和getindex等方法会在多个Thread中进行,而这些方法都是以synchronized关键字声明的,即这些方法会以类的每个实例中的lock进行多线程同步。

2、这些synchronized的方法中存在穿插调用其他同类型实例的synchronized方法的行为。

3、完全将方法用synchronized关键字声明是一个比较懒的做法,这样会导致同步锁的粒度太大,没有细化临界区,在多线程高并发的状态下会降低代码流执行的吞吐量,而且会加大在穿插调用过程中彼此依赖发生死锁碰撞的可能。

在当前代码的执行状态下就有一定概率(很小,依赖于具体的进程调度时机)出现因为调度原因而先调度到了Thread1并执行了对象A的同步方法,然后调度到了Thread2并执行对象B的同步方法,在对象B的同步方法中想要去调用对象A的同步方法,此时发生阻塞,接着又调度到了Thread1,继续执行对象A的同步方法中的代码,然后又去调用对象B的同步方法,因为在Thread2中已经持有了对象B的lock,所以此时Thread1也发生了阻塞,当前的状态就是Thread1和Thread2相互等待对方释放锁而无限期等待,各种的代码流得不到执行而死锁。

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

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

1、更换同步锁的类型

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

2、方案相关的具体代码和backtrace

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

3、最终方案的代码修改

三、问题初步分析

以ALTO4.5TMO出问题时候的一份典型backtrace和log为例,发现出问题时SystemServer的主线程block在了一个AudioService内部的一个函数上,从而引发ANR和SWT重启,具体backtrace如下:

为什么会block?通过查看如上对应代码,发现这个方法是个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个问题,接下来我们继续深入分析以期能到找到答案和问题的根本原因。

1、两个Thread为什么会同时block?

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

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

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

最后在activity的onResume方法中进行测试,结果测试的activity就会ANR,为什么会ANR?

原理和上面systemServer ANR并SWT重启一样,这里activity的UI主线程和新建的ct1线程发生了死锁。

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

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方法,sleep 10ms,再次调度到其它thread。

6、等到ct1的10ms sleep先结束之后再次调度到ct1,然后执行t2的synchronized方法,这里会发生阻塞,因为在UI主线程中已经进入到了t2的synchronized方法,即t2实例自己的lock已经处于锁定状态,然后调度到其他thread。

7、等到UI主线程的10ms sleep结束之后再次调度到UI主线程,然后执行t1的synchronized的方法,这里同样会发生阻塞,因为在ct1中已经进入t1的synchronized方法,t1实例自己的lock已经处于锁定状态,然后调度到其他thread。

8、此时ct1和UI主线程已经产生相互依赖而死锁。

将上面的代码中使用的synchronized关键字更改为同步类的全局锁,问题解决,activity不会再发生ANR,具体更改如下:

五、解决方案潜在的影响

由于使用类的全局锁,而且没有细分临界区,所以在高并发的情况下可能会略微降低代码执行流的吞吐量,但是这个影响对SystemServer中AudioService的setindex和getindex等方法可以忽略,因为这几个方法都非常轻量级并且并发量不会达到太高的量级。

Analyzed by vincent.song from SWD2 Framework team.

[email protected]

201506241646

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-27 14:04:38

Android System ANR caused SWT restart issue的相关文章

Android Stability test occured SWT restart issue

一.问题现象 1.System先ANR. 2.ANR之后系统重启. 测试方法: Stability test. Platform:MT6732 Android版本:4.4.4KK BuildType:user 系统软件版本:D17+ZX 系统RAM:1GB 问题概率:暂未统计,截止到目前仅此1次 参考机行为: 1.低概率问题,暂无参考机行为. 二.解决方案 通过初步分析.深入分析(具体分析过程.关键代码和log在下面会附上)我们清楚的知道了问题发生的原因: 1.SystemServer进程的主线

android 自定义View Caused by: java.lang.ClassNotFoundException: Didn't find class

在android studio中, 自定义View 时,出现 Caused by: java.lang.ClassNotFoundException: Didn't find class 在查看包名和类名都没有错误的情况,一个可能的原因是,在添加包名时,粗心导致把包类型定义为androidTest下了 如下图所示: 本人做为android  新手,英语水平一般,只是如实记录自己所犯的错,高手不喜勿吐. android 自定义View Caused by: java.lang.ClassNotFo

The behavior of App killed or restored by Android System or by users

What's the behavior of App killed or restored by Android System or by users? First, user kills the app by swiping out the screen The DEMO process is killed and activity stack is cleared. And the system will relaunch the DEMO process automatically.  W

Android System分区大小异常

平台:Freescale / Android 4.2.2 问题描述: 用 df 命令,看到/system分区大小275M. 用 busybox fdisk -l /dev/block/mmcblk0p5,看到 536M. Freescale的刷机工具是Mfgtool,分区的动作在mksdcard-android.sh里面完成. SYSTEM_ROM_SIZE=512 dd if=/dev/zero of=${node} bs=1024 count=1 sfdisk --force -uM ${n

Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)

这个错误在高版本的系统常见,为了更好的用户体验,在低版本的系统能正常运行,在高版本(比如7.0)很容易出问题. 原因: 在主线程中进行了网络操作. 解决: 检查代码哪里使用了网络操作,开启子线程.

Android System Property 解析

一 System Property 今天在折腾HDMI 显示这块的时候,为Setting提供接口时候,遇到很多跟Android系统属性相关的问题.因此,顺便分析和总结一些. android的代码中大量存在:SystemProperties.set()/SystemProperties.get():通过这两个接口可以对系统的属性进行读取/设置, 顾名思义系统属性,肯定对整个系统全局共享.通常程序的执行以进程为单位各自相互独立,如何实现全局共享呢? System Properties是怎么一回事,又

安卓系统广播暴露设备信息-Android System Broadcasts Expose Device Information

Android device details are being exposed to running applications via Wi-Fi broadcasts in the mobile operating system, Nightwatch Cybersecurity has discovered. The exposed information includes the WiFi network name, BSSID, local IP addresses, DNS serv

Forms Android System Download

1 不用自己写下载文件的功能,直接调用系统下载服务 2 forms 接口 3 4 using System; 5 using System.Collections; 6 using System.Collections.Generic; 7 8 namespace 9 { 10 public interface ISystemDownloadFile 11 { 12 //下载文件 13 void DownloadThread (string strUrl,string str1); 14 } 1

android system service 系统服务列表

1 public abstract Object getSystemService(String name); 2 3 /** 4 * Use with {@link #getSystemService} to retrieve a 5 * {@link android.os.PowerManager} for controlling power management, 6 * including "wake locks," which let you keep the device