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 */; };
|
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 */; };
|
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 */; };
|
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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference 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>"; };
|
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>"; };
|
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; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -289,6 +293,8 @@
|
||||||
children = (
|
children = (
|
||||||
16C7CC88147D4A4300776EAD /* GTMLogger.h */,
|
16C7CC88147D4A4300776EAD /* GTMLogger.h */,
|
||||||
16C7CC89147D4A4300776EAD /* GTMLogger.m */,
|
16C7CC89147D4A4300776EAD /* GTMLogger.m */,
|
||||||
|
E69213D6265202570071B04F /* HTTPRequest.h */,
|
||||||
|
E69213D7265202570071B04F /* HTTPRequest.m */,
|
||||||
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */,
|
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */,
|
||||||
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */,
|
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */,
|
||||||
16C7CC93147D4A4300776EAD /* file_id.cc */,
|
16C7CC93147D4A4300776EAD /* file_id.cc */,
|
||||||
|
@ -335,6 +341,7 @@
|
||||||
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */,
|
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */,
|
||||||
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */,
|
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */,
|
||||||
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */,
|
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */,
|
||||||
|
E69213D8265202570071B04F /* HTTPRequest.h in Headers */,
|
||||||
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */,
|
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */,
|
||||||
16C7CE84147D4A4300776EAD /* file_id.h in Headers */,
|
16C7CE84147D4A4300776EAD /* file_id.h in Headers */,
|
||||||
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */,
|
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */,
|
||||||
|
@ -416,6 +423,7 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */,
|
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */,
|
||||||
|
E69213D9265202570071B04F /* HTTPRequest.m in Sources */,
|
||||||
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */,
|
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */,
|
||||||
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */,
|
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */,
|
||||||
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */,
|
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */,
|
||||||
|
|
|
@ -32,8 +32,26 @@
|
||||||
#include <Availability.h>
|
#include <Availability.h>
|
||||||
#include <AvailabilityMacros.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"
|
#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
|
// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
|
||||||
// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
|
// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
|
||||||
// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
|
// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
|
||||||
|
@ -41,20 +59,17 @@
|
||||||
static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
|
static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
|
||||||
NSURLResponse** outResponse,
|
NSURLResponse** outResponse,
|
||||||
NSError** outError) {
|
NSError** outError) {
|
||||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
|
#if USE_NSURLSESSION
|
||||||
__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)
|
|
||||||
__block NSData* result = nil;
|
__block NSData* result = nil;
|
||||||
__block NSError* error = nil;
|
__block NSError* error = nil;
|
||||||
__block NSURLResponse* response = nil;
|
__block NSURLResponse* response = nil;
|
||||||
dispatch_semaphore_t waitSemaphone = dispatch_semaphore_create(0);
|
dispatch_semaphore_t waitSemaphone = dispatch_semaphore_create(0);
|
||||||
|
|
||||||
NSURLSessionConfiguration* config =
|
NSURLSessionConfiguration* config =
|
||||||
[NSURLSessionConfiguration defaultSessionConfiguration];
|
[NSURLSessionConfiguration defaultSessionConfiguration];
|
||||||
[config setTimeoutIntervalForRequest:240.0];
|
[config setTimeoutIntervalForRequest:240.0];
|
||||||
NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
|
NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
|
||||||
[[session
|
NSURLSessionDataTask *task = [session
|
||||||
dataTaskWithRequest:req
|
dataTaskWithRequest:req
|
||||||
completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) {
|
completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) {
|
||||||
if (outError)
|
if (outError)
|
||||||
|
@ -64,19 +79,59 @@ static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
|
||||||
if (err == nil)
|
if (err == nil)
|
||||||
result = [data retain];
|
result = [data retain];
|
||||||
dispatch_semaphore_signal(waitSemaphone);
|
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_semaphore_wait(waitSemaphone, DISPATCH_TIME_FOREVER);
|
||||||
dispatch_release(waitSemaphone);
|
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)
|
if (outError)
|
||||||
*outError = [error autorelease];
|
*outError = [error autorelease];
|
||||||
if (outResponse)
|
if (outResponse)
|
||||||
*outResponse = [response autorelease];
|
*outResponse = [response autorelease];
|
||||||
return [result autorelease];
|
return [result autorelease];
|
||||||
#else
|
#else // USE_NSURLSESSION
|
||||||
return [NSURLConnection sendSynchronousRequest:req
|
return [NSURLConnection sendSynchronousRequest:req
|
||||||
returningResponse:outResponse
|
returningResponse:outResponse
|
||||||
error:outError];
|
error:outError];
|
||||||
#endif
|
#endif // USE_NSURLSESSION
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation HTTPRequest
|
@implementation HTTPRequest
|
||||||
|
|
Loading…
Reference in a new issue