Приложение Android продолжает перезапускаться после исключения SIGFPEAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Приложение Android продолжает перезапускаться после исключения SIGFPE

Сообщение Anonymous »

У меня есть приложение для Android, логика которого в основном написана на C++. Что касается обработки исключений в C++, я использую механизм обработчика сигналов Linux для перехвата сигналов, возникающих из-за исключений, таких как нарушение доступа к памяти, деление на ноль и т. д.

Код: Выделить всё

// ExceptionHandlingCpp.h file

using SignalHandlerFunc = void (*) (int, siginfo_t *, void *);

struct tSignals {

SignalHandlerFunc signalHandlerFunc;
uint32_t          signal;
[[maybe_unused]]
uint8_t           reserved[4];
};

class ExceptionHandlingCpp {

public:

static tSignals unixSignals[];

private:
static uint8_t numOfRecursions;
static thread_local uint8_t currentIteration;

// Other private data members

public:

static void RegisterSignals();
static void HandleSignals(int pSignals, siginfo_t* pInfo, void* pContext);
static void UnregisterSignal(int pSignal);
static void CheckRecursiveExceptions(int pSignal);

static void* DivisionByZero(void* pParms);

// Other public member functions

};

Код: Выделить всё

// ExceptionHandlingCpp.cpp file

tSignals ExceptionHandlingCpp::unixSignals[] = {

{HandleSignals, SIGFPE, {0}},
{HandleSignals, SIGSEGV, {0}},
{HandleSignals, SIGKILL, {0}},
};

uint8_t ExceptionHandlingCpp::numOfRecursions {5};
thread_local uint8_t ExceptionHandlingCpp::currentIteration {0};

void ExceptionHandlingCpp::RegisterSignals() {
LOG("ExceptionHandlingCpp::RegisterSignals()");

struct sigaction sa;

sa.sa_flags = SA_SIGINFO;

for(int i = 0; i < sizeof(unixSignals)/sizeof(tSignals); ++i) {

sa.sa_sigaction = unixSignals[i].signalHandlerFunc;
sigaction(unixSignals[i].signal, &sa, nullptr);
}
}

void ExceptionHandlingCpp::HandleSignals(int pSignal, siginfo_t *pInfo, void *pContext) {
LOG("ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)");

LOG("signal = " + signalName(pSignal));

// TODO: Handle the exception/signal.

// Sets the default handler if the exception keeps repeating
// more than 5 times.  This is just to experiment what happens when
// the default handler is set for the signal.
CheckRecursiveExceptions(pSignal);

// Record the exception count
LOG("currentIteration = " + std::to_string(currentIteration));

LOG("Returning from exception handler...");
}

void ExceptionHandlingCpp::UnregisterSignal(int pSignal) {

LOG("ExceptionHandlingCpp::UnregisterSignal(int)");

struct sigaction defaultAction {};
defaultAction.sa_handler = SIG_DFL;

if(sigaction(pSignal, &defaultAction, nullptr) == -1) {
LOG("Error in resetting action for " + signalName(pSignal));
} else {
LOG("Successfully reset " + signalName(pSignal) + "'s action to default!");
}
}

void ExceptionHandlingCpp::CheckRecursiveExceptions(int pSignal) {

LOG("ExceptionHandlingCpp::CheckRecursiveExceptions()");

currentIteration++;

if(currentIteration > numOfRecursions) {
// After repeating for said times, update the action for the signal to default and do nothing
UnregisterSignal(pSignal);
} else {
LOG("Number of recursions so far = " + std::to_string(currentIteration));
}
}

void* ExceptionHandlingCpp::DivisionByZero ([[maybe_unused]] void* pParms)
{
LOG("ExceptionHandlingCpp::DivisionByZero()");

int num1;
int num2;
int result;

num1 = 5;
num2 = 0;

LOG("Raising exception...");

result = num1 / num2;

LOG("Returning from DivisionByZero() method");

return nullptr;
}

std::string ExceptionHandlingCpp::signalName(int pSignal)
{
switch(pSignal) {
case SIGSEGV:
return "SIGSEGV";
case SIGFPE:
return "SIGFPE";
case SIGKILL:
return "SIGKILL";
default:
return "Undefined signal!";
}
}

В Activity.onCreate я вызываю функцию C++ с искаженным именем, Java_sample_experiments_androidExceptionhandling_KotlinExceptions_testExceptionHandlerFromCppрегистрирует обработчики для некоторых сигналов (, SIGFPE и SIGKILL) и имитировать исключение деления на ноль, вызывая метод ExceptionHandlingCpp::DivisionByZero.

Код: Выделить всё

HandleSignals
— мой обработчик сигналов. Когда вы просто возвращаетесь из обработчика сигнала, управление возвращается к инструкции, вызвавшей сигнал, которая затем снова вызывает обработчик сигнала. Единственный выход из этого цикла — установить для сигнала обработчик по умолчанию. Я устанавливаю обработчик по умолчанию в методе UnregisterSignal, который вызывается из обработчика сигнала после 5 итераций.
В logcat есть следующие журналы:

Код: Выделить всё

---------------------------- PROCESS STARTED (6199) for package sample.experiments.androidexceptionhandling ----------------------------
(2 | 6199) MainApplication.onCreate()
(6199) JNI_OnLoad(JavaVM*, void*)
(6199) Initializing JavaVM...
(2 | 6199) MainActivity.onCreate(Bundle?)
(6199) Java_sample_experiments_androidexceptionhandling_KotlinExceptions_testExceptionHandlerFromCpp(JNIEnv *, jobject)
(6199) ExceptionHandlingCpp::RegisterSignals()
(6199) TestExceptionHandler()
(6199) ***** Begin Exception Handling testing (C++) *****
(6199) ExceptionHandlingCpp::DivisionByZero()
(6199) Raising exception...
(6199) ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)
(6199) signal = SIGFPE
(6199) ExceptionHandlingCpp::CheckRecursiveExceptions()
(6199) Number of recursions so far = 1
(6199) Returning from exception handler...
(6199) ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)
(6199) signal = SIGFPE
(6199) ExceptionHandlingCpp::CheckRecursiveExceptions()
(6199) Number of recursions so far = 2
(6199) Returning from exception handler...
(6199) ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)
(6199) signal = SIGFPE
(6199) ExceptionHandlingCpp::CheckRecursiveExceptions()
(6199) Number of recursions so far = 3
(6199) Returning from exception handler...
(6199) ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)
(6199) signal = SIGFPE
(6199) ExceptionHandlingCpp::CheckRecursiveExceptions()
(6199) Number of recursions so far = 4
(6199) Returning from exception handler...
(6199) ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)
(6199) signal = SIGFPE
(6199) ExceptionHandlingCpp::CheckRecursiveExceptions()
(6199) Number of recursions so far = 5
(6199) Returning from exception handler...
(6199) ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)
(6199) signal = SIGFPE
(6199) ExceptionHandlingCpp::CheckRecursiveExceptions()
(6199) ExceptionHandlingCpp::UnregisterSignal(int)
(6199) Successfully reset SIGFPE's action to default!
(6199) Returning from exception handler...
---------------------------- PROCESS ENDED (6199) for package sample.experiments.androidexceptionhandling ----------------------------
---------------------------- PROCESS STARTED (6276) for package sample.experiments.androidexceptionhandling ----------------------------
(2 | 6276) MainApplication.onCreate()
(6276) JNI_OnLoad(JavaVM*, void*)
(6276) Initializing JavaVM...
(2 | 6276) MainActivity.onCreate(Bundle?)
(6276) Java_sample_experiments_androidexceptionhandling_KotlinExceptions_testExceptionHandlerFromCpp(JNIEnv *, jobject)
(6276) ExceptionHandlingCpp::RegisterSignals()
(6276) TestExceptionHandler()
(6276) ***** Begin Exception Handling testing (C++) *****
(6276) ExceptionHandlingCpp::DivisionByZero()
(6276) Raising exception...
(6276) ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)
(6276) signal = SIGFPE
Число в скобках — это идентификатор основного потока. Как показано в приведенных выше журналах, возникает исключение, вызывается обработчик сигнала и ведется подсчет итераций. Под итерациями я имею в виду инструкцию исключения -> обработчик сигнала -> инструкцию исключения и так далее. Когда выполняются 5 итераций, в шестой раз вызывается UnregisterSignal для установки обработчика по умолчанию, который должен завершить процесс. Но я заметил, что процесс каким-то образом перезапускается. Как показано в приведенных выше журналах, класс MainAcpplication вызывается снова с другим идентификатором для основного потока.

Когда я прекращаю регистрацию в SIGFPE, процесс завершается, как и ожидалось. Это происходит только для SIGFPE... когда я повторяю то же самое для SIGSEGV, он работает так, как ожидалось, т. е. повторяется 5 раз, а когда я устанавливаю значение по умолчанию, процесс завершается и не перезапускается.
Почему процесс SIGFPE продолжает перезапускаться? Я ожидаю, что процесс завершится после установки обработчика по умолчанию. Это какая-то настройка студии Android? Я обновил Android Studio, несколько раз удалял и воссоздавал проект, пробовал использовать разные эмуляторы, но ничего не помогло.
Среда:

Студийная версия Android: Ladybug

Операционная система эмулятора: Android 13.0 (Тирамису) и Android 14.0 (перевернутый торт)

Подробнее здесь: https://stackoverflow.com/questions/791 ... -exception
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»