diff --git a/CHANGELOG.md b/CHANGELOG.md index c183c7a66..9a045a535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ Changelog ========= +## TBD + +### Enhancements + +* Add configuration option (`reportOOMs`) to disable out-of-memory (OOM) event + reporting, defaulting to enabled. + [#345](https://github.com/bugsnag/bugsnag-cocoa/pull/345) +* Disable background OOM reporting by default. It can be enabled using + `reportBackgroundOOMs`. + [#345](https://github.com/bugsnag/bugsnag-cocoa/pull/345) + ## 5.21.0 (2019-05-01) ### Enhancements diff --git a/Source/BSGOutOfMemoryWatchdog.m b/Source/BSGOutOfMemoryWatchdog.m index 1d28507db..dafc034de 100644 --- a/Source/BSGOutOfMemoryWatchdog.m +++ b/Source/BSGOutOfMemoryWatchdog.m @@ -158,7 +158,7 @@ - (BOOL)computeDidOOMLastLaunchWithConfig:(BugsnagConfiguration *)config { [appInfo valueForKey:(__bridge NSString *)kCFBundleVersionKey]; BOOL sameVersions = [lastBootOSVersion isEqualToString:osVersion] && [lastBootAppVersion isEqualToString:appVersion]; - BOOL shouldReport = config.reportBackgroundOOMs || lastBootInForeground; + BOOL shouldReport = config.reportOOMs && (config.reportBackgroundOOMs || lastBootInForeground); [self deleteSentinelFile]; return sameVersions && shouldReport; } diff --git a/Source/BugsnagConfiguration.h b/Source/BugsnagConfiguration.h index 090954475..213bac60c 100644 --- a/Source/BugsnagConfiguration.h +++ b/Source/BugsnagConfiguration.h @@ -160,7 +160,13 @@ NSArray *beforeSendSessionBlocks; /** * Whether the app should report out of memory events which terminate the app - * while the app is in the background. + * When NO, this setting overrides reportBackgroundOOMs. + */ +@property BOOL reportOOMs; + +/** + * Whether the app should report out of memory events which terminate the app + * while the app is in the background. This setting has no effect when reportOOMs is NO. */ @property BOOL reportBackgroundOOMs; diff --git a/Source/BugsnagConfiguration.m b/Source/BugsnagConfiguration.m index 457bfc284..0625a7829 100644 --- a/Source/BugsnagConfiguration.m +++ b/Source/BugsnagConfiguration.m @@ -68,7 +68,8 @@ - (id)init { _breadcrumbs = [BugsnagBreadcrumbs new]; _automaticallyCollectBreadcrumbs = YES; _shouldAutoCaptureSessions = YES; - _reportBackgroundOOMs = YES; + _reportBackgroundOOMs = NO; + _reportOOMs = YES; if ([NSURLSession class]) { _session = [NSURLSession diff --git a/Source/BugsnagNotifier.m b/Source/BugsnagNotifier.m index d99460793..3e2d25a0b 100644 --- a/Source/BugsnagNotifier.m +++ b/Source/BugsnagNotifier.m @@ -384,7 +384,7 @@ - (void)start { #endif _started = YES; - if (!bsg_ksmachisBeingTraced() && self.configuration.autoNotify) { + if (self.configuration.reportOOMs && !bsg_ksmachisBeingTraced() && self.configuration.autoNotify) { [self.oomWatchdog enable]; } diff --git a/Tests/BugsnagConfigurationTests.m b/Tests/BugsnagConfigurationTests.m index ad78c4dcc..32b353cd7 100644 --- a/Tests/BugsnagConfigurationTests.m +++ b/Tests/BugsnagConfigurationTests.m @@ -60,9 +60,14 @@ - (void)testDefaultSessionConfig { XCTAssertTrue([config shouldAutoCaptureSessions]); } +- (void)testDefaultReportOOMs { + BugsnagConfiguration *config = [BugsnagConfiguration new]; + XCTAssertTrue([config reportOOMs]); +} + - (void)testDefaultReportBackgroundOOMs { BugsnagConfiguration *config = [BugsnagConfiguration new]; - XCTAssertTrue([config reportBackgroundOOMs]); + XCTAssertFalse([config reportBackgroundOOMs]); } - (void)testErrorApiHeaders { diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj index e8ea26058..b2a6dc841 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 8A14F0F52282D4AE00337B05 /* ReportBackgroundOOMsEnabledScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A14F0F02282D4AD00337B05 /* ReportBackgroundOOMsEnabledScenario.m */; }; + 8A14F0F62282D4AE00337B05 /* ReportOOMsDisabledScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A14F0F22282D4AD00337B05 /* ReportOOMsDisabledScenario.m */; }; + 8A14F0F72282D4AE00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A14F0F32282D4AE00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m */; }; 8A22FC66225B598500CA8895 /* OOMScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A22FC65225B598500CA8895 /* OOMScenario.m */; }; 8A32DB8222424E3000EDD92F /* NSExceptionShiftScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A32DB8122424E3000EDD92F /* NSExceptionShiftScenario.m */; }; 8A42FD35225DEE04007AE561 /* SessionOOMScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A42FD33225DEE04007AE561 /* SessionOOMScenario.m */; }; @@ -63,6 +66,12 @@ /* Begin PBXFileReference section */ 4994F05E0421A0B037DD2CC5 /* Pods_iOSTestApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOSTestApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8A14F0EF2282D4AD00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h; sourceTree = ""; }; + 8A14F0F02282D4AD00337B05 /* ReportBackgroundOOMsEnabledScenario.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReportBackgroundOOMsEnabledScenario.m; sourceTree = ""; }; + 8A14F0F12282D4AD00337B05 /* ReportOOMsDisabledScenario.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReportOOMsDisabledScenario.h; sourceTree = ""; }; + 8A14F0F22282D4AD00337B05 /* ReportOOMsDisabledScenario.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReportOOMsDisabledScenario.m; sourceTree = ""; }; + 8A14F0F32282D4AE00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m; sourceTree = ""; }; + 8A14F0F42282D4AE00337B05 /* ReportBackgroundOOMsEnabledScenario.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReportBackgroundOOMsEnabledScenario.h; sourceTree = ""; }; 8A22FC62225B3E4800CA8895 /* ReportDidCrashScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportDidCrashScenario.swift; sourceTree = ""; }; 8A22FC64225B598500CA8895 /* OOMScenario.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OOMScenario.h; sourceTree = ""; }; 8A22FC65225B598500CA8895 /* OOMScenario.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OOMScenario.m; sourceTree = ""; }; @@ -220,6 +229,12 @@ F42953DE2BB41023C0B07F41 /* scenarios */ = { isa = PBXGroup; children = ( + 8A14F0F42282D4AE00337B05 /* ReportBackgroundOOMsEnabledScenario.h */, + 8A14F0F02282D4AD00337B05 /* ReportBackgroundOOMsEnabledScenario.m */, + 8A14F0EF2282D4AD00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h */, + 8A14F0F32282D4AE00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m */, + 8A14F0F12282D4AD00337B05 /* ReportOOMsDisabledScenario.h */, + 8A14F0F22282D4AD00337B05 /* ReportOOMsDisabledScenario.m */, 8A32DB8022424E3000EDD92F /* NSExceptionShiftScenario.h */, 8A32DB8122424E3000EDD92F /* NSExceptionShiftScenario.m */, 8A840FB921AF5C450041DBFA /* SwiftAssertion.swift */, @@ -425,6 +440,7 @@ F42955E0916B8851F074D9B3 /* UserEmailScenario.swift in Sources */, F4295968571A4118D6A4606A /* UserEnabledScenario.swift in Sources */, F4295A036B228AF608641699 /* UserDisabledScenario.swift in Sources */, + 8A14F0F62282D4AE00337B05 /* ReportOOMsDisabledScenario.m in Sources */, E7767F13221C21E30006648C /* ResumedSessionScenario.swift in Sources */, 8AEFC73120F8D1A000A78779 /* AutoSessionWithUserScenario.m in Sources */, 8AF6FD7A225E3FA00056EF9E /* ResumeSessionOOMScenario.m in Sources */, @@ -447,6 +463,7 @@ F429538D8941382EC2C857CE /* AsyncSafeThreadScenario.m in Sources */, F42955869D33EE0E510B9651 /* ReadGarbagePointerScenario.m in Sources */, 8AEFC73420F8D1BB00A78779 /* ManualSessionWithUserScenario.m in Sources */, + 8A14F0F72282D4AE00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m in Sources */, F4295B56219D228FAA99BC14 /* ObjCExceptionScenario.m in Sources */, F4295218A62E41518DC3C057 /* AccessNonObjectScenario.m in Sources */, F4295262625F84A80282E520 /* CorruptMallocScenario.m in Sources */, @@ -460,6 +477,7 @@ F42951BEB2518C610A85FE0D /* BuiltinTrapScenario.m in Sources */, 8AEFC79C20F92E2200A78779 /* AutoSessionUnhandledScenario.m in Sources */, F4295397AD31C1C1E64144F5 /* NonExistentMethodScenario.m in Sources */, + 8A14F0F52282D4AE00337B05 /* ReportBackgroundOOMsEnabledScenario.m in Sources */, 8AEFC79920F9132C00A78779 /* AutoSessionHandledEventsScenario.m in Sources */, F4295A0B0DA0AF3B5502D29C /* PrivilegedInstructionScenario.m in Sources */, F42958BE5DDACDBF653CA926 /* ManualSessionScenario.m in Sources */, diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.h b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.h new file mode 100644 index 000000000..c5cec1ce0 --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.h @@ -0,0 +1,5 @@ +#import "Scenario.h" + +@interface ReportBackgroundOOMsEnabledScenario : Scenario + +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.m new file mode 100644 index 000000000..c641d7ab4 --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.m @@ -0,0 +1,19 @@ +#import "ReportBackgroundOOMsEnabledScenario.h" +#import + +@implementation ReportBackgroundOOMsEnabledScenario + +- (void)startBugsnag { + self.config.shouldAutoCaptureSessions = NO; + self.config.reportBackgroundOOMs = YES; + [super startBugsnag]; +} + +- (void)run { + [Bugsnag leaveBreadcrumbWithMessage:@"Crumb left before crash"]; + [Bugsnag configuration].releaseStage = @"beta"; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + raise(SIGKILL); + }); +} +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h new file mode 100644 index 000000000..ed06c27b4 --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h @@ -0,0 +1,5 @@ +#import "Scenario.h" + +@interface ReportOOMsDisabledReportBackgroundOOMsEnabledScenario : Scenario + +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m new file mode 100644 index 000000000..43822adfc --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m @@ -0,0 +1,18 @@ +#import "ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h" +#import + +@implementation ReportOOMsDisabledReportBackgroundOOMsEnabledScenario + +- (void)startBugsnag { + self.config.shouldAutoCaptureSessions = NO; + self.config.reportOOMs = NO; + self.config.reportBackgroundOOMs = YES; + [super startBugsnag]; +} + +- (void)run { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + raise(SIGKILL); + }); +} +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.h b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.h new file mode 100644 index 000000000..274f33e0c --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.h @@ -0,0 +1,5 @@ +#import "Scenario.h" + +@interface ReportOOMsDisabledScenario : Scenario + +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.m new file mode 100644 index 000000000..bb889a4ff --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.m @@ -0,0 +1,18 @@ + +#import "ReportOOMsDisabledScenario.h" +#import + +@implementation ReportOOMsDisabledScenario + +- (void)startBugsnag { + self.config.shouldAutoCaptureSessions = NO; + self.config.reportOOMs = NO; + [super startBugsnag]; +} + +- (void)run { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + raise(SIGKILL); + }); +} +@end diff --git a/features/oom.feature b/features/oom.feature index 85cf45070..49d251e7c 100644 --- a/features/oom.feature +++ b/features/oom.feature @@ -23,6 +23,13 @@ Feature: Reporting out of memory events And I put the app in the background And I wait for 4 seconds And I relaunch the app + Then I should receive 0 requests + + Scenario: The OS kills the application in the background and reportBackgroundOOMs is true + When I crash the app using "ReportBackgroundOOMsEnabledScenario" + And I put the app in the background + And I wait for 4 seconds + And I relaunch the app Then I should receive a request And the request is a valid for the error reporting API And the payload field "events" is an array with 1 element @@ -79,3 +86,23 @@ Feature: Reporting out of memory events And the payload field "events.0.session.events.unhandled" equals 1 for request 2 And the payload field "events.0.session.id" of request 1 equals the payload field "sessions.0.id" of request 0 And the payload field "events.0.session.id" of request 1 equals the payload field "events.0.session.id" of request 2 + + Scenario: The OS kills the application in the foreground when reportOOMs is false + When I crash the app using "ReportOOMsDisabledScenario" + And I wait for 4 seconds + And I relaunch the app + Then I should receive 0 requests + + Scenario: The OS kills the application in the background when reportOOMs is false + When I crash the app using "ReportOOMsDisabledScenario" + And I put the app in the background + And I wait for 4 seconds + And I relaunch the app + Then I should receive 0 requests + + Scenario: The OS kills the application in the background when reportOOMs is false and reportBackgroundOOMs is true + When I crash the app using "ReportOOMsDisabledReportBackgroundOOMsEnabledScenario" + And I put the app in the background + And I wait for 4 seconds + And I relaunch the app + Then I should receive 0 requests