Сбой тайм-аута сторожевого таймера iOS11 (0x8badf00d), но код не находится в стеке

Я отлаживаю пользовательские отчеты о том, что наше приложение постоянно закрывается, находясь в фоновом режиме, начиная с iOS11, даже во время активного использования (например, пользователь заходит в фоновый режим и возвращается в течение нескольких секунд или минут только для того, чтобы найти его перезапущенным). Все журналы сбоев указывают на одну и ту же причину: тайм-аут сторожевого таймера. Вот соответствующий фрагмент из одного такого журнала сбоев:

Exception Type:  EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Termination Reason: Namespace <0xF>, Code 0x8badf00d
Triggered by Thread:  0

Я понимаю, что наш код имеет ограниченный период времени для работы при получении push-уведомлений или в фоновом режиме. Мы определенно используем UIBackgroundTasks (с Alamofire Networking, FWIW), и у нас есть обработчики истечения срока действия, которые делают это. :

backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
    [application endBackgroundTask:backgroundTask];
    backgroundTask = UIBackgroundTaskInvalid; // Set the task to be invalid
    DebugLog(@"Ended because expiration");
}];

Больше всего в этих отчетах о сбоях сбивает с толку то, что нашего кода нигде нет в стеках. Мы можем видеть из это обсуждение Apple кода исключения 0x8badf00d , нарушающий код фактически активно выполняется в основном потоке.

Однако в моем случае ни один из стеков никогда не выполнял мой код. Вот один репрезентативный образец:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib          0x0000000183208bc4 0x183208000 + 3012
1   libsystem_kernel.dylib          0x0000000183208a3c 0x183208000 + 2620
2   CoreFoundation                  0x00000001836b9c4c 0x1835d0000 + 957516
3   CoreFoundation                  0x00000001836b7818 0x1835d0000 + 948248
4   CoreFoundation                  0x00000001835d7e78 0x1835d0000 + 32376
5   GraphicsServices                0x000000018546cf84 0x185462000 + 44932
6   UIKit                           0x000000018d37a0bc 0x18d307000 + 471228
7   MyApp                           0x0000000102a6572c main + 87852 (main.m:22)
8   libdyld.dylib                   0x00000001830fa56c 0x1830f9000 + 5484

Thread 1 name:  com.apple.uikit.eventfetch-thread
Thread 1:
0   libsystem_kernel.dylib          0x0000000183208bc4 0x183208000 + 3012
1   libsystem_kernel.dylib          0x0000000183208a3c 0x183208000 + 2620
2   CoreFoundation                  0x00000001836b9c4c 0x1835d0000 + 957516
3   CoreFoundation                  0x00000001836b7818 0x1835d0000 + 948248
4   CoreFoundation                  0x00000001835d7e78 0x1835d0000 + 32376
5   Foundation                      0x00000001840006e4 0x183ff4000 + 50916
6   Foundation                      0x000000018401fafc 0x183ff4000 + 178940
7   UIKit                           0x000000018ded9630 0x18d307000 + 12396080
8   Foundation                      0x0000000184101860 0x183ff4000 + 1103968
9   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
10  libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
11  libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 2 name:  com.twitter.crashlytics.ios.MachExceptionServer
Thread 2:
0   libsystem_kernel.dylib          0x0000000183208bc4 0x183208000 + 3012
1   libsystem_kernel.dylib          0x0000000183208a3c 0x183208000 + 2620
2   MyApp                           0x0000000102cdaad8 CLSMachExceptionServer + 100
3   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
4   libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
5   libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 3 name:  com.apple.NSURLConnectionLoader
Thread 3:
0   libsystem_kernel.dylib          0x0000000183208bc4 0x183208000 + 3012
1   libsystem_kernel.dylib          0x0000000183208a3c 0x183208000 + 2620
2   CoreFoundation                  0x00000001836b9c4c 0x1835d0000 + 957516
3   CoreFoundation                  0x00000001836b7818 0x1835d0000 + 948248
4   CoreFoundation                  0x00000001835d7e78 0x1835d0000 + 32376
5   CFNetwork                       0x0000000183d41de0 0x183c93000 + 716256
6   Foundation                      0x0000000184101860 0x183ff4000 + 1103968
7   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
8   libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
9   libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 4 name:  AVAudioSession Notify Thread
Thread 4:
0   libsystem_kernel.dylib          0x0000000183208bc4 0x183208000 + 3012
1   libsystem_kernel.dylib          0x0000000183208a3c 0x183208000 + 2620
2   CoreFoundation                  0x00000001836b9c4c 0x1835d0000 + 957516
3   CoreFoundation                  0x00000001836b7818 0x1835d0000 + 948248
4   CoreFoundation                  0x00000001835d7e78 0x1835d0000 + 32376
5   AVFAudio                        0x0000000189615774 0x189591000 + 542580
6   AVFAudio                        0x0000000189640018 0x189591000 + 716824
7   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
8   libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
9   libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 5:
0   libsystem_kernel.dylib          0x0000000183229150 0x183208000 + 135504
1   libsystem_pthread.dylib         0x000000018333ed30 0x18333a000 + 19760
2   libc++.1.dylib                  0x00000001828e3ea4 0x1828dc000 + 32420
3   JavaScriptCore                  0x000000018b157d00 0x18a812000 + 9723136
4   JavaScriptCore                  0x000000018b157c28 0x18a812000 + 9722920
5   JavaScriptCore                  0x000000018b157f8c 0x18a812000 + 9723788
6   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
7   libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
8   libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 6 name:  WebThread
Thread 6:
0   libsystem_kernel.dylib          0x0000000183208bc4 0x183208000 + 3012
1   libsystem_kernel.dylib          0x0000000183208a3c 0x183208000 + 2620
2   CoreFoundation                  0x00000001836b9c4c 0x1835d0000 + 957516
3   CoreFoundation                  0x00000001836b7818 0x1835d0000 + 948248
4   CoreFoundation                  0x00000001835d7e78 0x1835d0000 + 32376
5   WebCore                         0x000000018bc1c75c 0x18bbdb000 + 268124
6   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
7   libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
8   libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 7 name:  WebCore: LocalStorage
Thread 7:
0   libsystem_kernel.dylib          0x0000000183229150 0x183208000 + 135504
1   libsystem_pthread.dylib         0x000000018333ed30 0x18333a000 + 19760
2   JavaScriptCore                  0x000000018a81fa18 0x18a812000 + 55832
3   JavaScriptCore                  0x000000018b13da04 0x18a812000 + 9615876
4   WebKitLegacy                    0x000000018d00f5fc 0x18cf7c000 + 603644
5   WebKitLegacy                    0x000000018d01226c 0x18cf7c000 + 615020
6   WebKitLegacy                    0x000000018d011998 0x18cf7c000 + 612760
7   JavaScriptCore                  0x000000018a81c010 0x18a812000 + 40976
8   JavaScriptCore                  0x000000018a81bf50 0x18a812000 + 40784
9   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
10  libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
11  libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 8 name:  com.apple.CFSocket.private
Thread 8:
0   libsystem_kernel.dylib          0x0000000183229570 0x183208000 + 136560
1   CoreFoundation                  0x00000001836c2184 0x1835d0000 + 991620
2   libsystem_pthread.dylib         0x000000018333c31c 0x18333a000 + 8988
3   libsystem_pthread.dylib         0x000000018333c1e8 0x18333a000 + 8680
4   libsystem_pthread.dylib         0x000000018333ac28 0x18333a000 + 3112

Thread 9:
0   libsystem_pthread.dylib         0x000000018333ac1c 0x18333a000 + 3100

Thread 10:
0   libsystem_kernel.dylib          0x0000000183229dbc 0x183208000 + 138684
1   libsystem_pthread.dylib         0x000000018333afa0 0x18333a000 + 4000
2   libsystem_pthread.dylib         0x000000018333ac20 0x18333a000 + 3104

Thread 11:
0   libsystem_pthread.dylib         0x000000018333ac1c 0x18333a000 + 3100

Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000010004005   x1: 0x0000000007000806   x2: 0x0000000000000000   x3: 0x0000000000000c00
    x4: 0x0000000000002b03   x5: 0x00000000ffffffff   x6: 0x0000000000000000   x7: 0x0000000000000000
    x8: 0x00000000fffffbbf   x9: 0x0000000007000000  x10: 0x0000000007000100  x11: 0x0000000000000040
   x12: 0xffffffffffffffff  x13: 0x0000000000000001  x14: 0x01e8540001e85400  x15: 0x0000000000000000
   x16: 0xffffffffffffffe1  x17: 0x00000000ffffffff  x18: 0x0000000000000000  x19: 0x0000000000000000
   x20: 0x00000000ffffffff  x21: 0x0000000000002b03  x22: 0x0000000000000c00  x23: 0x000000016d3aed38
   x24: 0x0000000007000806  x25: 0x0000000000000000  x26: 0x0000000007000806  x27: 0x0000000000000c00
   x28: 0x0000000000000001   fp: 0x000000016d3aec30   lr: 0x0000000183208a3c
    sp: 0x000000016d3aebe0   pc: 0x0000000183208bc4 cpsr: 0x60000000

Единственная часть моего кода, которая работает, это main.m, строка 22, которая

int retVal = UIApplicationMain(argc, argv, nil, @"PSSMyAppDelegate");  

Таким образом, я недоумеваю, как мое приложение может быть неоднократно убито из-за нарушения времени выполнения, когда кажется, что ни один из моих кодов на самом деле не работает. Есть ли в iOS 11 что-то новое, что может изменить поведение сторожевого таймера? Если нет, то как я могу определить, какая часть моего кода нарушает правила из-за слишком долгой работы?


person esilver    schedule 30.09.2017    source источник


Ответы (2)


Ваш поток 0 очень похож на сбой, который мы наблюдаем в iOS 11. Это наш:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib         0x00000001853c4bc4 mach_msg_trap + 8
1   libsystem_kernel.dylib         0x00000001853c4a3c mach_msg + 72
2   CoreFoundation                 0x0000000185875c4c __CFRunLoopServiceMachPort + 196
3   CoreFoundation                 0x0000000185873818 __CFRunLoopRun + 1424
4   CoreFoundation                 0x0000000185793e78 CFRunLoopRunSpecific + 436
5   GraphicsServices               0x0000000187628f84 GSEventRunModal + 100
6   UIKit                         0x000000018f5360bc UIApplicationMain + 208
7   TestCrashInBackground         0x0000000100e8dbac 0x100e88000 + 23468
8   libdyld.dylib                 0x00000001852b656c start + 4

Для нас проблема в том, что отображение уведомлений приводит к сбою приложения (когда приложение работает в фоновом режиме). Мы даже создали тестовое приложение (TestCrashInBackground, которое вы видите выше), в котором мы можем воспроизвести эту проблему. Приложение отображает только уведомление и не имеет фоновых задач. Тестовый пример:

  1. Приложение показывает уведомление
  2. Пользователь запускает приложение в фоновом режиме (нажимает клавишу «Домой»).
  3. Пользователь блокирует экран

Результат: ОС убивает приложение через некоторое (короткое) время.

Мы провели sysdiagnose после того, как это произошло, и мы видим, что когда мы отображаем уведомление, добавляется утверждение с именем «будет представлять уведомление».

default 2017-10-03 14:32:16.280562 +0200    assertiond  [SpringBoard:53] Attempting to acquire assertion for TestCrashInBack:507: <BKProcessAssertion: 0x101235c90; "will present notification" (notificationAction:30s); id:…E1D79D51D1D9>
default 2017-10-03 14:32:16.281283 +0200    assertiond  [TestCrashInBack:507] Add assertion: <BKProcessAssertion: 0x101235c90; id: 53-96A5F4EA-4C42-4675-97E4-E1D79D51D1D9; name: "will present notification"; state: active; reason: notificationAction; duration: 30.0s> {
    owner = <BSProcessHandle: 0x10110a810; SpringBoard:53; valid: YES>;
    flags = preventSuspend, preventThrottleDownUI, preventIdleSleep, preventSuspendOnSleep;
}

Примерно через 45 секунд приложение закрывается, потому что оно «имеет активные утверждения сверх разрешенного времени»:

default 2017-10-03 14:33:00.436085 +0200    assertiond  [TestCrashInBack:507] Forcing crash report with description: TestCrashInBack:507 has active assertions beyond permitted time: 
<BKProcessAssertion: 0x101235c90; "will present notification" (notificationAction:30s); id:…E1D79D51D1D9> (owner: SpringBoard:53)

Все это только для отображения уведомления... довольно серьезная ошибка!

Это код, который добавляет уведомление:

UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.body = NSLocalizedString(@"This is test notification", nil);

UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:content.body content:content trigger:[UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1.0 repeats:NO]];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    NSLog(@"display notification error:%@", error);
}];

Я отправил отчет об ошибке в Apple (id: 34788843) с нашим тестовым проектом и прикрепленным sysdiagnose. Надеюсь, они скоро решат этот вопрос.

person Lars    schedule 04.10.2017

Я разговаривал с инженером Apple, который описал проблему следующим образом — представьте, что у нас есть такой метод:

- (void)startTask {
   self.bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
      [application endBackgroundTask:self.bgTask];
      self.bgTask = UIBackgroundTaskInvalid;
   }];
}

Затем код вызывает его дважды (скажем, потому что мы получили два вызова didReceiveRemoteNotification):

[self startTask];
[self startTask];

По словам инженера, с которым мы говорили, приложение вылетит именно так, как мы видим.

Более того, технически наше приложение будет аварийно завершать работу каждый раз, когда мы создаем вторую задачу до завершения первой задачи. Если фоновые задачи напрямую не привязаны к какому-либо другому объекту, который непосредственно управляет их временем существования и не может «владеть» более чем одним (например, автономная операция, которая начинает одну задачу при создании и заканчивает ее при завершении/уничтожении), это очень трудно избежать проблемы «повторного входа в задачу».

Лучший вариант — полагаться на локальные переменные для истечения срока действия задачи, сохраняя переменные-члены вашего объекта вне обработчика истечения срока действия.

person esilver    schedule 07.10.2017