ACRA / acra

Application Crash Reports for Android
https://www.acra.ch
Apache License 2.0
6.31k stars 1.14k forks source link

Crash in background service leads to continous loop. #477

Closed pssaravanan closed 7 years ago

pssaravanan commented 8 years ago

Hi, I have a background service which runs contiously. if crash happened in background service, it is captured by acra, sends report and kills the app. But the background service started again. and crash again and send report again and kills the app again and restart again and it happens continously. And my service getting error report for every seconds. When i check without acra. in a second time, ANR comes and service ended.

Thanks, Saravanan

william-ferguson-au commented 8 years ago

You don't mention which version of ACRA you are using, but if it ios 4.7+ then ACRA will be using the SenderService to send the report in a different process. When that new process is started it is possible that your errant Service is also started.

You should ensure that your service is only started for the non ACRA process.

pssaravanan commented 8 years ago

We using acra 4.8.5. Any code snippet will be useful. Thanks.

pssaravanan commented 8 years ago

Note: I am new to android. I defined a seperate process for running the service by setting android:process for service. But still the problem occurs. And i am starting service with START_STICKY.

william-ferguson-au commented 8 years ago

How are you starting your service?

pssaravanan commented 8 years ago

By using context.startService(intent).

william-ferguson-au commented 8 years ago

Yes, but from where and when?

pssaravanan commented 8 years ago

In two places, in the main activity and when phone call received using broadcast receiver.

pssaravanan commented 8 years ago

I put log in different places like where i am starting the service(main activity & phone call receiver), onStartCommand, before error. and i am seeing, service is only once started in MainActivity. And other logs are from onStartCommand method and before error.

william-ferguson-au commented 8 years ago

It is probably because you are starting your service with START_STICKY. I suspect this is causing your service to attempt to restart each time. Are you sure that's what you want to do?

pssaravanan commented 8 years ago

There were two approches to my problem very similar to truecaller.

  1. Using the phone call receiver.
  2. Having long running service with PhoneStateListener with START_STICKY.

I cant go to phone call receiver because, it is delayed by few seconds. which is not surely acceptable for my problem. Hence i choosen service with START_STICKY. Even then, without acra, Services stops after a second try may be.

Thanks,

F43nd1r commented 8 years ago

I was able to reproduce the problem with a service with only this method:

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        ACRA.log.d(ACRA.LOG_TAG, "Service started");
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                ACRA.log.d(ACRA.LOG_TAG, "Service crashing");
                throw new RuntimeException();
            }
        }, 100);
        return START_STICKY;
    }

However I have no idea how to fix this. Of course we could stop all services in the crashing process, but I can't think of any way on how to identify if a Service is responsible for a crash or not.

william-ferguson-au commented 8 years ago

You could always check ACRA.isACRASenderServiceProcess() inside onStartCommand() and refuse to start the service. But I don't see a way of doing it generically.

F43nd1r commented 8 years ago

The service is not restarted inside the acra process. It normally respawns in a process with the same name as the one that got killed, but I also saw it in an unnamed process a few times.

william-ferguson-au commented 8 years ago

So unless we can find a way of starting the SenderService in a new Process without also starting any STICKY services then we can't support apps with services that use START_STICKY.

F43nd1r commented 8 years ago

To my understanding the trigger for restart is not the start of senderservice, but instead the kill of the process.

F43nd1r commented 8 years ago

The real problem is that all services in the same process will show the same behaviour regardless of their role in the crash.

william-ferguson-au commented 8 years ago

Is this caused by ACRA explicitly killing the process? If so what happens if we stop doing that?

F43nd1r commented 8 years ago

Yes. If we do not kill the process, all threads but the crashed one will continue to run. While I haven't tested this, I suspect that this will lead to inconsistent states, especially if the crashed thread is the main thread (unless android recreates it).

I'd say it will require a lot of testing. For example I would not expect to see any other activity lifecycle methods being called after I threw an exception in oncreate. But this is what could happen.

Also the default exception handler exits the same way, but I see my service is restarted exactly one time (so two crashes). Maybe we can find out why that is the case and copy the behaviour.

F43nd1r commented 8 years ago

Is this caused by ACRA explicitly killing the process? If so what happens if we stop doing that?

I did my tests. We do not want to stop doing that. If the crashed thread was connected to a Looper (e.g. Main Thread, UI Thread), bad things are happening. I have seen everything from ANR to a System crash depending on the place of the exception.

pssaravanan commented 8 years ago

Right now, i did work around to my problem, by having the code.

        Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable ex) {
                ACRA.getErrorReporter().uncaughtException(thread, ex);
                Intent in = new Intent(context, ProblematicService.class);
                context.stopService(in);
            }
        });

Thanks

F43nd1r commented 8 years ago

I spent some more time on this. I have to say: There is no nice solution. Options are:

F43nd1r commented 8 years ago

Actually I saw a glimpse of a good solution, but it involves sourcecode/bytecode postprocessing. I have no experience in that whatsoever. Also bytecode manipulation doesn't work with the new jack toolchain atm.

william-ferguson-au commented 8 years ago

If there was a way in the UncaughtExceptionHandler to determine that this Thread/Process is owned by Service and we can determine what service, then we could use @pssaravanan 's approach generically.

F43nd1r commented 8 years ago

The problem is that Threads and Android components do not correlate in any way. Multiple Services and activities might be using the same main thread, and threads can be shared with bound services. The only way i know of to eliminate this problem is to use a different process for that service, but even in this case we'd need to get a hold on the service instance to prevent the restart.

Edit: We'd need a mapping from process name to service class (not service instance).

william-ferguson-au commented 8 years ago

What if we stopped all services regardless?

F43nd1r commented 8 years ago

Is an option, but must be opt-in. Most apps will not expect their services to stop outside their own control.

william-ferguson-au commented 8 years ago

That sounds reasonable to me. New config item: stopServicesOnCrash

F43nd1r commented 8 years ago

A boolean or an array of service classes?

william-ferguson-au commented 8 years ago

I think Boolean. Keep it simple. Kill all services (except SenderService). After all the app has just crashed.

F43nd1r commented 7 years ago

Resolved in #513