Mitigate upload failure when app is backgrounded.
iOS closes an app’s network connections when the app is backgrounded. This can cause an in-progress upload request to fail. We can mitigate this by requesting additional background execution time using the `UIApplication` background task APIs. BUG=b:130302235 Change-Id: Ifd8e14ca82c736ad7dd60dcdd0d4bbcabb76f5ad Signed-off-by: Darren Mo <darrenmo@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2251020 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
dbbdf05740
commit
7ba29f4a36
2 changed files with 72 additions and 9 deletions
|
@ -59,6 +59,8 @@
|
|||
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
|
||||
CF6D547D1F9E6FFE00E95174 /* long_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */; };
|
||||
CF706DC11F7C6EFB002C54C7 /* long_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */; };
|
||||
E69213D8265202570071B04F /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = E69213D6265202570071B04F /* HTTPRequest.h */; };
|
||||
E69213D9265202570071B04F /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E69213D7265202570071B04F /* HTTPRequest.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
|
@ -116,6 +118,8 @@
|
|||
CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = long_string_dictionary.cc; sourceTree = "<group>"; };
|
||||
CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = long_string_dictionary.h; sourceTree = "<group>"; };
|
||||
D2AAC07E0554694100DB518D /* libBreakpad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBreakpad.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E69213D6265202570071B04F /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; };
|
||||
E69213D7265202570071B04F /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -289,6 +293,8 @@
|
|||
children = (
|
||||
16C7CC88147D4A4300776EAD /* GTMLogger.h */,
|
||||
16C7CC89147D4A4300776EAD /* GTMLogger.m */,
|
||||
E69213D6265202570071B04F /* HTTPRequest.h */,
|
||||
E69213D7265202570071B04F /* HTTPRequest.m */,
|
||||
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */,
|
||||
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */,
|
||||
16C7CC93147D4A4300776EAD /* file_id.cc */,
|
||||
|
@ -335,6 +341,7 @@
|
|||
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */,
|
||||
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */,
|
||||
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */,
|
||||
E69213D8265202570071B04F /* HTTPRequest.h in Headers */,
|
||||
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */,
|
||||
16C7CE84147D4A4300776EAD /* file_id.h in Headers */,
|
||||
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */,
|
||||
|
@ -416,6 +423,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */,
|
||||
E69213D9265202570071B04F /* HTTPRequest.m in Sources */,
|
||||
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */,
|
||||
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */,
|
||||
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */,
|
||||
|
|
|
@ -32,8 +32,26 @@
|
|||
#include <Availability.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0)
|
||||
#import <UIKit/UIKit.h>
|
||||
#define HAS_BACKGROUND_TASK_API 1
|
||||
#else
|
||||
#define HAS_BACKGROUND_TASK_API 0
|
||||
#endif
|
||||
|
||||
#import "encoding_util.h"
|
||||
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
|
||||
(defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
|
||||
defined(MAC_OS_X_VERSION_10_11) && \
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
|
||||
#define USE_NSURLSESSION 1
|
||||
#else
|
||||
#define USE_NSURLSESSION 0
|
||||
#endif
|
||||
|
||||
// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
|
||||
// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
|
||||
// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
|
||||
|
@ -41,20 +59,17 @@
|
|||
static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
|
||||
NSURLResponse** outResponse,
|
||||
NSError** outError) {
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
|
||||
(defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
|
||||
defined(MAC_OS_X_VERSION_10_11) && \
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
|
||||
#if USE_NSURLSESSION
|
||||
__block NSData* result = nil;
|
||||
__block NSError* error = nil;
|
||||
__block NSURLResponse* response = nil;
|
||||
dispatch_semaphore_t waitSemaphone = dispatch_semaphore_create(0);
|
||||
|
||||
NSURLSessionConfiguration* config =
|
||||
[NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
[config setTimeoutIntervalForRequest:240.0];
|
||||
NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
|
||||
[[session
|
||||
NSURLSessionDataTask *task = [session
|
||||
dataTaskWithRequest:req
|
||||
completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) {
|
||||
if (outError)
|
||||
|
@ -64,19 +79,59 @@ static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
|
|||
if (err == nil)
|
||||
result = [data retain];
|
||||
dispatch_semaphore_signal(waitSemaphone);
|
||||
}] resume];
|
||||
}];
|
||||
[task resume];
|
||||
|
||||
#if HAS_BACKGROUND_TASK_API
|
||||
// Used to guard against ending the background task twice, which UIKit
|
||||
// considers to be an error.
|
||||
__block BOOL isBackgroundTaskActive = YES;
|
||||
__block UIBackgroundTaskIdentifier backgroundTaskIdentifier =
|
||||
UIBackgroundTaskInvalid;
|
||||
backgroundTaskIdentifier = [UIApplication.sharedApplication
|
||||
beginBackgroundTaskWithName:@"Breakpad Upload"
|
||||
expirationHandler:^{
|
||||
if (!isBackgroundTaskActive) {
|
||||
return;
|
||||
}
|
||||
isBackgroundTaskActive = NO;
|
||||
|
||||
[task cancel];
|
||||
[UIApplication.sharedApplication
|
||||
endBackgroundTask:backgroundTaskIdentifier];
|
||||
}];
|
||||
#endif // HAS_BACKGROUND_TASK_API
|
||||
|
||||
dispatch_semaphore_wait(waitSemaphone, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(waitSemaphone);
|
||||
|
||||
#if HAS_BACKGROUND_TASK_API
|
||||
if (backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
|
||||
// Dispatch to main queue in order to synchronize access to
|
||||
// `isBackgroundTaskActive` with the background task expiration handler,
|
||||
// which is always run on the main thread.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!isBackgroundTaskActive) {
|
||||
return;
|
||||
}
|
||||
isBackgroundTaskActive = NO;
|
||||
|
||||
[UIApplication.sharedApplication
|
||||
endBackgroundTask:backgroundTaskIdentifier];
|
||||
});
|
||||
}
|
||||
#endif // HAS_BACKGROUND_TASK_API
|
||||
|
||||
if (outError)
|
||||
*outError = [error autorelease];
|
||||
if (outResponse)
|
||||
*outResponse = [response autorelease];
|
||||
return [result autorelease];
|
||||
#else
|
||||
#else // USE_NSURLSESSION
|
||||
return [NSURLConnection sendSynchronousRequest:req
|
||||
returningResponse:outResponse
|
||||
error:outError];
|
||||
#endif
|
||||
#endif // USE_NSURLSESSION
|
||||
}
|
||||
|
||||
@implementation HTTPRequest
|
||||
|
|
Loading…
Reference in a new issue