android 稳定性问题分析20211108

本文详细分析了Android稳定性问题,包括Java Exception (JE)的Checked和UnChecked Exception,ANR的类型、避免措施和分析方法,Native Exception (NE)的tombstone分析,以及Kernel Errors (KE)的处理和调试。此外,还介绍了Watchdog Timers (WDT)在系统稳定性中的作用。通过对各种异常的深入理解,有助于提升Android应用的健壮性和用户体验。
摘要由CSDN通过智能技术生成

稳定性问题分析20211108

1. JE 问题分析

Java Exception的分析方法相对要简单很多,java堆栈会保留出错的调用栈,能精确到代码指定的行号。如果问题容易复现,可以直接用logcat命令复现并保存日志。如果是已经发生的低概率问题,机器现场还在的话,可以通过导出data/system/dropbox目录下的日志文件。通常是data_app_crash、system_app_crash、system_server_crash开头,以txt为后缀。通过分析日志堆栈可以快速定位到出错的代码。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ix6H1rt0-1636330330493)(C:\Users\20247969\AppData\Roaming\Typora\typora-user-images\image-20211101104436301.png)]

Java的异常可以分为两类:Checked Exception和UnChecked Exception。所有RuntimeException类及其子类的实例被称为Runt ime异常,即UnChecked Exception,不是RuntimeException类及其子类的异常实例则被称为Checked Exception。

1.1 Checked Exception

Checked异常又称为编译时异常,即在编译阶段被处理的异常。编译器会强制程序处理所有的Checked异常,也就是用try…catch显式的捕获并处理,因为Java认为这类异常都是可以被处理(修复)的。在Java API文档中,方法说明时,都会添加是否throw某个exception,这个exception就是Checked异常。如果没有try…catch这个异常,则编译出错,错误提示类似于“Unhandled

exception type xxxxx”。

该类异常捕获的流程是:

  • 执行try块中的代码出现异常,系统会自动生成一个异常对象,并将该异常对象提交给Java运行环境,这个就是异常抛出(throw)阶段;
  • 当Java运行环境收到异常对象时,会寻找最近的能够处理该异常对象的catch块,找到之后把该异常对象交给catch块处理,这个就是异常捕获(catch)阶段。

Checked异常一般是不引起Android App Crash的,注意是“一般”,这里之所以介绍Checked异常,有两个原因:

  • 形成系统的了解,更好地对比理解UnCheckedException;
  • 对于一些Checked Exception,虽然我们在程序里面已经捕获并处理了,但是如果能同时将该异常收集并发送到后台,将有助于提升App的健壮性。比如修改代码逻辑回避该异常,或者捕获后采用更好的方法去处理该异常。至于应该收集哪些Checked Exception,则取决于App的业务逻辑和开发者的经验了。

1.2 UnChecked Exception

UnChecked异常又称为运行时异常,即Runtime-Exception,最常见的莫过于NullPointerException。UnChecked异常发生时,由于没有相应的try…catch处理该异常对象,所以Java运行环境将会终止,程序将退出,也就是我们所说的Crash。当然,你可能会说,那我们把这些异常也try…catch住不就行了。理论上确实是可以的,但有两点会导致这种方案不可行:

  • 无法将所有的代码都加上try…catch,这样对代码的效率和可读性将是毁灭性的;

  • UnChecked异常通常都是较为严重的异常,或者说已经破坏了运行环境的。比如内存地址,即使我们try…catch住了,也不能明确知道如何处理该异常,才能保证程序接下来的运行是正确的。

没有try…catch住的异常,即Uncaught异常,都会导致应用程序崩溃。那么面对崩溃,我们是否可以做些什么呢?比如程序退出前,弹出个性化对话框,而不是默认的强制关闭对话框,或者弹出一个提示框安慰一下用户,甚至重启应用程序等。

其实Java提供了一个接口给我们,可以完成这些,这就是UncaughtExceptionHandler,该接口含有一个纯虚函数:public abstract void uncaughtException (Thread thread, Throwableex)。

Uncaught异常发生时会终止线程,此时,系统便会通知UncaughtExceptionHandler,告诉它被终止的线程以及对应的异常,然后便会调用uncaughtException函数。如果该handler没有被显式设置,则会调用对应线程组的默认handler。如果我们要捕获该异常,必须实现我们自己的handler,并通过以下函数进行设置:
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler)
实现自定义的handler,只需要继承UncaughtExceptionHandler该接口,并实现uncaughtException方法即可。

static class MyCrashHandler implements UncaughtExceptionHandler{
     
    @Override  
    public void uncaughtException(Thread thread, final Throwable throwable) {
     
        // Deal this exception
    }
}

在任何线程中,都可以通过setDefaultUncaughtExceptionHandler来设置handler,但在Android应用程序中,全局的Application和Activity、Service都同属于UI主线程,线程名称默认为“main”。所以,在Application中应该为UI主线程添加UncaughtExceptionHandler,这样整个程序中的Activity、Service中出现的UncaughtException事件都可以被处理。

参考文档:

  1. Android内存异常机制(用户空间)_JE - 内核工匠 - 博客园 (cnblogs.com)
  2. Android内存异常机制(用户空间)_NE - 内核工匠 - 博客园 (cnblogs.com)

2. ANR 问题分析

2.1 ANR 类型

根据发生ANR的原因和超时时间分类,大致有四种ANR:

anr_timeout

Provider:

provider_anr

Input:

input_anr

Broadcast:

broadcast_anr

broadcast_anr_2

Service:

service_anr

2.2 常见的ANR发生场景

  1. 主线程频繁进行IO操作,比如读写文件或者数据库;

  2. 硬件操作如进行调用照相机或者录音等操作;

  3. 多线程操作的死锁,导致主线程等待超时;

  4. 主线程操作调用join()方法、sleep()方法或者wait()方法;

  5. 耗时动画/耗资源行为导致CPU负载过重

  6. system server中发生WatchDog ANR;

  7. service binder的数量达到上限

2.3 流程总结

前台服务,超时为SERVICE_TIMEOUT = 20s;
后台服务,超时为SERVICE_BACKGROUND_TIMEOUT = 200s
前台广播,超时为BROADCAST_FG_TIMEOUT = 10s;
后台广播,超时为BROADCAST_BG_TIMEOUT = 60s;
应用页面相应为5s;
Service, Broadcast, Input发生ANR之后,最终都会调用AMS.appNotResponding方法来处理超时,记录日志、弹出ANR的dialog等操作。

2.4 避免措施

在Activity和Service的生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。建议使用Handler+Message的方式做一些耗时的创建操作。
避免在主线程上进行复杂耗时的操作。可以把耗时操作放在线程中去执行。
避免在BroadcastReceiver里做耗时的操作。如果要进行复杂的耗时操作,可以在onReceive()方法中启动一个Service来处理。
编写代码一定要仔细,避免出现同步/死锁或者错误处理不恰当等情况。

2.5 ANR 分析方法

1. Log

刚才产生ANR后,看下Log:

img

ANR Log.png

可以看到logcat清晰地记录了ANR发生的时间,以及线程的tid和一句话概括原因:`WaitingInMainSignalCatcherLoop`,大概意思为主线程等待异常。
最后一句`The application may be doing too much work on its main thread.`告知可能在主线程做了太多的工作。
2. traces.txt

刚才的log有第二句Wrote stack traces to '/data/anr/traces.txt',说明ANR异常已经输出到traces.txt文件,使用adb命令把这个文件从手机里导出来:

  1. cd到`adb.exe`所在的目录,也就是**Android SDK**的`platform-tools`目录,例如:
cd D:\Android
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值