Как я могу перехватить SIGSEGV (ошибка сегментации) и получить трассировку стека под JNI на Android?

StackOverflow https://stackoverflow.com/questions/1083154

Вопрос

Я переезжаю проект к новому встроенному комплекту разработки Android (т.е.JNI) и я хотел бы перехватить SIGSEGV, если это произойдет (возможно, также SIGILL, SIGABRT, SIGFPE), чтобы представить приятный диалог сообщения о сбое вместо (или раньше) того, что происходит в данный момент:немедленная бесцеремонная смерть процесса и, возможно, какая-то попытка операционной системы перезапустить его.(Редактировать: Виртуальная машина JVM / Dalvik улавливает сигнал и регистрирует трассировку стека и другую полезную информацию;Я просто хочу предложить пользователю возможность отправить мне эту информацию по электронной почте на самом деле.)

Ситуация такова:большой объем кода на C, который я не писал, выполняет большую часть работы в этом приложении (вся игровая логика), и хотя он хорошо протестирован на множестве других платформ, вполне возможно, что я в своем порту Android загружу в него мусор и вызову сбой в машинном коде, поэтому я хочу, чтобы аварийные дампы (как native, так и Java), которые в настоящее время отображаются в журнале Android (я предполагаю, что это был бы stderr в ситуации, отличной от Android).Я волен произвольно изменять код как на C, так и на Java, хотя обратных вызовов (как входящих, так и выходящих из JNI) насчитывается около 40 и, очевидно, бонусные баллы за небольшие различия.

Я слышал о библиотеке цепочки сигналов в J2SE, libjsig.so , и если бы я мог безопасно установить подобный обработчик сигналов на Android, это решило бы основную часть моего вопроса, но я не вижу такой библиотеки для Android / Dalvik.

Это было полезно?

Решение

Редактировать: Начиная с Jelly Bean, вы не можете получить трассировку стека, потому что READ_LOGS ушел прочь. :-(

На самом деле я заставил обработчик сигналов работать, не делая ничего слишком экзотического, и выпустил код, использующий его, который вы можете видеть на github (редактировать:ссылка на исторический релиз;С тех пор я удалил обработчик сбоев).Вот как это делается:

  1. Использование sigaction() чтобы перехватывать сигналы и сохранять старые обработчики.(android.c:570)
  2. Проходит время, происходит сбой сегмента.
  3. В обработчике сигнала вызовите JNI в последний раз, а затем вызовите старый обработчик.(android.c:528)
  4. В этом вызове JNI запишите любую полезную информацию об отладке и вызовите startActivity() для действия, которое помечено как необходимое в его собственном процессе.(SGTPuzzles.java:962, AndroidManifest.xml:28)
  5. Когда вы вернетесь с Java и вызовете этот старый обработчик, платформа Android подключится к debuggerd чтобы записать для вас хорошую собственную трассировку, и тогда процесс умрет.(отладчик.c, debuggerd.c)
  6. Тем временем запускается ваша операция по устранению сбоев.Действительно, вы должны передать ему PID, чтобы он мог дождаться завершения шага 5;Я этого не делаю.Здесь вы приносите извинения пользователю и спрашиваете, можете ли вы отправить журнал.Если это так, соберите выходные данные logcat -d -v threadtime и запустить ACTION_SEND с указанием получателя, темы и основного текста.Пользователь должен будет нажать Отправить.(CrashHandler.java, SGTPuzzles.java:462, строки.xml:41
  7. Остерегайтесь logcat сбой или занимает больше нескольких секунд.Я столкнулся с одним устройством, T-Mobile Pulse / Huawei U8220, где logcat сразу переходит в T (отслеживается) состояние и зависает.(Обработчик сбоев.java:70, строки.xml:51)

В ситуации, не связанной с Android, кое-что из этого было бы по-другому.Вам нужно было бы собрать свой собственный родной след, понимаете этот другой вопрос, в зависимости от того, какой тип libc у вас есть.Вам нужно было бы обработать сброс этой трассировки, запустить свой отдельный процесс обработки сбоев и отправить электронное письмо некоторыми подходящими способами для вашей платформы, но я полагаю, что общий подход все равно должен работать.

Другие советы

Я немного опоздал, но у меня была точно такая же потребность, и я разработал небольшую библиотеку для ее решения, отслеживая распространенные сбои (SEGV, SIBGUS, и т.д.) внутри Код JNI, и замените их обычными java.lang.Error исключения.Бонус, если клиент запущен на Android >= 4.1.1, трассировка стека встраивает разрешенные обратная трассировка о сбое (псевдотрасса, содержащая полную собственную трассировку стека).Вы не будете восстанавливаться после жестоких сбоев (т.е.если вы повредили распределитель, например), но, по крайней мере, он должен позволять вам восстанавливаться из большинство из них.(пожалуйста, сообщайте об успехах и неудачах, код совершенно новый)

Более подробная информация на https://github.com/xroche/coffeecatch (код является Лицензия BSD 2-Clauses)

FWIW, Панель управления Google отлично работает на Android.Я выполнил работу по переносу, и мы отправляем его как часть Firefox Mobile.Это требует небольшой настройки, поскольку оно не предоставляет вам трассировки стека на стороне клиента, но отправляет вам необработанную память стека и выполняет обработку стека на стороне сервера (поэтому вам не нужно отправлять символы отладки с вашим приложением).

По моему ограниченному опыту (не для Android), SIGSEGV в коде JNI обычно приводит к сбою JVM до того, как управление будет возвращено вашему Java-коду.Я смутно припоминаю, что слышал о какой-то не-Sun JVM, которая позволяет вам перехватывать SIGSEGV, но AFAICR вы не можете ожидать, что сможете это сделать.

Вы можете попытаться перехватить их в C (см. sigaction(2)), хотя вы можете сделать очень мало после обработчика SIGSEGV (или SIGFPE, или SIGILL), поскольку текущее поведение процесса официально не определено.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top