开发者

UIKitBackgroundCompletionTask - iPhone application crash

开发者 https://www.devze.com 2023-02-05 03:06 出处:网络
I\'m facing a problem, without any solution (yet). I\'m using a background task handler to start some data fetching, after the user press the Home button. The code is something like:

I'm facing a problem, without any solution (yet). I'm using a background task handler to start some data fetching, after the user press the Home button. The code is something like:

-(void)startRequest {
    UIApplication *app = [UIApplication sharedApplication];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
        dispatch_async(dispatch_get_main_queue(), ^{
                [app endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
            });
    }];
    开发者_运维问答//..
    //Fetch data with NSURLRequest / delegate method
    //..
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    if ([delegate respondsToSelector:delegateErrorMethod])
        [delegate performSelector:delegateErrorMethod];

    UIApplication *app = [UIApplication sharedApplication];
    if (bgTask != UIBackgroundTaskInvalid) {
       dispatch_async(dispatch_get_main_queue(), ^{
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        });
    }
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if([delegate respondsToSelector:delegateMethod])
        [delegate performSelector:delegateMethod withObject:self];  

    UIApplication *app = [UIApplication sharedApplication];
    if (bgTask != UIBackgroundTaskInvalid) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        });
    }
}

It works great, but sometimes (without any issue or reason, so it's really unpredictable) the application crash with the following crash log:

Application Specific Information:
MyBackgroundTest[7745] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0x90e65e0> identifier: UIKitBackgroundCompletionTask process: MyBackgroundTest[7745] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:7745 preventSuspend  preventIdleSleep 
)}

Elapsed total CPU time (seconds): 0.010 (user 0.010, system 0.000), 100% CPU 
Elapsed application CPU time (seconds): 0.000, 0% CPU

Thread 0:
0   libSystem.B.dylib               0x33b5d268 mach_msg_trap + 20
1   libSystem.B.dylib               0x33b5f354 mach_msg + 44
2   CoreFoundation                  0x33a48648 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x33a47ed2 __CFRunLoopRun + 350
4   CoreFoundation                  0x33a47c80 CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x33a47b88 CFRunLoopRunInMode + 52
6   GraphicsServices                0x33b0e4a4 GSEventRunModal + 108
7   GraphicsServices                0x33b0e550 GSEventRun + 56
8   UIKit                           0x32099322 -[UIApplication _run] + 406
9   UIKit                           0x32096e8c UIApplicationMain + 664
10  MyBackgroundTest                0x00002d64 0x1000 + 7524
11  MyBackgroundTest                0x00002d18 0x1000 + 7448

Thread 1:
0   libSystem.B.dylib               0x33b89974 kevent + 24
1   libSystem.B.dylib               0x33c33704 _dispatch_mgr_invoke + 88
2   libSystem.B.dylib               0x33c33174 _dispatch_queue_invoke + 96
3   libSystem.B.dylib               0x33c32b98 _dispatch_worker_thread2 + 120
4   libSystem.B.dylib               0x33bd724a _pthread_wqthread + 258
5   libSystem.B.dylib               0x33bcf970 start_wqthread + 0

Thread 2:
0   libSystem.B.dylib               0x33b5d268 mach_msg_trap + 20
1   libSystem.B.dylib               0x33b5f354 mach_msg + 44
2   CoreFoundation                  0x33a48648 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x33a47ed2 __CFRunLoopRun + 350
4   CoreFoundation                  0x33a47c80 CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x33a47b88 CFRunLoopRunInMode + 52
6   WebCore                         0x304df124 RunWebThread(void*) + 332
7   libSystem.B.dylib               0x33bd6886 _pthread_start + 242
8   libSystem.B.dylib               0x33bcba88 thread_start + 0

Thread 3:
0   libSystem.B.dylib               0x33b5d268 mach_msg_trap + 20
1   libSystem.B.dylib               0x33b5f354 mach_msg + 44
2   CoreFoundation                  0x33a48648 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x33a47ed2 __CFRunLoopRun + 350
4   CoreFoundation                  0x33a47c80 CFRunLoopRunSpecific + 224
5   CoreFoundation                  0x33a47b88 CFRunLoopRunInMode + 52
6   Foundation                      0x336465f6 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 206
7   Foundation                      0x33624192 -[NSThread main] + 38
8   Foundation                      0x3361d242 __NSThread__main__ + 966
9   libSystem.B.dylib               0x33bd6886 _pthread_start + 242
10  libSystem.B.dylib               0x33bcba88 thread_start + 0

Thread 4:
0   libSystem.B.dylib               0x33b8168c select$DARWIN_EXTSN + 20
1   CoreFoundation                  0x33a7f662 __CFSocketManager + 582
2   libSystem.B.dylib               0x33bd6886 _pthread_start + 242
3   libSystem.B.dylib               0x33bcba88 thread_start + 0

Thread 5:
0   libSystem.B.dylib               0x33bd79e0 __workq_kernreturn + 8
1   libSystem.B.dylib               0x33bd7364 _pthread_wqthread + 540
2   libSystem.B.dylib               0x33bcf970 start_wqthread + 0

Thread 6:
0   libSystem.B.dylib               0x33bd79e0 __workq_kernreturn + 8
1   libSystem.B.dylib               0x33bd7364 _pthread_wqthread + 540
2   libSystem.B.dylib               0x33bcf970 start_wqthread + 0

Unknown thread crashed with unknown flavor: 5, state_count: 1

UPDATE: Seems that a closer thread related to this issue is open here. The bug is related to redirect http connections, both async and sync NRURL operations. Perhaps, since NSURLConnection inherits from the foundation framework, then the bug is present on iPhone too?

openradar at: 1062401


My investigation shows that, whatever reason really is, you get the exception below:

TMS[13544] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0x8cb6040> identifier: UIKitBackgroundCompletionTask process: TMS[13544] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:13544 preventSuspend  preventIdleSleep 
)}

if the code doesn't execute`endBackgroundTask:' method.

This means that EVERY background task created with beginBackgroundTaskWithExpirationHandler:' call MUST be ended withendBackgroundTask:'. Double check that `endBackgroundTask:' is invoked with the correct task id.


This exception is caused when a background task is not ended in time. While I can't be 100% certain, I believe this particular crash is happening because of the block you pass into beginBackgroundTaskWithExpirationHandler: which is called if the connection hasn't finished yet and the system wants to end your background task.

UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    dispatch_async(dispatch_get_main_queue(), ^{
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        });
}];

The documentation of - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler says about handler: "You should use this handler to clean up and mark the end of the background task".

You aren't actually ending the task when this block is called because of the dispatch_async call. You don't end the task until after this block call returns (and your dispatch_async block runs). I believe that most of the time there is enough time for your second block to run before the watchdog shuts down your app, but sometimes there isn't. So what you should do is end the background task right away, then do a dispatch_async for any other cleanup you need to do:

UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier tid = bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:tid];
    dispatch_async(dispatch_get_main_queue(), ^{
            bgTask = UIBackgroundTaskInvalid;
        });
}];

In addition, the documentation says: "The handler is called synchronously on the main thread" so there really isn't any need for you to do the dispatch_async. You could just do:

UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}];
0

精彩评论

暂无评论...
验证码 换一张
取 消