Можно ли использовать Core Foundation в обратном вызове сигнала PLCrashReporter?

Я использую PLCrashReporter в своем проекте iOS, и мне интересно, можно ли использовать код Core Foundation в мой пользовательский обратный вызов при сбое. Вещь, которая удовлетворяет мои потребности, - это CFPreferences. Вот часть кода, который я создаю:

void LMCrashCallback(siginfo_t* info, ucontext_t* uap, void* context) {
  CFStringRef networkStatusOnCrash;
  networkStatusOnCrash = (CFStringRef)CFPreferencesCopyAppValue(networkStatusKey, kCFPreferencesCurrentApplication);
  CFStringRef additionalInfo = CFStringCreateWithFormat(
              NULL, NULL, CFSTR( "Additional Crash Properties:[Internet: %@]", networkStatusOnCrash);
  CFPreferencesSetAppValue(additionalInfoKey, additionalInfo,
                           kCFPreferencesCurrentApplication);
  CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
}

Моя цель - собрать некоторую системную информацию как раз в момент сбоя приложения, например, тип подключения к Интернету.

Я знаю, что не стоит создавать собственный обратный вызов при сбое из-за асинхронно-безопасных функций, но это может помочь.

Также как другой вариант: есть ли способ как-то расширить класс PLCrashReportSystemInfo?


person Foriger    schedule 26.05.2015    source источник


Ответы (1)


Это очень опасно. В частности, вызов CFStringCreateWithFormat выделяет память. Выделение памяти в середине обработчика сбоя может привести к зависанию батареи (да, была эта ошибка…). Например, если вы были в середине free() (что не редкость для сбоя), вы уже удержание спин-блокировки в куче. Когда вы вызываете malloc, чтобы получить немного памяти, вы можете снова заблокировать кучу и зайти в тупик в узком цикле. Куча должна быть заблокирована так часто и на такие короткие периоды времени, что она не использует блокировку блокировки. Это эквивалентно while (locked) {}.

Кажется, вы просто читаете предпочтение и копируете его в другое предпочтение. Нет причин делать это внутри обработчика сбоев. Просто проверьте hasPendingCrashReport во время запуска (что, я полагаю, вы уже делаете) и затем прочитайте ключ. Непонятно, что такое networkStatusKey, но он все равно должен быть там, когда вы снова запустите.

Если по какой-либо причине оно было изменено очень рано (до вызова hasPendingCrashReport), вы можете получить его в main() перед запуском приложения. Или вы можете получить его в методе +load, который вызывается еще раньше.

person Rob Napier    schedule 26.05.2015
comment
Отличный ответ. Большое спасибо. - person Foriger; 26.05.2015