| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #if !defined(NDEBUG) | |
| 6 | |
| 7 #import "ios/chrome/app/UIApplication+ExitsOnSuspend.h" | |
| 8 | |
| 9 #include "base/ios/block_types.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/threading/thread_restrictions.h" | |
| 12 | |
| 13 NSString* const kExitsOnSuspend = @"EnableExitsOnSuspend"; | |
| 14 | |
| 15 namespace { | |
| 16 int backgroundTasksCount = 0; | |
| 17 UIBackgroundTaskIdentifier countTaskIdentifier = UIBackgroundTaskInvalid; | |
| 18 | |
| 19 // Perform a block on the main thread. Asynchronously if the thread is not the | |
| 20 // main thread, synchronously if the thread is the main thread. | |
| 21 void ExecuteBlockOnMainThread(ProceduralBlock block) { | |
| 22 if ([NSThread isMainThread]) | |
| 23 block(); | |
| 24 else | |
| 25 dispatch_async(dispatch_get_main_queue(), block); | |
| 26 } | |
| 27 } // namespace | |
| 28 | |
| 29 // Category defining interposing methods. These methods keep a tally of the | |
| 30 // background tasks count. | |
| 31 @implementation UIApplication (BackgroundTasksCounter) | |
| 32 | |
| 33 // Method to replace -beginBackgroundTaskWithExpirationHandler:. The original | |
| 34 // method is called within. | |
| 35 - (UIBackgroundTaskIdentifier) | |
| 36 cr_interpose_beginBackgroundTaskWithExpirationHandler: | |
| 37 (ProceduralBlock)handler { | |
| 38 UIBackgroundTaskIdentifier identifier = | |
| 39 [self cr_interpose_beginBackgroundTaskWithExpirationHandler:handler]; | |
| 40 if (identifier != UIBackgroundTaskInvalid) { | |
| 41 ExecuteBlockOnMainThread(^{ | |
| 42 backgroundTasksCount++; | |
| 43 }); | |
| 44 } | |
| 45 return identifier; | |
| 46 } | |
| 47 | |
| 48 // Method to replace -endBackgroundTask:. The original method is called within. | |
| 49 - (void)cr_interpose_endBackgroundTask:(UIBackgroundTaskIdentifier)identifier { | |
| 50 if (identifier != UIBackgroundTaskInvalid) | |
| 51 ExecuteBlockOnMainThread(^{ | |
| 52 backgroundTasksCount--; | |
| 53 }); | |
| 54 [self cr_interpose_endBackgroundTask:identifier]; | |
| 55 } | |
| 56 | |
| 57 @end | |
| 58 | |
| 59 @interface UIApplication (ExitsOnSuspend_Private) | |
| 60 // Terminate the app immediately. exit(0) is used. | |
| 61 - (void)cr_terminateImmediately; | |
| 62 // Terminate the app via -cr_terminateImmediately when the background tasks | |
| 63 // count is one. The remaining task is the count observation task. | |
| 64 - (void)cr_terminateWhenCountIsOne; | |
| 65 @end | |
| 66 | |
| 67 @implementation UIApplication (ExitsOnSuspend) | |
| 68 | |
| 69 - (void)cr_terminateWhenDoneWithBackgroundTasks { | |
| 70 // Add a background task for the count observation. | |
| 71 DCHECK(countTaskIdentifier == UIBackgroundTaskInvalid); | |
| 72 countTaskIdentifier = [self beginBackgroundTaskWithExpirationHandler:^{ | |
| 73 // If we get to the end of the 10 minutes, exit. | |
| 74 [self cr_terminateImmediately]; | |
| 75 }]; | |
| 76 | |
| 77 [self cr_terminateWhenCountIsOne]; | |
| 78 } | |
| 79 | |
| 80 - (void)cr_cancelTermination { | |
| 81 [NSObject | |
| 82 cancelPreviousPerformRequestsWithTarget:self | |
| 83 selector:@selector( | |
| 84 cr_terminateWhenCountIsOne) | |
| 85 object:nil]; | |
| 86 | |
| 87 // Cancel the count observation background task. | |
| 88 [self endBackgroundTask:countTaskIdentifier]; | |
| 89 countTaskIdentifier = UIBackgroundTaskInvalid; | |
| 90 } | |
| 91 | |
| 92 #pragma mark - Private | |
| 93 | |
| 94 - (void)cr_terminateImmediately { | |
| 95 DVLOG(1) << "App exited when suspended after running background tasks."; | |
| 96 // exit(0) will trigger at_exit handlers. Some need to be run on a IOAllowed | |
| 97 // thread, such as file_util::MemoryMappedFile::CloseHandles(). | |
| 98 base::ThreadRestrictions::SetIOAllowed(true); | |
| 99 exit(0); | |
| 100 } | |
| 101 | |
| 102 - (void)cr_terminateWhenCountIsOne { | |
| 103 if (backgroundTasksCount <= 1) | |
| 104 [self cr_terminateImmediately]; | |
| 105 [self performSelector:_cmd withObject:nil afterDelay:1]; | |
| 106 } | |
| 107 | |
| 108 @end | |
| 109 | |
| 110 #endif // !defined(NDEBUG) | |
| OLD | NEW |