24

My app is partly written in native app using C/C++. The problem is that whenever C/C++ part crashes for some reason the app dies and then restarts automatically. This causes all kinds of messy problems

Now of course, it should not crash in the native part and I'm trying to weed out all reasons why it would happen. However, if it does happen I'd like to:

  1. Quit gracefully
  2. If it does die, at least not try to restart automatically.

I'm curious as to why this behaviour happens. After some search I tried putting the following line in the main activity element of the AndroidManifest.xml:

android:finishOnTaskLaunch="true"

but the automatic restore still happens.

Anyone knows why this is happening and how to change it?

UPDATE: I think a more fundamental question is,
Is there something similar to a callback if there is a native crash?

One of the answers suggested 'handling crash signals'. I'd be grateful for any links on how it can be done at an application or module level.

As it stands currently, if there is a crash the app just disappears, there's nothing in logcat, so no debugging is possible.

OceanBlue
  • 9,142
  • 21
  • 62
  • 84
  • Android is designed with the idea that it, not the developer, will manage process lifetimes. To that end, it reserves the right to pretty much arbitrarily kill things, and conversely, if something it doesn't think should be dead dies, it may restart it. – Chris Stratton Sep 06 '11 at 14:59
  • 4
    @Chris Stratton: "conversely, if something it doesn't think should be dead dies, it may restart it." I understand the killing part part, but is there a way to override the restart part? – OceanBlue Sep 06 '11 at 15:07
  • Hi, did you find a fix ? I am facing the same issue with my app, containing c++ lib as well. – gxela Aug 08 '18 at 15:56

2 Answers2

14

Try to handle crash signals (SIGSEGV etc.) and send kill to yourself in signal handler. This trick helps me.

Example:

#include <signal.h>
#include <unistd.h>


static void signal_handler(int signal, siginfo_t *info, void *reserved)
{
  kill(getpid(),SIGKILL);
}

extern "C" jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{
  struct sigaction handler;
  memset(&handler, 0, sizeof(handler));
  handler.sa_sigaction = signal_handler;
  handler.sa_flags = SA_SIGINFO;
  sigaction(SIGILL, &handler, NULL);
  sigaction(SIGABRT, &handler, NULL);
  sigaction(SIGBUS, &handler, NULL);
  sigaction(SIGFPE, &handler, NULL);
  sigaction(SIGSEGV, &handler, NULL);
  sigaction(SIGSTKFLT, &handler, NULL);
  return(JNI_VERSION_1_6);
}

UPDATE2

if you want to see crashlog in android logcat you should use this signal handler

static void signal_handler(int signal, siginfo_t *info, void *reserved)
{
 struct sockaddr_un addr;
 size_t namelen;
 socklen_t alen;
 int s, err;
 char name[] = "android:debuggerd";
 namelen  = strlen(name);

 // Test with length +1 for the *initial* '\0'.
 if ((namelen + 1) > sizeof(addr.sun_path)) {
    errno = EINVAL;
    return;
 }

 /* This is used for abstract socket namespace, we need
  * an initial '\0' at the start of the Unix socket path.
  *
  * Note: The path in this case is *not* supposed to be
  * '\0'-terminated. ("man 7 unix" for the gory details.)
  */
 memset (&addr, 0, sizeof addr);
 addr.sun_family = AF_LOCAL;
 addr.sun_path[0] = 0;
 memcpy(addr.sun_path + 1, name, namelen);

 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;

 s = socket(AF_LOCAL, SOCK_STREAM, 0);
 if(s < 0) return;

 RETRY_ON_EINTR(err,connect(s, (struct sockaddr *) &addr, alen));
 if (err < 0) {
    close(s);
    s = -1;
 }

 pid_t tid = gettid();
 if(s>=0)
 {
   /* debugger knows our pid from the credentials on the
    * local socket but we need to tell it our tid.  It
    * is paranoid and will verify that we are giving a tid
    * that's actually in our process
    */
    int  ret;

    RETRY_ON_EINTR(ret, write(s, &tid, sizeof(unsigned)));
    if (ret == sizeof(unsigned)) {
        /* if the write failed, there is no point to read on
         * the file descriptor. */
        RETRY_ON_EINTR(ret, read(s, &tid, 1));
        //notify_gdb_of_libraries();
    }
    close(s);
 }

 wait(NULL);
 kill(getpid(),SIGKILL);
}

I took it from android source (can't insert link because android.git.kernel.org is down), but I am not sure that it will work in future Android releases

Henry Pootle
  • 1,196
  • 1
  • 11
  • 30
  • That sounds promising. I'm sorry, but I don't know how to do that in C/C++. Would that be similar to a try/catch block of Java? What statements in the native code would I put that around? (the native code is a huge behemoth I am trying to port) – OceanBlue Sep 12 '11 at 18:25
  • I add simple example to my answer – Henry Pootle Sep 13 '11 at 07:20
  • Thanks! I think this is the way to go. I can't try it right now, but awarding bounty before it expires. I will look this up further on the web & see if I can write something like umbrella Signal Handlers. – OceanBlue Sep 13 '11 at 10:29
  • I tried putting the Example1 in the c file & it compiles fine. But when I run the app, the System.loadLibrary gives a java UnsatisfiedLinkError :-( – OceanBlue Sep 13 '11 at 16:33
  • My bad, add return JNI_VERSION_1_6 from JNI_OnLoad – Henry Pootle Sep 13 '11 at 19:47
  • didn't work for me :-( (my app still restarts when my native code crashes) – fatfreddyscat Mar 13 '12 at 18:58
  • oceanBlue did you got a solution for the restart issue? because i cant stop it either :/ – Ariel Capozzoli Aug 23 '13 at 18:04
  • 4
    Don't ship an app that talks directly to debuggerd like this. The protocol has changed in the past and will likely change in the future. – fadden Sep 26 '13 at 14:49
0

By default your application should not be automatically restarting. Generally one would have to register for this kind of thing, e.g. via the AlarmManager/keep alives.

Do you have a service as part of your application?

NuSkooler
  • 5,391
  • 1
  • 34
  • 58