17

Is there a way to get notified when your app triggers an ANR (Application Not Responding)? Similar to the default exception handler?

In anticipation of the "what would you do with it" answers, just logging. Not "doing" anything.

Kevin Galligan
  • 16,159
  • 5
  • 42
  • 62
  • 3
    @WarrenFaith Dude. What are you talking about? I accept satisfactory answers. If somebody replies, but it doesn't actually answer the question, I don't accept them. Most of my questions are *really* hard, or don't have an answer. Usually by the time I ask, I've looked a lot, and if its an Android question, and I can't find the answer myself, its going to be a *really tricky* question. My 2K rep is from answering questions. If my app is in the market, I can see freezes. Shocker. I want to catch them myself. – Kevin Galligan Jan 08 '12 at 20:42
  • 1
    @WarrenFaith PS. If you can tell me how to catch ANR's, I promise, your answer will be accepted. Judging from your "If your app is in the market...", you don't know how, so if you answer with that, I won't "accept" it, because its not the answer. Right? Or am I supposed to accept it just because you wrote it? – Kevin Galligan Jan 08 '12 at 20:44
  • 2
    @WarrenFaith PPS, if your answer is "you can't do that", you need to cite a source with a link. Otherwise its just a guess. – Kevin Galligan Jan 08 '12 at 20:45
  • @WarrenFaith "Dude" doesn't imply ownership. So, since I don't really understand your community rules, what do I do with questions that have crap answers? I just went through my open ones, and found like 2 that were borderline, so accepted them, even though they were kind of phoning it in. The rest have submissions but don't really "answer" anything. I can't exactly "reject" them. – Kevin Galligan Jan 08 '12 at 20:56
  • @WarrenFaith Offended? Didn't know that was offensive. That's me expressing my exasperation. As in, "dude, give me a break". I agree I should fill in my own answers when I figure them out. I often do not reply when people fill in quickie answers, because they're obviously just trying to bump up their scores. If there's a legitimate attempt to answer, I think I've been comunicative, at least recently. Didn't understand rules when I was new. Anyway, how is sub-50% suspicious? Most of my questions didn't have good answers. Period. – Kevin Galligan Jan 09 '12 at 04:02
  • I'm not sure if either of these will catch ANR, but http://stackoverflow.com/questions/601503/how-do-i-obtain-crash-data-from-my-android-application or [Bugsense](http://www.bugsense.com/). They very well may only get force close. – Reed Jan 17 '12 at 01:48
  • Check [this thread](http://stackoverflow.com/questions/8543486/how-to-resolve-the-anr-error-while-invoking-the-camera/8559934#8559934) – Lalit Poptani Feb 11 '12 at 04:54

5 Answers5

12

Since the system watchdog does not warn the application, the application itself can have it's own watchdog. The steps are simple, just start a thread that loops doing the following :

  1. Schedule small code to be run on the UI thread as soon as possible.
  2. Wait for X seconds (you decide).
  3. See if the code has run : if it has, go back to 1
  4. If the code has not run, it means that the UI thread has been blocked for at least X seconds, raises an exception with the UI thread stack trace

I have written a small library that does exactly that and that I use with ACRA.

I hope it helps ;)

Salomon BRYS
  • 9,247
  • 5
  • 29
  • 44
6

I've been thinking about this quite a bit. You could do the following, although its pretty heavy handed. ANR's write out a threads file to a generally readable directory:

/data/anr/traces.txt

You could have a service, in a different process, poll that file periodically. If the date changes, and your app is at the top, then you probably had an ANR event.

I'm not 100% sure of the format of the file, though.

Kevin Galligan
  • 16,159
  • 5
  • 42
  • 62
  • This is my favorite answer. Got to try that. Not sure the format of the file matters: it will contain the name of your app package, so you can make sure it's your app which generated it. Wondering if the file system observers would work on that file though. Then on every change you can check if it contains your package name. Could also be checked on app start, to check if app was killed by user following the ANR. – 3c71 Dec 19 '12 at 16:00
5

No. Unlike exceptions that occur within your process's VM that you can catch, the ANR is generated by a system watchdog, outside your VM. Google offers info on triggers and avoidance

larham1
  • 11,736
  • 5
  • 35
  • 26
  • 1
    I really think there's no way to do this, which is pretty frustrating. Could (maybe) do something special with my own api and thread to catch, but that seems pretty hacky. – Kevin Galligan Feb 17 '12 at 00:10
1

This small ANR-WatchDog thread can help you to monitor your app's thread and get notified when ANR happens.

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();
Hassan TBT
  • 805
  • 7
  • 5
0

you could use a service (preferably a foreground service) that listens to the logs (using a thread) , and if there is a log that indicate the ANR , handle it.

here's a small sample of an app that causes ANR:

...
findViewById(R.id.button).setOnClickListener(new OnClickListener()
  {
    @Override
    public void onClick(final View v)
      {
      try
        {
        Thread.sleep(10000);
        }
      catch(final InterruptedException e)
        {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
      }
  });
...

here's the log that i got from the logcat when i got the ANR:

08-03 13:02:37.746: E/ActivityManager(158): ANR in com.example.anr (com.example.anr/.MainActivity)
08-03 13:02:37.746: E/ActivityManager(158): Reason: keyDispatchingTimedOut
08-03 13:02:37.746: E/ActivityManager(158): Load: 6.19 / 2.37 / 0.86
08-03 13:02:37.746: E/ActivityManager(158): CPU usage from 5598ms to 0ms ago:
08-03 13:02:37.746: E/ActivityManager(158):   2.6% 158/system_server: 2.5% user + 0.1% kernel / faults: 86 minor
08-03 13:02:37.746: E/ActivityManager(158):   0.5% 298/com.android.phone: 0.3% user + 0.1% kernel / faults: 15 minor
08-03 13:02:37.746: E/ActivityManager(158):   0% 35/rild: 0% user + 0% kernel
08-03 13:02:37.746: E/ActivityManager(158): 4.6% TOTAL: 3.9% user + 0.6% kernel
08-03 13:02:37.746: E/ActivityManager(158): CPU usage from 2029ms to 2654ms later:
08-03 13:02:37.746: E/ActivityManager(158):   11% 158/system_server: 4.8% user + 6.4% kernel / faults: 2 minor
08-03 13:02:37.746: E/ActivityManager(158):     11% 192/InputDispatcher: 4.8% user + 6.4% kernel
08-03 13:02:37.746: E/ActivityManager(158):     1.6% 163/Compiler: 1.6% user + 0% kernel
08-03 13:02:37.746: E/ActivityManager(158):     1.6% 193/InputReader: 0% user + 1.6% kernel
08-03 13:02:37.746: E/ActivityManager(158): 18% TOTAL: 9.3% user + 9.3% kernel

so , yes , i think it's possible.

android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • It will not be possible as of Jelly Bean, as you are not be able to read the logs from other processes or the OS. Besides, reading the logs is not part of the Android SDK. – CommonsWare Aug 03 '12 at 13:27
  • correct.since i don't have JB , i can't see if there are any workarounds for this. they said in the google IO that even though now it won't work , it's ok to read the logs of your own app , so i don't know if such a thing is considered to be inside the app (i guess it's not).anyway , this solution is a workaround from the start . it should work for about 99% of the devices currently . – android developer Aug 03 '12 at 14:00
  • I have another idea. Will post in answer section. – Kevin Galligan Aug 04 '12 at 16:21