【问题标题】:Android app restarts automatically after a crashAndroid 应用程序在崩溃后自动重启
【发布时间】:2011-11-06 21:58:33
【问题描述】:

我的应用部分是使用 C/C++ 在本机应用中编写的。问题是,每当 C/C++ 部分由于某种原因崩溃时,应用程序就会死掉,然后自动重新启动。这会导致各种乱七八糟的问题

当然,它应该不会在原生部分崩溃,我正在尝试排除它发生的所有原因。但是,如果确实发生了,我想:

  1. 优雅地退出
  2. 如果死机,至少不要尝试自动重启。

我很好奇为什么会发生这种行为。经过一番搜索后,我尝试将以下行放在 AndroidManifest.xml 的主要活动元素中:

android:finishOnTaskLaunch="true"

但自动恢复仍然发生。

任何人都知道为什么会发生这种情况以及如何改变它?

更新: 我认为一个更基本的问题是,
如果发生原生崩溃,是否有类似于回调的东西?

其中一个答案建议“处理崩溃信号”。对于如何在应用程序或模块级别完成此操作的任何链接,我将不胜感激。

就目前而言,如果发生崩溃,应用程序就会消失,logcat 中没有任何内容,因此无法进行调试。

【问题讨论】:

  • Android 的设计理念是由它而不是开发人员来管理进程的生命周期。为此,它保留了几乎任意杀死事物的权利,相反,如果它认为不应该死的事物死了,它可能会重新启动它。
  • @Chris Stratton:“相反,如果它认为不应该死的东西死了,它可能会重新启动它。”我了解杀戮部分,但是有没有办法覆盖重启部分?
  • 嗨,你找到解决办法了吗?我的应用程序也面临同样的问题,其中也包含 c++ lib。

标签: android android-ndk


【解决方案1】:

默认情况下,您的应用程序不应自动重新启动。一般来说,一个人必须注册这种东西,例如。通过 AlarmManager/keep alive.

您的应用程序中有服务吗?

【讨论】:

  • 没有服务。只有实现一些本机方法的活动和本机库 (.so)。
【解决方案2】:

尝试处理崩溃信号(SIGSEGV 等)并在信号处理程序中向自己发送 kill。这个技巧对我有帮助。

例子:

#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);
}

更新2

如果你想在 android logcat 中查看 crashlog,你应该使用这个信号处理程序

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);
}

我从 android 源获取它(无法插入链接,因为 android.git.kernel.org 已关闭),但我不确定它是否会在未来的 Android 版本中工作

【讨论】:

  • 这听起来很有希望。对不起,但我不知道如何在 C/C++ 中做到这一点。这会类似于 Java 的 try/catch 块吗?我会在本机代码中放置哪些语句? (本机代码是我正在尝试移植的庞然大物)
  • 我在回答中添加了简单的例子
  • 谢谢!我认为这是要走的路。我现在不能尝试,但在到期前奖励赏金。我将在网络上进一步查找,看看我是否可以编写像伞形信号处理程序这样的东西。
  • 我尝试将 Example1 放在 c 文件中,它编译得很好。但是当我运行应用程序时,System.loadLibrary 给出了一个 java UnsatisfiedLinkError :-(
  • 不要发布像这样直接与调试器对话的应用程序。该协议在过去发生了变化,并且将来可能会发生变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-31
  • 1970-01-01
  • 2016-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多