{"id":13604151,"url":"https://github.com/SalomonBrys/ANR-WatchDog","last_synced_at":"2025-04-11T23:31:47.921Z","repository":{"id":9728161,"uuid":"11686345","full_name":"SalomonBrys/ANR-WatchDog","owner":"SalomonBrys","description":"A simple watchdog that detects Android ANR (Application Not Responding) error and throws a meaningful exception","archived":false,"fork":false,"pushed_at":"2022-03-11T12:23:25.000Z","size":377,"stargazers_count":2917,"open_issues_count":13,"forks_count":408,"subscribers_count":103,"default_branch":"master","last_synced_at":"2025-04-06T08:07:49.821Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SalomonBrys.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-07-26T13:29:59.000Z","updated_at":"2025-04-03T08:47:11.000Z","dependencies_parsed_at":"2022-07-12T15:03:41.321Z","dependency_job_id":null,"html_url":"https://github.com/SalomonBrys/ANR-WatchDog","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SalomonBrys%2FANR-WatchDog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SalomonBrys%2FANR-WatchDog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SalomonBrys%2FANR-WatchDog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SalomonBrys%2FANR-WatchDog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SalomonBrys","download_url":"https://codeload.github.com/SalomonBrys/ANR-WatchDog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248495001,"owners_count":21113544,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T19:00:40.643Z","updated_at":"2025-04-11T23:31:47.651Z","avatar_url":"https://github.com/SalomonBrys.png","language":"Java","funding_links":[],"categories":["Libs","Performance","Java"],"sub_categories":["\u003cA NAME=\"Performance\"\u003e\u003c/A\u003ePerformance"],"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)\n[![MIT License](https://img.shields.io/github/license/salomonbrys/ANR-WatchDog.svg)](https://github.com/SalomonBrys/ANR-WatchDog/blob/master/LICENSE)\n[![GitHub issues](https://img.shields.io/github/issues/SalomonBrys/ANR-WatchDog.svg)](https://github.com/SalomonBrys/ANR-WatchDog/issues)\n[![Donate](https://img.shields.io/badge/Backing-Donate-orange.svg)](https://donorbox.org/donation-salomonbrys/)\n\n\nANR-WatchDog\n============\n\nA simple watchdog that detects Android ANRs (Application Not Responding).\n\n\nTable of contents\n-----------------\n\n  * [ANR-WatchDog](#anr-watchdog)\n    * [Table of contents](#table-of-contents)\n    * [Why it exists](#why-it-exists)\n    * [What it does](#what-it-does)\n    * [Can it work with crash reporters?](#can-it-work-with-crash-reporters)\n    * [How it works](#how-it-works)\n  * [Usage](#usage)\n    * [Install](#install)\n      * [With Gradle / Android Studio](#with-gradle--android-studio)\n      * [With Eclipse](#with-eclipse)\n    * [Reading the ANRError exception report](#reading-the-anrerror-exception-report)\n    * [Configuration](#configuration)\n      * [Timeout (minimum hanging time for an ANR)](#timeout-minimum-hanging-time-for-an-anr)\n      * [Debugger](#debugger)\n      * [On ANR callback](#on-anr-callback)\n      * [Filtering reports](#filtering-reports)\n      * [Watchdog thread](#watchdog-thread)\n  * [Donate](#donate)\n\n\nWhy it exists\n-------------\n\nThere is currently no way for an android application to catch and report ANR errors.  \nIf your application is not in the play store (either because you are still developing it or because you are distributing it differently), the only way to investigate an ANR is to pull the file /data/anr/traces.txt.  \nAdditionally, we found that using the Play Store was not as effective as being able to choose our own bug tracking service.\n\nThere is an [issue entry](https://code.google.com/p/android/issues/detail?id=35380) in the android bug tracker describing this lack, feel free to star it ;)\n\n\nWhat it does\n------------\n\nIt sets up a \"watchdog\" timer that will detect when the UI thread stops responding. When it does, it raises an error with all threads stack traces (main first).\n\n\nCan it work with crash reporters?\n---------------------------------\n\nYes! I'm glad you asked: That's the reason why it was developed in the first place!  \nAs this throws an error, a crash handler can intercept it and handle it the way it needs.\n\nKnown working crash reporters include:\n\n * [ACRA](https://github.com/ACRA/acra)\n * [Crashlytics](https://get.fabric.io/crashlytics) ([Only with `setReportMainThreadOnly()`](https://github.com/SalomonBrys/ANR-WatchDog/issues/29))\n * [HockeyApp](https://hockeyapp.net/)\n * [Bugsnag](https://www.bugsnag.com/)\n\nAnd there is no reason why it should not work with *[insert your favourite crash reporting system here]*.\n\n\nHow it works\n------------\n\nThe watchdog is a simple thread that does the following in a loop:\n\n1.  Schedules a runnable to be run on the UI thread as soon as possible.\n2.  Wait for 5 seconds. (5 seconds is the default, but it can be configured).\n3.  See if the runnable has been run. If it has, go back to 1.\n4.  If the runnable has not been run, which means that the UI thread has been blocked for at least 5 seconds, it raises an error with all running threads stack traces.\n\n\nUsage\n=====\n\nInstall\n-------\n\n### With Gradle / Android Studio\n\n1.  In the `app/build.gradle` file, add:\n\n    ```\n    implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'\n    ```\n\n2.  In your application class, in `onCreate`, add:\n\n    ```java\n    new ANRWatchDog().start();\n    ```\n\n\n### With Eclipse\n\n1. [Download the latest jar](https://search.maven.org/remote_content?g=com.github.anrwatchdog\u0026a=anrwatchdog\u0026v=LATEST)\n\n2. Put the jar in the `libs/` directory of your project\n\n\nReading the ANRError exception report\n-------------------------------------\n\nThe `ANRError` stack trace is a bit particular, it has the stack traces of all the threads running in your application. So, in the report, **each `caused by` section is not the cause of the precedent exception**, but the stack trace of a different thread.\n\nHere is a dead lock example:\n\n```\nFATAL EXCEPTION: |ANR-WatchDog|\n    Process: anrwatchdog.github.com.testapp, PID: 26737\n    com.github.anrwatchdog.ANRError: Application Not Responding\n    Caused by: com.github.anrwatchdog.ANRError$_$_Thread: main (state = WAITING)\n        at testapp.MainActivity$1.run(MainActivity.java:46)\n        at android.os.Handler.handleCallback(Handler.java:739)\n        at android.os.Handler.dispatchMessage(Handler.java:95)\n        at android.os.Looper.loop(Looper.java:135)\n        at android.app.ActivityThread.main(ActivityThread.java:5221)\n    Caused by: com.github.anrwatchdog.ANRError$_$_Thread: APP: Locker (state = TIMED_WAITING)\n        at java.lang.Thread.sleep(Native Method)\n        at java.lang.Thread.sleep(Thread.java:1031)\n        at java.lang.Thread.sleep(Thread.java:985)\n        at testapp.MainActivity.SleepAMinute(MainActivity.java:18)\n        at testapp.MainActivity.access$100(MainActivity.java:12)\n        at testapp.MainActivity$LockerThread.run(MainActivity.java:36)\n```\n\nFrom this report, we can see that the stack traces of two threads. The first (the \"main\" thread) is stuck at `MainActivity.java:46` while the second thread (named \"App: Locker\") is locked in a Sleep at `MainActivity.java:18`.  \nFrom there, if we looked at those two lines, we would surely understand the cause of the dead lock!\n\nNote that some crash reporting library (such as Crashlytics) report all thread stack traces at the time of an uncaught exception. In that case, having all threads in the same exception can be cumbersome. In such cases, simply use `setReportMainThreadOnly()`.\n\n\nConfiguration\n-------------\n\n### Timeout (minimum hanging time for an ANR)\n\nTo set a different timeout (5000 millis is the default):\n\n```java\nif (BuildConfig.DEBUG == false) {\n  new ANRWatchDog(10000 /*timeout*/).start();\n}\n```\n\n\n### Debugger\n\nBy default, the watchdog will ignore ANRs if the debugger is attached or if the app is waiting for the debugger to attach. This is because it detects execution pauses and breakpoints as ANRs.\nTo disable this and throw an `ANRError` even if the debugger is connected, you can add `setIgnoreDebugger(true)`:\n\n```java\nnew ANRWatchDog().setIgnoreDebugger(true).start();\n```\n\n\n### On ANR callback\n\nIf you would prefer not to crash the application when an ANR is detected, you can enable a callback instead:\n\n```java\nnew ANRWatchDog().setANRListener(new ANRWatchDog.ANRListener() {\n    @Override\n    public void onAppNotResponding(ANRError error) {\n        // Handle the error. For example, log it to HockeyApp:\n        ExceptionHandler.saveException(error, new CrashManager());\n    }\n}).start();\n```\n\n**This is very important when delivering your app in production.**\nWhen in the hand of the final user, it's *probably better* not to crash after 5 seconds, but simply report the ANR to whatever reporting system you use.\nMaybe, after some more seconds, the app will \"de-freeze\".\n\n\n### Filtering reports\n\nIf you would like to have only your own threads to be reported in the ANRError, and not all threads (including system threads such as the `FinalizerDaemon` thread), you can set a prefix: only the threads whose name starts with this prefix will be reported.\n\n```java\nnew ANRWatchDog().setReportThreadNamePrefix(\"APP:\").start();\n```\n\nThen, when you start a thread, don't forget to set its name to something that starts with this prefix (if you want it to be reported):\n\n```java\npublic class MyAmazingThread extends Thread {\n    @Override\n    public void run() {\n        setName(\"APP: Amazing!\");\n        /* ... do amazing things ... */\n    }\n}\n```\n\nIf you want to have only the main thread stack trace and not all the other threads, you can:\n\n```java\nnew ANRWatchDog().setReportMainThreadOnly().start();\n```\n\n\n### ANR Interceptor\n\nSometimes, you want to know that the application has froze for a certain duration, but not report the ANR error just yet.\nYou can define an interceptor that will be called before reporting an error.\nThe role of the interceptor is to define whether or not, given the given freeze duration, an ANR error should be raised or postponed.\n\n```java\nnew ANRWatchDog(2000).setANRInterceptor(new ANRWatchDog.ANRInterceptor() {\n    @Override\n    public long intercept(long duration) {\n        long ret = 5000 - duration;\n        if (ret \u003e 0) {\n            Log.w(TAG, \"Intercepted ANR that is too short (\" + duration + \" ms), postponing for \" + ret + \" ms.\");\n        }\n        return ret;\n    }\n})\n```\n\nIn this example, the ANRWatchDog starts with a timeout of 2000 ms, but the interceptor will postpone the error until at least 5000 ms of freeze has been reached.\n\n\n### Watchdog thread\n\nANRWatchDog is a thread, so you can interrupt it at any time.\n\nIf you are programming with Android's multi process capability (like starting an activity in a new process), remember that you will need an ANRWatchDog thread per process.\n\n\nDonate\n======\n\nANR-Watchdog is free to use for both non-profit and commercial use and always will be.\n\nIf you wish to show some support or appreciation to my work, you are free to **[donate](https://donorbox.org/donation-salomonbrys)**!\n\nThis would be (of course) greatly appreciated but is by no means necessary to receive help or support, which I'll be happy to provide for free :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSalomonBrys%2FANR-WatchDog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSalomonBrys%2FANR-WatchDog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSalomonBrys%2FANR-WatchDog/lists"}