一、问题现象

1、System先ANR。

2、ANR之后系统重启。

测试方法:

Stability test。

Platform:MT6732

Android版本:4.4.4KK

BuildType:user

系统软件版本:D17+ZX

系统RAM:1GB

问题概率:暂未统计,截止到目前仅此1次

参考机行为:

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

二、解决方案

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

1、SystemServer进程的主线程访问media audio的接口进行跨进程调用时被block。

2、Media audio的接口最终会调用到mediaserver进程中。

3、Mediaserver进程中产生了死锁。

4、最终导致systemServer先ANR然后被SWT重启。

在当前代码的执行状态下有一定概率(很小,必须满足sp指针获取到之后并成为最后一个强引用的条件)出现递归调用一个加了默认为NORMAL类型的mutex autolock的方法而产生死锁。

考虑mediaserver中复杂的逻辑,所以要以最小风险的改动来修复这个问题,因此这里给出的方案没有进行太大的改动。

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

1、延长sp指针的生命周期,使其生命周期长于mutex autolock

在可能递归调用的加了mutex autolock的函数中,使用vector容器延长sp指针的生命周期,使其在mutex autolock生命周期结束并unlock之后再析构sp指针,此时如果再发生递归调用则不会死锁。

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

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

3、最终方案的代码修改

三、问题初步分析

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

为什么会block?通过查看如上对应代码,发现setParameter这个方法会通过audioflinger的代理对象跨进程调用到mediaserver中的audioflinger的setParameter方法,因此接下来就要mediaserver进程是否工作的正常。

根据这个线索继续查看mediaserver中各个thread的调用栈,发现几乎所有的Binder thread都被block了,这也就解释了为什么SystemServer的调用得不到处理而发生ANR以及SWT重启。其中绝大多数Binder thread被block的backtrace如下:

由于mediaserver是native的C/C++代码,所以需要用address2line这个工具将对应的PC指针的地址在symbols中找到对应的源码来分析,具体过程不再赘述,大家可以找一些专门的文章来简单学习一下,经过这个过程之后得到的对应的源码如下:

从以上代码中我们可以看到getplayertype的实现中第一句代码就是要进行sLock.lock(),如果lock不成功则会等待,因此接下来继续看其他thread中谁占用了这个lock。通过查看其他thread的backtrace,发现Binder_5这个thread占用了sLock,但是它也被block在另外一个mutex lock上,具体的backtrace和代码如下:

顺着这个线索我们继续看mediaserver进程中的其他thread,看谁占用了ALooperRoster的mLock,最终找到了rtsp thread在调用ALooperRoster的unregisterStaleHandlers函数时占用了mLock这个锁,但同时它自己又间接调用了unregisterStaleHandlers,最终也被block在了这个mLock上,具体的backtrace和代码如下:

四、深入分析问题

经过初步分析我们定位到了第一个问题点,即rtsp thread block在了它已经lock的一个mLock上,同时也产生了2个问题,接下来我们继续深入分析以期能到找到答案和问题的根本原因。

1、为什么会间接递归调用ALooperRoster::unregisterStaleHandlers方法?

2、为什么rtsp thread自己会block在mLock上?

通过进一步分析和查看代码发现,rstp thread之所以会间接递归调用ALooperRoster::unregisterStaleHandlers方法,是因为sp<ALooper> looper = info.mLooper.promote();这句代码中的looper强指针sp在出现问题的场景下,出了一次for循环的作用域时会成为最后一个持有ALooper对象的sp而在析构时发生ALooper对象的释放,从而引发ALooper对象的析构,在ALooper对象析构时就会再次调用ALooperRoster::unregisterStaleHandlers方法而产生间接递归调用。关于Android中native层的C++的智能指针、sp、wp这里简单介绍一下,大概原理就是利用sp和wp指针对象的构造函数和析构函数来对所指向的对象进行引用计数的加减,指针所指向的对象必须要继承自class RefBase,根据对象的生命周期标志在强引用计数或弱引用计数为0时来进行对象的释放:

 

生命周期默认是STRONG,即当对象的强引用计数为0时就释放对象,关键代码如下:

回答完第一个问题,我们接下来看第二个问题,在回答上面第二个问题之前我们需要先简单说一下Autolock这个类,这个类是在system/core/include/utils/Mutex.h中Mutex类内部定义的,具体代码如下:

这个类的原理简单理解就是在构造函数中lock,析构函数中unlock,这正好利用了C++的特性,所以进入Autolock对象的作用域就会lock,出了作用域就会unlock,从而实现自动的Mutex。而Mutex类是pthread_mutex_t的一个封装,而pthread_mutex_t默认是NORMAL类型的,即不可递归重入的:

而ALooperRoster::unregisterStaleHandlers方法就是使用的Mutex::Autolock autoLock(mLock)进行同步的,在没有出Autolock的作用域时间接递归调用,这时mLock这个Mutex是lock着的,由于Mutex默认的这个不可递归重入的属性最终就导致了当前这个死锁的现象,到这这也就回答了为什么rtsp thread自己为什么会block在mLock上。

五、解决方案潜在的影响

由于仅仅是稍微延迟了sp指针的生命周期,在出了函数作用域之后就会马上释放,所以当前的方案没有其他已知的影响,最后再次看一下修改的代码和注释:

Analyzed by vincent.song from SWD2 Framework team.

vincent.song@tcl.com

201506242052

Android Stability test occured SWT restart issue相关推荐

  1. android日志管理最佳策略,Android Stability - tombstone日志

    Tombstone日志的生成 Android默认是不会抓取coredump文件的,AOSP在进程发生内存访问异常的时候一般会在 data/tombstones/ 下面生成"tombstone ...

  2. Firefox Nightly 让 Android 机用上任意桌面端附加组件 | Expanded extension support in Firefox for Android Nightly

    Firefox Nightly 让 Android 机用上任意桌面端附加组件 官方文档:https://blog.mozilla.org/addons/2020/09/29/expanded-exte ...

  3. ubuntu无法识别android手机

    Ubuntu 下Android adb devices显示no permission Setting up a Device for Development With an Android-power ...

  4. Cocos2D-X Tutorial for iOS and Android: Getting Started

    Cocos2D is an amazing and easy to use framework, but since it's written in Objective-C you can only ...

  5. 三星android 驱动,Samsung Android Driver for Windows [Free Download]

    Having an issue with your Samsung Android driver in your computer? Don't worry! You can fix the Sams ...

  6. Android Studio 3.5 Canary 12 发布

    开发四年只会写业务代码,分布式高并发都不会还做程序员? >>>   Android Studio 3.5 Canary 12  发布了,Canary 和 Dev 可用. 此版本包括针 ...

  7. Android studio中出现Couldn't resolve resource @dimen/...

    问题出现: Path.isConvex is not supported. Rendering problems .. Couldn't resolve resource @dimen/...等等 资 ...

  8. 使用LeakTracer检测android NDK C/C++代码中的memory leak

    Memory issue是C/C++开发中比较常遇到,经常带给人比较大困扰,debug起来又常常让人无从下手的一类问题,memory issue主要又分为memory leak,野指针,及其它非法访问 ...

  9. 【我的Android进阶之旅】Android自定义Lint实践

    背景 2017年8月份的时候,我在公司开始推广Lint.FindBugs等静态代码检测工具.然后发现系统自带的Lint检测的Issue不满足我们团队内部的特定需求,因此去自定义了部分Lint规则.这个 ...

最新文章

  1. “抽象类”的定义及其与“普通类”的区别
  2. 通过@Enable*注解触发Spring Boot配置
  3. 【iOS】NSNumberFormatter
  4. 通过什么来衡量C# Socket服务的效能
  5. python嗅探网页视频_网络嗅探python
  6. oracle存储过程 --1
  7. 超详攻略!Databricks 数据洞察 - 企业级全托管 Spark 大数据分析平台及案例分析
  8. 测控技术与仪器专业c语言教学视频,测控技术与仪器要学哪些基础和专业课程...
  9. 基于Surface的视频编解码与OpenGL ES渲染
  10. 从食品质检员到代码工程师,大哥你就这样跳槽进了阿里巴巴?
  11. 变量的引用类型和非引用类型的区别
  12. 最近两个星期,机器经常卡死,难道是内存用光了?
  13. python从外部传入参数_Python学习杂记_8_从程序外部传参的办法sys.argv
  14. EPLAN p8 安装失败解决办法
  15. loadrunner11的安装
  16. 微信公众号服务号如何在线给粉丝发送模板消息
  17. 基于CNN-LSTM的手写数字识别与应用实现(附tensorflow代码讲解)
  18. 最美证件照工作室需要买什么东西
  19. mysql可以存储.wav文件吗_手机迅雷下载的视频文件存储路径位置、iPad可以下载迅雷...
  20. MC9S12XEP100的SPI模块(S12SPIV5)

热门文章

  1. SpringBoot(二)——JPA
  2. MySQL创建相同表和数据命令
  3. vue.js学习系列-第二篇
  4. 2.Spring初学
  5. rsync同步服务实验讲解
  6. zzzp0371 属于本人
  7. 帝国cms底部代码哪里改?要修改版权和统计代码
  8. mysql入门之事务处理
  9. Qt Linguist 界面语言翻译
  10. 配置hibernate手动配置