1 Star 0 Fork 3

WangCrystal / ANR-WatchDog-ohos

forked from ISRC_OHOS / ANR-WatchDog-ohos 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 10.84 KB
一键复制 编辑 原始数据 按行查看 历史
蜃啸 提交于 2021-03-17 10:15 . update README.md.

Maven Central MIT License GitHub issues Donate

ANR-WatchDog-ohos

一个简单的监测程序,可检测到鸿蒙系统的 ANR(Application Not Response-应用程序无响应)错误并引发有意义的异常

  • 项目名称:ANR-WatchDog-ohos
  • 所属系列:鸿蒙的第三方组件适配移植
  • 功能:可检测到鸿蒙系统的ANR错误并引发有意义的异常
  • 项目移植状态:全部完成
  • 调用差异:无
  • 项目作者和维护人:陈丛笑
  • 联系方式:isrc_hm@iscas.ac.cn
  • 原项目Doc地址:https://github.com/SalomonBrys/ANR-WatchDog

目录

组件的意义

目前,ohos应用程序无法捕获和报告ANR错误。而调查ANR的唯一方法是提取文件/data/anr/traces.txt,不如选择我们自己的错误跟踪服务有效。

组件的功能

该组件设置了一个“watch dog”计时器,该计时器将检测UI线程何时停止响应。当监测到UI线程停止相应时,该组件会抛出一个具有堆栈轨迹的错误。

是否能和崩溃报告期一起使用

可以,由于这会引发错误,因此崩溃处理程序可以拦截该错误并按照所需的方式对其进行处理。

它是如何工作的

看门狗是一个简单的线程,它在循环中执行以下操作:

  1. 安排可运行对象尽快在UI线程上运行。
  2. 等待5秒钟。(默认值为5秒,但可以配置)。
  3. 查看可运行对象是否已运行。如果有,请返回1。
  4. 如果该可运行对象尚未运行,这意味着该UI线程已被阻塞至少5秒钟,则它将对所有正在运行的线程堆栈跟踪引发错误。

用法

安装

使用Devceo studio

  1. app/build.gradle 中, 添加:

    compile project(path: ':anr_watchdog')
  2. 在 AbilityPackage类的 onCreate中, 添加:

    new ANRWatchDog().start();

阅读异常报告

ANRError 堆栈跟踪有点特殊, 它在你的应用程序运行的所有线程的堆栈跟踪。因此,在报告中, 每一个 caused by 部分都不是导致先例异常的原因, 而是不同线程的堆栈跟踪.

这是一个死锁示例:

鸿蒙手机的死锁示例:


2021-03-16 10:28:22.978 12535-12801/com.huawei.mytestapp E/AndroidRuntime: FATAL EXCEPTION: |ANR-WatchDog|
    Process: com.huawei.mytestapp, PID: 12535
    com.github.anrwatchdog.ANRError: Application Not Responding for at least 4000 ms.
    Caused by: com.github.anrwatchdog.ANRError$$$_Thread: main (state = BLOCKED)
        at com.huawei.mytestapp.MainAbility.lock(MainAbility.java:83)
        at com.huawei.mytestapp.MainAbility.access$500(MainAbility.java:15)
        at com.huawei.mytestapp.MainAbility$8.onClick(MainAbility.java:170)
    Caused by: com.github.anrwatchdog.ANRError$$$_Thread: AppEyeUiProbeThread (state = RUNNABLE)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:363)
        at android.os.Looper.loop(Looper.java:176)
        at android.os.HandlerThread.run(HandlerThread.java:67)
    Caused by: com.github.anrwatchdog.ANRError$$$_Thread: FinalizerDaemon (state = WAITING)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:442)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211)
        at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:271)

从报告中,我们可以看到每一个线程的详细报告,根据Caused by 后面的堆栈追踪可以查看到死锁的原因

线程休眠报告:

  Caused by: com.github.anrwatchdog.ANRError$$$_Thread: AppEyeUiProbeThread (state = RUNNABLE)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:363)
        at android.os.Looper.loop(Looper.java:176)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: com.github.anrwatchdog.ANRError$$$_Thread: FinalizerDaemon (state = WAITING)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:442)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211)
        at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:271)
 Caused by: com.github.anrwatchdog.ANRError$$$_Thread: AppEyeUiProbeThread (state = RUNNABLE)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:363)
        at android.os.Looper.loop(Looper.java:176)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: com.github.anrwatchdog.ANRError$$$_Thread: FinalizerDaemon (state = WAITING)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:442)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211)

无限循环报告:

2021-03-16 14:48:45.471 29817-30409/com.huawei.mytestapp E/AndroidRuntime: FATAL EXCEPTION: |ANR-WatchDog|
    Process: com.huawei.mytestapp, PID: 29817
    com.github.anrwatchdog.ANRError: Application Not Responding for at least 4000 ms.
    Caused by: com.github.anrwatchdog.ANRError$$$_Thread: main (state = RUNNABLE)
        at com.huawei.mytestapp.MainAbility.InfiniteLoop(MainAbility.java:33)
        at com.huawei.mytestapp.MainAbility.access$400(MainAbility.java:15)
        at com.huawei.mytestapp.MainAbility$7.onClick(MainAbility.java:164)
     Caused by: com.github.anrwatchdog.ANRError$$$_Thread: AppEyeUiProbeThread (state = RUNNABLE)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:363)
        at android.os.Looper.loop(Looper.java:176)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: com.github.anrwatchdog.ANRError$$$_Thread: FinalizerDaemon (state = WAITING)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:442)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211)
        at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:271)
        at java.lang.Daemons$Daemon.run(Daemons.java:137)
        at java.lang.Thread.run(Thread.java:929)
     Caused by: com.github.anrwatchdog.ANRError$$$_Thread: FinalizerWatchdogDaemon (state = TIMED_WAITING)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:443)
        at java.lang.Thread.sleep(Thread.java:359)

配置

超时

如何设置其他超时时间: ( 默认值为5000):

if (BuildConfig.DEBUG == false) {
  new ANRWatchDog(10000 /*timeout*/).start();
}

调试

默认情况下,如果在进行debug或应用程序正在等待debug,watch-dog将忽略ANR。这是因为它将执行暂停和断点检测为ANR。要禁用此功能并在debug的情况下抛出ANRError,可以添加setIgnoreDebugger(true)

new ANRWatchDog().setIgnoreDebugger(true).start();

ANR回调

如果您不想在检测到ANR时不使应用程序崩溃,则可以启用回调:

new ANRWatchDog().setANRListener(new ANRWatchDog.ANRListener() {
    @Override
    public void onAppNotResponding(ANRError error) {
        // Handle the error. For example, log it to HockeyApp:
        ExceptionHandler.saveException(error, new CrashManager());
    }
}).start();

在生产环境中交付应用程序时,这一点非常重要。 当由最终用户掌握时,最好不要在5秒后崩溃,而只需将ANR报告给您使用的任何报告系统即可。也许,再过几秒钟后,该应用程序将“解冻”。

Filtering reports

如果您希望仅在ANRError中报告自己的线程,而不是在所有线程(包括系统线程,例如该FinalizerDaemon线程)中报告所有线程,则可以设置前缀:仅报告名称以该前缀开头的线程。

new ANRWatchDog().setReportThreadNamePrefix("APP:").start();

然后,在启动线程时,请不要忘记将其名称设置为以该前缀开头的名称(如果要报告该名称):

public class MyAmazingThread extends Thread {
    @Override
    public void run() {
        setName("APP: Amazing!");
        /* ... do amazing things ... */
    }
}

如果只想拥有主线程堆栈跟踪而没有其他所有线程,则可以:

new ANRWatchDog().setReportMainThreadOnly().start();

ANR Interceptor

有时,您想知道应用程序已经冻结了一段时间,但是还没有报告ANR错误。您可以定义在报告错误之前将被调用的拦截器。拦截器的作用是定义在给定的冻结持续时间下是否应提高或推迟ANR错误。

new ANRWatchDog(2000).setANRInterceptor(new ANRWatchDog.ANRInterceptor() {
    @Override
    public long intercept(long duration) {
        long ret = 5000 - duration;
        if (ret > 0) {
            Log.w(TAG, "Intercepted ANR that is too short (" + duration + " ms), postponing for " + ret + " ms.");
        }
        return ret;
    }
})

在此示例中,ANRWatchDog以2000毫秒的超时开始,但是拦截器将推迟错误,直到达到至少5000毫秒的冻结为止。

Watchdog thread

ANRWatchDog是一个线程,因此您可以随时中断它。

如果您正在使用Android的多进程功能进行编程(例如在新进程中启动活动),请记住,每个进程将需要ANRWatchDog线程。

Donate

原作者github地址:https://github.com/SalomonBrys/ANR-WatchDog#donate

1
https://gitee.com/crystal08/anr-watch-dog-ohos.git
git@gitee.com:crystal08/anr-watch-dog-ohos.git
crystal08
anr-watch-dog-ohos
ANR-WatchDog-ohos
master

搜索帮助