# ANR-WatchDog-ohos **Repository Path**: isrc_ohos/anr-watch-dog-ohos ## Basic Information - **Project Name**: ANR-WatchDog-ohos - **Description**: 一个简单的监测程序,可检测到鸿蒙系统的 ANR(Application Not Response-应用程序无响应)错误并引发有意义的异常 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 14 - **Forks**: 3 - **Created**: 2021-03-16 - **Last Updated**: 2025-05-20 ## Categories & Tags **Categories**: harmony **Tags**: HarmonyComponent ## README [![Maven Central](https://img.shields.io/maven-central/v/com.github.anrwatchdog/anrwatchdog.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.anrwatchdog%22) [![MIT License](https://img.shields.io/github/license/salomonbrys/ANR-WatchDog.svg)](https://github.com/SalomonBrys/ANR-WatchDog/blob/master/LICENSE) [![GitHub issues](https://img.shields.io/github/issues/SalomonBrys/ANR-WatchDog.svg)](https://github.com/SalomonBrys/ANR-WatchDog/issues) [![Donate](https://img.shields.io/badge/Backing-Donate-orange.svg)](https://donorbox.org/donation-salomonbrys/) ANR-WatchDog-ohos ============ 一个简单的监测程序,可检测到鸿蒙系统的 ANR(Application Not Response-应用程序无响应)错误并引发有意义的异常 - 项目名称:ANR-WatchDog-ohos - 所属系列:鸿蒙的第三方组件适配移植 - 功能:可检测到鸿蒙系统的ANR错误并引发有意义的异常 - 项目移植状态:全部完成 - 调用差异:无 - 开发版本:sdk5,DevEco Studio2.1 beta3 - 项目发起作者:陈丛笑 - 邮箱:isrc_hm@iscas.ac.cn - 原项目Doc地址:https://github.com/SalomonBrys/ANR-WatchDog 目录 ---- * [ANR-WatchDog](#anr-watchdog) * [目录](#目录) * [组件的意义](#组件的意义) * [组件的功能](#组件的功能) * [是否能和崩溃报告期一起使用](#是否能和崩溃报告期一起使用) * [它是如何工作的](#它是如何工作的) * [用法](#用法) * [安装](#安装) * [阅读异常报告](#阅读异常报告) * [设置配置](#配置) * [ANR最小挂起时间](#超时) * [调试](#调试) * [ANR回调](#ANR回调) * [报告过滤](#filtering-reports) * [线程](#watchdog-thread) * [捐助](#donate) 组件的意义 --------- 目前,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`中, 添加: ```java 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): ```java if (BuildConfig.DEBUG == false) { new ANRWatchDog(10000 /*timeout*/).start(); } ``` ### 调试 默认情况下,如果在进行debug或应用程序正在等待debug,watch-dog将忽略ANR。这是因为它将执行暂停和断点检测为ANR。要禁用此功能并在debug的情况下抛出ANRError,可以添加`setIgnoreDebugger(true)`: ```java new ANRWatchDog().setIgnoreDebugger(true).start(); ``` ### ANR回调 如果您不想在检测到ANR时不使应用程序崩溃,则可以启用回调: ```java 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`线程)中报告所有线程,则可以设置前缀:仅报告名称以该前缀开头的线程。 ```java new ANRWatchDog().setReportThreadNamePrefix("APP:").start(); ``` 然后,在启动线程时,请不要忘记将其名称设置为以该前缀开头的名称(如果要报告该名称): ```java public class MyAmazingThread extends Thread { @Override public void run() { setName("APP: Amazing!"); /* ... do amazing things ... */ } } ``` 如果只想拥有主线程堆栈跟踪而没有其他所有线程,则可以: ```java new ANRWatchDog().setReportMainThreadOnly().start(); ``` ### ANR Interceptor 有时,您想知道应用程序已经冻结了一段时间,但是还没有报告ANR错误。您可以定义在报告错误之前将被调用的拦截器。拦截器的作用是定义在给定的冻结持续时间下是否应提高或推迟ANR错误。 ```java 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