Pergunta

estou me mudando um projeto ao novo kit de desenvolvimento nativo do Android (ou seja,JNI) e gostaria de capturar o SIGSEGV, caso ele ocorra (possivelmente também SIGILL, SIGABRT, SIGFPE) para apresentar uma boa caixa de diálogo de relatório de falhas, em vez (ou antes) do que acontece atualmente:a morte imediata e sem cerimônia do processo e possivelmente alguma tentativa do sistema operacional de reiniciá-lo.(Editar: A JVM/Dalvik VM captura o sinal e registra um rastreamento de pilha e outras informações úteis;Eu só quero oferecer ao usuário a opção de me enviar essas informações por e-mail.)

A situação é:um grande corpo de código C que eu não escrevi faz a maior parte do trabalho neste aplicativo (toda a lógica do jogo) e embora seja bem testado em inúmeras outras plataformas, é perfeitamente possível que eu, na minha versão Android, alimente é lixo e causa uma falha no código nativo, então eu quero os despejos de memória (nativos e Java) que aparecem atualmente no log do Android (acho que seria stderr em uma situação não Android).Estou livre para modificar o código C e Java arbitrariamente, embora os retornos de chamada (entrando e saindo do JNI) sejam cerca de 40 e, obviamente, pontos de bônus para pequenas diferenças.

Já ouvi falar da biblioteca de encadeamento de sinais em J2SE, libjsig.so, e se eu pudesse instalar com segurança um manipulador de sinais como esse no Android, isso resolveria a parte complicada da minha pergunta, mas não vejo essa biblioteca para Android/Dalvik .

Foi útil?

Solução

Editar: Do Jelly Bean em diante você não pode obter o rastreamento de pilha, porque READ_LOGS se afastou. :-(

Na verdade, coloquei um manipulador de sinal funcionando sem fazer nada muito exótico e liberei código usando-o, que você pode ver no github (editar:vinculando ao lançamento histórico;Eu removi o manipulador de falhas desde então).Veja como:

  1. Usar sigaction() para capturar os sinais e armazenar os manipuladores antigos.(android.c:570)
  2. O tempo passa, acontece uma falha de segmento.
  3. No manipulador de sinal, chame o JNI uma última vez e depois chame o manipulador antigo.(android.c:528)
  4. Nessa chamada JNI, registre qualquer informação útil de depuração e ligue startActivity() em uma atividade que está sinalizada como necessitando estar em seu próprio processo.(SGTPuzzles.java:962, AndroidManifest.xml:28)
  5. Quando você voltar do Java e chamar aquele manipulador antigo, a estrutura do Android se conectará a debuggerd para registrar um bom rastreamento nativo para você e então o processo morrerá.(depurador.c, depurador.c)
  6. Enquanto isso, sua atividade de tratamento de falhas está sendo iniciada.Na verdade, você deve passar o PID para que ele possa aguardar a conclusão da etapa 5;Eu não faço isso.Aqui você pede desculpas ao usuário e pergunta se pode enviar um log.Se sim, reúna a saída de logcat -d -v threadtime e lançar um ACTION_SEND com destinatário, assunto e corpo preenchidos.O usuário terá que pressionar Enviar.(CrashHandler.java, SGTPuzzles.java:462, strings.xml:41
  7. Ter cuidado com logcat falhando ou demorando mais do que alguns segundos.Encontrei um dispositivo, o T-Mobile Pulse/Huawei U8220, onde o logcat entra imediatamente no T estado (rastreado) e trava.(CrashHandler.java:70, strings.xml:51)

Em uma situação não Android, parte disso seria diferente.Você precisaria reunir seu próprio rastreamento nativo, consulte essa outra pergunta, dependendo do tipo de libc que você possui.Você precisaria lidar com o despejo desse rastreamento, iniciar seu processo separado de tratamento de falhas e enviar o e-mail de maneiras apropriadas para sua plataforma, mas imagino que a abordagem geral ainda deva funcionar.

Outras dicas

Estou um pouco atrasado, mas tive exatamente a mesma necessidade e desenvolvi uma pequena biblioteca para resolver isso, capturando travamentos comuns (SEGV, SIBGUS, etc.) dentro Código JNI, e substitua-os por regulares java.lang.Error exceções.Bônus, se o cliente estiver rodando em Android >= 4.1.1, o rastreamento de pilha incorpora o resolvido rastreamento de retorno da falha (um pseudo-rastreamento contendo o rastreamento de pilha nativo completo).Você não se recuperará de travamentos violentos (ou seja,se você corromper o alocador, por exemplo), mas pelo menos deveria permitir que você se recupere de maioria deles.(por favor, relate sucessos e falhas, o código é totalmente novo)

Mais informações em https://github.com/xroche/coffeecatch(o código é Licença BSD de 2 cláusulas)

FWIW, Google Breakpad funciona bem no Android.Eu fiz o trabalho de portabilidade e estamos enviando-o como parte do Firefox Mobile.Ele requer um pouco de configuração, já que não fornece rastreamentos de pilha no lado do cliente, mas envia a memória bruta da pilha e faz o stack walk no lado do servidor (para que você não precise enviar símbolos de depuração com seu aplicativo ).

Na minha experiência limitada (não Android), o SIGSEGV no código JNI geralmente trava a JVM antes que o controle seja retornado ao seu código Java.Lembro-me vagamente de ter ouvido falar de alguma JVM não-Sun que permite capturar SIGSEGV, mas AFAICR você não pode esperar conseguir fazer isso.

Você pode tentar capturá-los em C (veja sigaction(2)), embora você possa fazer muito pouco depois de um manipulador SIGSEGV (ou SIGFPE ou SIGILL), já que o comportamento contínuo de um processo é oficialmente indefinido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top