├── .buildkite ├── block.step.yml ├── pipeline.full.yml ├── pipeline.yml └── pipeline_trigger.sh ├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ ├── A.md │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── SUPPORT.md ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── downstream_updates.yml │ ├── scorecard.yml │ └── signing.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── UPGRADING.md ├── bugsnag-android-core ├── CMakeLists.txt ├── README.md ├── api │ └── bugsnag-android-core.api ├── build.gradle.kts ├── detekt-baseline.xml ├── gradle.properties ├── lint-baseline.xml ├── proguard-rules.pro └── src │ ├── androidTest │ ├── AndroidManifest.xml │ └── java │ │ ├── android │ │ └── os │ │ │ └── strictmode │ │ │ └── FakeStrictModeViolation.kt │ │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── AppDataCollectorForegroundTest.kt │ │ ├── AppDataCollectorTest.kt │ │ ├── BreadcrumbFilterTest.kt │ │ ├── BreadcrumbStateTest.kt │ │ ├── BugsnagKotlinTestUtils.kt │ │ ├── BugsnagStoreMigratorTest.kt │ │ ├── ClientConfigTest.java │ │ ├── ClientContextInitTest.java │ │ ├── ClientTest.java │ │ ├── ClientUserTest.kt │ │ ├── DeviceIdStoreTest.kt │ │ ├── EventPayloadTest.java │ │ ├── EventStoreConfinementTest.kt │ │ ├── FileStoreTest.kt │ │ ├── LastRunInfoStoreTest.kt │ │ ├── ManifestConfigLoaderTest.kt │ │ ├── MemoryTrimTest.java │ │ ├── NativeInterfaceTest.java │ │ ├── ObserverInterfaceTest.java │ │ ├── OnBreadcrumbCallbackStateTest.java │ │ ├── ProjectPackagesTest.kt │ │ ├── SessionLegacyPayloadTest.java │ │ ├── SessionPayloadTest.kt │ │ ├── SessionTrackerConfinementTest.kt │ │ ├── StrictModeTest.java │ │ ├── StrictModeViolationTest.kt │ │ ├── StrictModeWrapper.java │ │ ├── SynchronizedStreamableStoreTest.kt │ │ ├── ThreadStateTest.kt │ │ ├── UniqueOnErrorCallbackTest.java │ │ └── UserStoreTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── CMakeLists.txt │ ├── java │ │ └── com │ │ │ └── bugsnag │ │ │ └── android │ │ │ ├── ActivityBreadcrumbCollector.kt │ │ │ ├── App.kt │ │ │ ├── AppDataCollector.kt │ │ │ ├── AppWithState.kt │ │ │ ├── BaseObservable.kt │ │ │ ├── Breadcrumb.java │ │ │ ├── BreadcrumbInternal.kt │ │ │ ├── BreadcrumbState.kt │ │ │ ├── BreadcrumbType.kt │ │ │ ├── Bugsnag.java │ │ │ ├── BugsnagEventMapper.kt │ │ │ ├── BugsnagStateModule.kt │ │ │ ├── BugsnagThreadViolationListener.java │ │ │ ├── BugsnagVmViolationListener.java │ │ │ ├── CallbackAware.kt │ │ │ ├── CallbackState.kt │ │ │ ├── Client.java │ │ │ ├── ClientComponentCallbacks.kt │ │ │ ├── ClientObservable.kt │ │ │ ├── CollectionUtils.java │ │ │ ├── ConfigInternal.kt │ │ │ ├── Configuration.java │ │ │ ├── ConnectivityCompat.kt │ │ │ ├── ContextExtensions.kt │ │ │ ├── ContextState.kt │ │ │ ├── DataCollectionModule.kt │ │ │ ├── DebugLogger.kt │ │ │ ├── DefaultDelivery.kt │ │ │ ├── Deliverable.kt │ │ │ ├── Delivery.kt │ │ │ ├── DeliveryDelegate.java │ │ │ ├── DeliveryHeaders.kt │ │ │ ├── DeliveryParams.kt │ │ │ ├── DeliveryStatus.kt │ │ │ ├── Device.kt │ │ │ ├── DeviceBuildInfo.kt │ │ │ ├── DeviceDataCollector.kt │ │ │ ├── DeviceIdFilePersistence.kt │ │ │ ├── DeviceIdPersistence.kt │ │ │ ├── DeviceIdStore.kt │ │ │ ├── DeviceWithState.kt │ │ │ ├── EndpointConfiguration.kt │ │ │ ├── Error.java │ │ │ ├── ErrorInternal.kt │ │ │ ├── ErrorType.kt │ │ │ ├── ErrorTypes.kt │ │ │ ├── Event.java │ │ │ ├── EventFilenameInfo.kt │ │ │ ├── EventInternal.kt │ │ │ ├── EventPayload.kt │ │ │ ├── EventStorageModule.kt │ │ │ ├── EventStore.kt │ │ │ ├── ExceptionHandler.java │ │ │ ├── FeatureFlag.java │ │ │ ├── FeatureFlagAware.kt │ │ │ ├── FeatureFlagState.kt │ │ │ ├── FeatureFlags.kt │ │ │ ├── FileStore.kt │ │ │ ├── IOUtils.java │ │ │ ├── InternalReportDelegate.java │ │ │ ├── Intrinsics.java │ │ │ ├── JsonReadable.kt │ │ │ ├── JsonScope.java │ │ │ ├── JsonStream.java │ │ │ ├── JsonWriter.java │ │ │ ├── LastRunInfo.kt │ │ │ ├── LastRunInfoStore.kt │ │ │ ├── LaunchCrashTracker.kt │ │ │ ├── LibraryLoader.java │ │ │ ├── Logger.kt │ │ │ ├── ManifestConfigLoader.kt │ │ │ ├── MarshalledEventSource.kt │ │ │ ├── MemoryTrimState.kt │ │ │ ├── Metadata.kt │ │ │ ├── MetadataAware.kt │ │ │ ├── MetadataState.kt │ │ │ ├── NativeInterface.java │ │ │ ├── NativeStackframe.kt │ │ │ ├── NdkPluginCaller.kt │ │ │ ├── NoopLogger.kt │ │ │ ├── Notifier.kt │ │ │ ├── ObjectJsonStreamer.kt │ │ │ ├── OnBreadcrumbCallback.kt │ │ │ ├── OnErrorCallback.kt │ │ │ ├── OnSendCallback.kt │ │ │ ├── OnSessionCallback.kt │ │ │ ├── Plugin.kt │ │ │ ├── PluginClient.kt │ │ │ ├── RootDetector.kt │ │ │ ├── Session.java │ │ │ ├── SessionFilenameInfo.kt │ │ │ ├── SessionStore.kt │ │ │ ├── SessionTracker.java │ │ │ ├── Severity.kt │ │ │ ├── SeverityReason.java │ │ │ ├── SharedPrefMigrator.kt │ │ │ ├── Stackframe.kt │ │ │ ├── Stacktrace.kt │ │ │ ├── StateEvent.kt │ │ │ ├── StorageModule.kt │ │ │ ├── StrictModeHandler.java │ │ │ ├── StrictModeOnErrorCallback.kt │ │ │ ├── SynchronizedStreamableStore.kt │ │ │ ├── SystemBroadcastReceiver.kt │ │ │ ├── Telemetry.kt │ │ │ ├── Thread.java │ │ │ ├── ThreadInternal.kt │ │ │ ├── ThreadSendPolicy.kt │ │ │ ├── ThreadState.kt │ │ │ ├── ThrowableExtensions.kt │ │ │ ├── TraceCorrelation.kt │ │ │ ├── TrackerModule.kt │ │ │ ├── User.kt │ │ │ ├── UserAware.kt │ │ │ ├── UserState.kt │ │ │ ├── UserStore.kt │ │ │ └── internal │ │ │ ├── AbstractStartupProvider.kt │ │ │ ├── BackgroundTaskService.kt │ │ │ ├── BugsnagContentProvider.kt │ │ │ ├── BugsnagMapper.kt │ │ │ ├── BugsnagStoreMigrator.kt │ │ │ ├── ByteArrayExtensions.kt │ │ │ ├── DateUtils.kt │ │ │ ├── DexBuildIdGenerator.kt │ │ │ ├── FallbackWriter.kt │ │ │ ├── ForegroundDetector.kt │ │ │ ├── ImmutableConfig.kt │ │ │ ├── InternalMetrics.kt │ │ │ ├── InternalMetricsImpl.kt │ │ │ ├── InternalMetricsNoop.kt │ │ │ ├── JsonHelper.kt │ │ │ ├── StateObserver.kt │ │ │ ├── StringUtils.kt │ │ │ └── dag │ │ │ ├── ConfigModule.kt │ │ │ ├── ContextModule.kt │ │ │ ├── DependencyModule.kt │ │ │ ├── Provider.kt │ │ │ └── SystemServiceModule.kt │ └── jni │ │ └── root_detection.c │ ├── sharedTest │ └── java │ │ └── com │ │ └── bugsnag │ │ └── android │ │ └── BugsnagTestUtils.java │ └── test │ ├── java │ ├── android │ │ └── os │ │ │ └── strictmode │ │ │ └── FakeStrictModeViolation.kt │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── ActivityLifecycleBreadcrumbTest.kt │ │ ├── ApiKeyConfigValidationTest.kt │ │ ├── ApiKeyValidationTest.kt │ │ ├── AppDataCollectorSerializationTest.kt │ │ ├── AppMetadataSerializationTest.kt │ │ ├── BreadcrumbFacadeTest.java │ │ ├── BreadcrumbMutabilityTest.kt │ │ ├── BreadcrumbNullabilityTest.java │ │ ├── BreadcrumbSerializationTest.kt │ │ ├── BreadcrumbStateSerializationTest.kt │ │ ├── BreadcrumbStateTest.kt │ │ ├── BugsnagApiTest.kt │ │ ├── BugsnagClientMirrorInterfaceTest.kt │ │ ├── CallbackStateTest.kt │ │ ├── ClientComponentCallbacksMemoryCallbackTest.kt │ │ ├── ClientFacadeTest.java │ │ ├── ClientObservableTest.kt │ │ ├── CollectionUtilsTest.java │ │ ├── ConcurrentCallbackTest.java │ │ ├── ConfigApiTest.kt │ │ ├── ConfigChangeReceiverTest.kt │ │ ├── ConfigurationFacadeTest.java │ │ ├── ConfigurationTest.java │ │ ├── ConnectivityApi24Test.kt │ │ ├── ConnectivityCompatTest.kt │ │ ├── ConnectivityLegacyTest.kt │ │ ├── ContextExtensionsKtTest.kt │ │ ├── ContextStateTest.kt │ │ ├── DataCollectorTest.kt │ │ ├── DeliveryDelegateTest.kt │ │ ├── DeliveryHeadersTest.kt │ │ ├── DeliveryStatusTest.kt │ │ ├── DeviceDataCollectorSerializationTest.kt │ │ ├── DeviceMetadataSerializationTest.kt │ │ ├── DiscardTest.kt │ │ ├── EmptyEventCallbackTest.kt │ │ ├── EnabledErrorTypesTest.kt │ │ ├── EndpointConfigValidationTest.kt │ │ ├── ErrorFacadeTest.java │ │ ├── ErrorSerializationTest.kt │ │ ├── ErrorTest.kt │ │ ├── EventApiTest.kt │ │ ├── EventErrorTypeTest.kt │ │ ├── EventFacadeTest.java │ │ ├── EventFeatureFlagsCloneTest.kt │ │ ├── EventFilenameTest.kt │ │ ├── EventMetadataCloneTest.kt │ │ ├── EventNameTest.kt │ │ ├── EventPayloadSerializationTest.kt │ │ ├── EventPayloadTest.kt │ │ ├── EventPayloadTrimTest.kt │ │ ├── EventRedactionTest.kt │ │ ├── EventSerializationTest.kt │ │ ├── EventStateTest.java │ │ ├── EventStoreMaxLimitTest.kt │ │ ├── EventTest.java │ │ ├── ExceptionHandlerTest.kt │ │ ├── FeatureFlagStateTest.kt │ │ ├── FeatureFlagTest.java │ │ ├── FeatureFlagsSerializationTest.kt │ │ ├── FeatureFlagsTest.kt │ │ ├── ImmutableConfigTest.kt │ │ ├── InterceptingLogger.kt │ │ ├── InternalEventPayloadDelegateTest.kt │ │ ├── JsonParser.kt │ │ ├── JsonStreamFileTest.java │ │ ├── JsonStreamTest.kt │ │ ├── JsonUtils.kt │ │ ├── JsonWriterBugsnagTest.java │ │ ├── JsonWriterTest.java │ │ ├── LastRunInfoApiTest.java │ │ ├── LaunchCrashDeliveryTest.kt │ │ ├── LaunchCrashTrackerTest.kt │ │ ├── LibraryLoaderTest.kt │ │ ├── MemoryTrimStateTest.kt │ │ ├── MetadataConcurrentModificationTest.kt │ │ ├── MetadataMergeTest.kt │ │ ├── MetadataRedactionTest.java │ │ ├── MetadataSerializationTest.kt │ │ ├── MetadataStateTest.kt │ │ ├── NativeInterfaceApiTest.kt │ │ ├── NativeStackframeSerializationTest.kt │ │ ├── NotifierSerializationTest.kt │ │ ├── NullMetadataTest.java │ │ ├── OnErrorCallbackTest.kt │ │ ├── PluginClientTest.kt │ │ ├── RecursiveThrowableCauseTest.kt │ │ ├── RootDetectorTest.kt │ │ ├── SessionFacadeTest.java │ │ ├── SessionFilenameTest.kt │ │ ├── SessionSerializationTest.kt │ │ ├── SessionStoreMaxLimitTest.kt │ │ ├── SessionStoreTest.kt │ │ ├── SessionTest.kt │ │ ├── SessionTrackerPauseResumeTest.kt │ │ ├── SessionTrackerTest.java │ │ ├── SeverityReasonSerializationTest.kt │ │ ├── SeverityReasonTest.kt │ │ ├── SeveritySerializationTest.kt │ │ ├── SharedPrefMigratorTest.kt │ │ ├── StackframeSerializationTest.kt │ │ ├── StacktraceSerializationTest.kt │ │ ├── StacktraceTest.kt │ │ ├── StrictModeChainedListenerTest.kt │ │ ├── StrictModeFacadeTest.java │ │ ├── SystemBroadcastReceiverTest.kt │ │ ├── ThreadDeserializationTest.kt │ │ ├── ThreadFacadeTest.java │ │ ├── ThreadSendPolicyTest.kt │ │ ├── ThreadSerializationTest.kt │ │ ├── UnrollThrowableCausesTest.kt │ │ ├── UpdateMemoryTrimLevelTest.kt │ │ ├── UserSerializationTest.kt │ │ ├── UserStateTest.kt │ │ ├── UserTest.java │ │ └── internal │ │ ├── BackgroundRunnableProviderServiceTest.kt │ │ ├── BugsnagMapperTest.kt │ │ ├── DexBuildIdGeneratorTest.kt │ │ ├── ForegroundDetectorTest.kt │ │ ├── JsonHelperTest.kt │ │ └── StringUtilsTest.kt │ └── resources │ ├── app_data_serialization_0.json │ ├── app_data_serialization_1.json │ ├── app_meta_data_serialization_0.json │ ├── breadcrumb_serialization_0.json │ ├── breadcrumb_serialization_1.json │ ├── breadcrumb_state_serialization_0.json │ ├── com │ └── bugsnag │ │ └── android │ │ └── internal │ │ ├── classes.dex │ │ └── empty-app-debug.apk │ ├── device_data_serialization_0.json │ ├── device_data_serialization_1.json │ ├── device_metadata_serialization_0.json │ ├── error_serialization_0.json │ ├── error_serialization_1.json │ ├── error_serialization_2.json │ ├── event_default_redaction.json │ ├── event_redaction.json │ ├── event_serialization_0.json │ ├── event_serialization_1.json │ ├── event_serialization_2.json │ ├── event_serialization_3.json │ ├── event_serialization_4.json │ ├── event_serialization_5.json │ ├── event_serialization_6.json │ ├── event_serialization_7.json │ ├── event_serialization_8.json │ ├── feature_flags_serialization_0.json │ ├── feature_flags_serialization_1.json │ ├── feature_flags_serialization_2.json │ ├── json_stream.json │ ├── meta_data_serialization_0.json │ ├── meta_data_serialization_1.json │ ├── meta_data_serialization_2.json │ ├── meta_data_serialization_3.json │ ├── meta_data_serialization_4.json │ ├── metadata_redaction_0.json │ ├── metadata_redaction_1.json │ ├── metadata_redaction_2.json │ ├── metadata_redaction_3.json │ ├── metadata_redaction_4.json │ ├── mockito-extensions │ └── org.mockito.plugins.MockMaker │ ├── native_stackframe_serialization_0.json │ ├── native_stackframe_serialization_1.json │ ├── native_stackframe_serialization_2.json │ ├── notifier_serialization_0.json │ ├── notifier_serialization_1.json │ ├── null_json_stream.json │ ├── report_serialization_0.json │ ├── session_serialization_0.json │ ├── severity_reason_serialization_0.json │ ├── severity_reason_serialization_1.json │ ├── severity_reason_serialization_2.json │ ├── severity_reason_serialization_3.json │ ├── severity_reason_serialization_4.json │ ├── severity_reason_serialization_5.json │ ├── severity_reason_serialization_6.json │ ├── severity_reason_serialization_7.json │ ├── severity_reason_serialization_8.json │ ├── severity_reason_serialization_9.json │ ├── severity_serialization_0.json │ ├── severity_serialization_1.json │ ├── severity_serialization_2.json │ ├── stackframe_serialization_0.json │ ├── stackframe_serialization_1.json │ ├── stackframe_serialization_2.json │ ├── stackframe_serialization_3.json │ ├── stackframe_serialization_4.json │ ├── stacktrace_serialization_0.json │ ├── stacktrace_serialization_1.json │ ├── stacktrace_serialization_2.json │ ├── stacktrace_serialization_3.json │ ├── stacktrace_serialization_4.json │ ├── stacktrace_serialization_5.json │ ├── thread_deserialization_0.json │ ├── thread_deserialization_1.json │ ├── thread_deserialization_2.json │ ├── thread_serialization_0.json │ ├── thread_serialization_1.json │ ├── thread_serialization_2.json │ ├── thread_serialization_3.json │ └── user_serialization_0.json ├── bugsnag-android ├── README.md ├── build.gradle.kts ├── gradle.properties ├── lint-baseline.xml └── src │ └── main │ └── AndroidManifest.xml ├── bugsnag-benchmarks ├── benchmark-proguard-rules.pro ├── build.gradle └── src │ ├── androidTest │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── ClientHooks.kt │ │ ├── EventHooks.java │ │ └── benchmark │ │ ├── ClientDataBenchmarkTest.kt │ │ ├── CriticalPathBenchmarkTest.kt │ │ ├── EventBenchmarkTest.kt │ │ ├── JsonSerializationBenchmarkTest.kt │ │ └── SessionBenchmarkTest.kt │ └── main │ └── AndroidManifest.xml ├── bugsnag-plugin-android-anr ├── CMakeLists.txt ├── README.md ├── api │ └── bugsnag-plugin-android-anr.api ├── build.gradle.kts ├── detekt-baseline.xml ├── gradle.properties ├── lint-baseline.xml ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── CMakeLists.txt │ ├── java │ │ └── com │ │ │ └── bugsnag │ │ │ └── android │ │ │ ├── AnrDetailsCollector.kt │ │ │ └── AnrPlugin.kt │ └── jni │ │ ├── anr_google.c │ │ ├── anr_google.h │ │ ├── anr_handler.c │ │ ├── anr_handler.h │ │ ├── bsg_unwind.h │ │ ├── bugsnag_anr.c │ │ ├── include │ │ └── event.h │ │ ├── unwind_func.h │ │ └── utils │ │ ├── string.c │ │ └── string.h │ └── test │ └── java │ └── com │ └── bugsnag │ └── android │ └── AnrDetailsCollectorTest.kt ├── bugsnag-plugin-android-exitinfo ├── README.md ├── api │ └── bugsnag-plugin-android-exitinfo.api ├── build.gradle.kts ├── detekt-baseline.xml ├── gradle.properties ├── lint-baseline.xml ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── BugsnagExitInfoPluginStoreTest.kt │ │ └── TestHooks.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── bugsnag │ │ │ └── android │ │ │ ├── ApplicationExitInfoMatcher.kt │ │ │ ├── BugsnagExitInfoPlugin.kt │ │ │ ├── CodeStrings.kt │ │ │ ├── EventSynthesizer.kt │ │ │ ├── ExitInfoCallback.kt │ │ │ ├── ExitInfoKey.kt │ │ │ ├── ExitInfoPluginConfiguration.kt │ │ │ ├── ExitInfoPluginStore.kt │ │ │ ├── InternalHooks.java │ │ │ ├── TombstoneEventEnhancer.kt │ │ │ ├── TombstoneParser.kt │ │ │ ├── TraceEventEnhancer.kt │ │ │ └── TraceParser.kt │ └── proto │ │ └── tombstone.proto │ └── test │ ├── java │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── ExitInfoCallbackTest.kt │ │ ├── TombstoneEventEnhancerTest.kt │ │ ├── TombstoneParserTest.kt │ │ ├── TraceEventEnhancerTest.kt │ │ ├── TraceParserInvalidStackframesTest.kt │ │ ├── TraceParserJavaStackframeTest.kt │ │ ├── TraceParserNativeStackframeTest.kt │ │ └── TraceParserTest.kt │ └── resources │ ├── emulator-exit-anr-trace │ └── tombstone_01.pb ├── bugsnag-plugin-android-ndk ├── CMakeLists.txt ├── README.md ├── api │ └── bugsnag-plugin-android-ndk.api ├── build.gradle.kts ├── detekt-baseline.xml ├── gradle.properties ├── lint-baseline.xml ├── package.json ├── proguard-rules.pro └── src │ ├── androidTest │ ├── java │ │ └── com │ │ │ └── bugsnag │ │ │ └── android │ │ │ └── ndk │ │ │ ├── NativeBreadcrumbTest.kt │ │ │ ├── NativeEventAppMutatorsTest.kt │ │ │ ├── NativeEventDeviceMutatorsTest.kt │ │ │ ├── NativeEventMutatorsTest.kt │ │ │ ├── NativeFeatureFlagsTest.kt │ │ │ ├── NativeJsonSerializeTest.kt │ │ │ ├── NativeStringTest.kt │ │ │ ├── OpaqueValueTest.kt │ │ │ ├── ReportDiscardScannerTest.kt │ │ │ ├── ResourceUtils.kt │ │ │ ├── StartBugsnagTest.kt │ │ │ ├── UnwindTest.kt │ │ │ └── VerifyUtils.kt │ └── resources │ │ └── event_serialization.json │ ├── main │ ├── AndroidManifest.xml │ ├── CMakeLists.txt │ ├── exported_native_symbols-Debug.txt │ ├── exported_native_symbols-RelWithDebInfo.txt │ ├── java │ │ └── com │ │ │ └── bugsnag │ │ │ └── android │ │ │ ├── NdkPlugin.kt │ │ │ └── ndk │ │ │ ├── BugsnagNDK.kt │ │ │ ├── NativeBridge.kt │ │ │ ├── OpaqueValue.kt │ │ │ └── ReportDiscardScanner.kt │ └── jni │ │ ├── bsg_unwind.h │ │ ├── bugsnag.c │ │ ├── bugsnag_ndk.c │ │ ├── bugsnag_ndk.h │ │ ├── event.c │ │ ├── event.h │ │ ├── featureflags.c │ │ ├── featureflags.h │ │ ├── handlers │ │ ├── cpp_handler.cpp │ │ ├── cpp_handler.h │ │ ├── signal_handler.c │ │ └── signal_handler.h │ │ ├── include │ │ ├── bugsnag.h │ │ └── event.h │ │ ├── internal_metrics.c │ │ ├── internal_metrics.h │ │ ├── jni_cache.c │ │ ├── jni_cache.h │ │ ├── metadata.c │ │ ├── metadata.h │ │ ├── safejni.c │ │ ├── safejni.h │ │ └── utils │ │ ├── build.h │ │ ├── crash_info.c │ │ ├── crash_info.h │ │ ├── logger.h │ │ ├── memory.c │ │ ├── memory.h │ │ ├── seqlock.c │ │ ├── seqlock.h │ │ ├── serializer.c │ │ ├── serializer.h │ │ ├── serializer │ │ ├── BSG_KSCrashStringConversion.c │ │ ├── BSG_KSCrashStringConversion.h │ │ ├── BSG_KSJSONCodec.c │ │ ├── BSG_KSJSONCodec.h │ │ ├── buffered_writer.c │ │ ├── buffered_writer.h │ │ ├── event_writer.c │ │ └── event_writer.h │ │ ├── stack_unwinder.cpp │ │ ├── stack_unwinder.h │ │ ├── string.c │ │ ├── string.h │ │ ├── threads.c │ │ └── threads.h │ └── test │ ├── CMakeLists.txt │ └── cpp │ ├── UnwindTest.cpp │ ├── deps │ └── greatest │ │ ├── greatest.h │ │ └── package.json │ ├── main.c │ ├── parson │ ├── package.json │ ├── parson.c │ └── parson.h │ ├── test_breadcrumbs.c │ ├── test_bsg_event.c │ ├── test_bsg_event.h │ ├── test_featureflags.c │ ├── test_serializer.c │ ├── test_serializer.h │ ├── test_utils_serialize.c │ └── test_utils_string.c ├── bugsnag-plugin-android-okhttp ├── README.md ├── api │ └── bugsnag-plugin-android-okhttp.api ├── build.gradle.kts ├── detekt-baseline.xml ├── gradle.properties ├── lint-baseline.xml ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── BreadcrumbHooks.kt │ │ └── okhttp │ │ ├── BugsnagOkHttpPlugin.kt │ │ └── OkHttpDelivery.kt │ └── test │ └── java │ └── com │ └── bugsnag │ └── android │ ├── BugsnagOkHttpPluginTest.kt │ ├── CachedRequestIntegrationTest.kt │ ├── ClonedRequestTest.kt │ ├── ComplexRequestIntegrationTest.kt │ ├── GetRequestIntegrationTest.kt │ ├── NetworkBreadcrumbRequest.kt │ ├── PostRequestIntegrationTest.kt │ └── RedirectedRequestIntegrationTest.kt ├── bugsnag-plugin-react-native ├── README.md ├── api │ └── bugsnag-plugin-react-native.api ├── build.gradle.kts ├── detekt-baseline.xml ├── gradle.properties ├── lint-baseline.xml ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── AppDeserializer.java │ │ ├── AppSerializer.kt │ │ ├── BreadcrumbDeserializer.java │ │ ├── BreadcrumbSerializer.kt │ │ ├── BugsnagReactNativeBridge.kt │ │ ├── BugsnagReactNativePlugin.kt │ │ ├── ConfigSerializer.java │ │ ├── DeviceDeserializer.java │ │ ├── DeviceSerializer.kt │ │ ├── ErrorDeserializer.java │ │ ├── EventDeserializer.kt │ │ ├── InternalHooks.java │ │ ├── MapDeserializer.java │ │ ├── MapSerializer.java │ │ ├── MapUtils.java │ │ ├── MessageEvent.kt │ │ ├── MetadataDeserializer.java │ │ ├── NativeStackDeserializer.java │ │ ├── StackframeDeserializer.java │ │ ├── ThreadDeserializer.java │ │ ├── ThreadSerializer.kt │ │ └── UserDeserializer.java │ └── test │ ├── java │ └── com │ │ └── bugsnag │ │ └── android │ │ ├── AppDeserializerTest.kt │ │ ├── AppSerializerTest.java │ │ ├── BreadcrumbDeserializerTest.kt │ │ ├── BreadcrumbSerializerTest.java │ │ ├── BugsnagReactNativeBridgeTest.java │ │ ├── BugsnagReactNativePluginTest.kt │ │ ├── ConfigSerializerTest.java │ │ ├── DeviceDeserializerTest.kt │ │ ├── DeviceSerializerTest.java │ │ ├── ErrorDeserializerTest.kt │ │ ├── EventDeserializerTest.kt │ │ ├── LeaveBreadcrumbTest.kt │ │ ├── MetadataDeserializerTest.java │ │ ├── NativeStackDeserializerTest.kt │ │ ├── StackframeDeserializerTest.kt │ │ ├── TestData.java │ │ ├── TestHooks.java │ │ ├── ThreadDeserializerTest.kt │ │ ├── ThreadSerializerTest.java │ │ ├── UpdateMetadataTest.kt │ │ └── UserDeserializerTest.kt │ └── resources │ └── mockito-extensions │ └── org.mockito.plugins.MockMaker ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ ├── Checkstyle.kt │ ├── ProjectDefaults.kt │ └── Versions.kt ├── config ├── checkstyle │ └── checkstyle.xml └── detekt │ └── detekt.yml ├── docker-compose.yml ├── dockerfiles ├── Dockerfile.android-common ├── Dockerfile.android-license-audit └── Dockerfile.android-publisher ├── docs ├── BENCHMARKS.md ├── DEVELOPMENT.md ├── ENVIRONMENT_SETUP.md ├── MAZERUNNER.md ├── NEW_MODULE_CHECKLIST.md ├── PROJECT_STRUCTURE.md ├── README.md ├── RELEASING.md └── TESTING.md ├── examples └── sdk-app-example │ ├── .gitignore │ ├── README.md │ ├── app │ ├── .gitignore │ ├── CMakeLists.txt │ ├── build.gradle.kts │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── cpp │ │ └── entrypoint.cpp │ │ ├── ic_launcher-web.png │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ ├── bugsnag │ │ │ └── android │ │ │ │ ├── BaseCrashyActivity.kt │ │ │ │ ├── ExampleActivity.kt │ │ │ │ ├── ExampleApplication.kt │ │ │ │ ├── MultiProcessActivity.kt │ │ │ │ └── ProcessCompat.kt │ │ │ └── foo │ │ │ └── CrashyClass.java │ │ └── res │ │ ├── drawable │ │ └── ic_bugsnag_svg.xml │ │ ├── layout │ │ └── main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── build.gradle.kts │ ├── fakekeys.jks │ ├── gradle.properties │ ├── gradle │ ├── libs.versions.toml │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── lint-baseline.xml │ └── settings.gradle.kts ├── features ├── fixtures │ ├── fakekeys.jks │ ├── mazerunner │ │ ├── README.md │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── detekt-baseline.xml │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── bugsnag │ │ │ │ │ └── android │ │ │ │ │ ├── BugsnagInternals.java │ │ │ │ │ └── mazerunner │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ ├── MazerunnerApp.kt │ │ │ │ │ ├── NetworkStatus.kt │ │ │ │ │ ├── SecondActivity.kt │ │ │ │ │ ├── StartSessionBehaviour.kt │ │ │ │ │ └── StartupANRBehaviour.kt │ │ │ │ └── res │ │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ │ └── xml │ │ │ │ └── network_security_config.xml │ │ ├── bugsnag-dependency.gradle │ │ ├── build.gradle │ │ ├── config │ │ │ ├── checkstyle │ │ │ │ └── checkstyle.xml │ │ │ └── detekt │ │ │ │ └── detekt.yml │ │ ├── cxx-scenarios-bugsnag │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── build.gradle │ │ │ ├── detekt-baseline.xml │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── cpp │ │ │ │ ├── CXXExceptionSmokeScenario.cpp │ │ │ │ ├── CXXExternalStackElementScenario.cpp │ │ │ │ └── cxx-scenarios-bugsnag.cpp │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── bugsnag │ │ │ │ │ └── android │ │ │ │ │ └── mazerunner │ │ │ │ │ └── scenarios │ │ │ │ │ ├── CXXAutoContextScenario.java │ │ │ │ │ ├── CXXBackgroundNotifyScenario.kt │ │ │ │ │ ├── CXXBreadcrumbScenario.java │ │ │ │ │ ├── CXXCaptureThreadsNotifyScenario.kt │ │ │ │ │ ├── CXXCaptureThreadsScenario.kt │ │ │ │ │ ├── CXXCrashLoopScenario.kt │ │ │ │ │ ├── CXXDelayedNotifyScenario.java │ │ │ │ │ ├── CXXExceptionOnErrorFalseScenario.kt │ │ │ │ │ ├── CXXExceptionOnErrorTrueScenario.kt │ │ │ │ │ ├── CXXExceptionSmokeScenario.kt │ │ │ │ │ ├── CXXExceptionWithUsageScenario.kt │ │ │ │ │ ├── CXXExternalStackElementScenario.java │ │ │ │ │ ├── CXXGetJavaDataScenario.java │ │ │ │ │ ├── CXXHandledOverrideScenario.kt │ │ │ │ │ ├── CXXJavaBreadcrumbNativeBreadcrumbScenario.java │ │ │ │ │ ├── CXXNativeBreadcrumbJavaCrashScenario.java │ │ │ │ │ ├── CXXNativeBreadcrumbJavaNotifyScenario.java │ │ │ │ │ ├── CXXNativeBreadcrumbNativeCrashScenario.java │ │ │ │ │ ├── CXXNativeUserInfoJavaCrashScenario.java │ │ │ │ │ ├── CXXNaughtyStringsScenario.kt │ │ │ │ │ ├── CXXNotifySmokeScenario.java │ │ │ │ │ ├── CXXRefreshSymbolTableDuringCrashScenario.kt │ │ │ │ │ ├── CXXRemoveDataScenario.java │ │ │ │ │ ├── CXXRemoveOnErrorScenario.kt │ │ │ │ │ ├── CXXSignalOnErrorFalseScenario.kt │ │ │ │ │ ├── CXXSignalSmokeScenario.java │ │ │ │ │ ├── CXXSigsegvWithUsageScenario.kt │ │ │ │ │ ├── CXXStartScenario.java │ │ │ │ │ ├── EventTooBigScenario.kt │ │ │ │ │ ├── ExitInfoScenario.kt │ │ │ │ │ ├── HandledExceptionWithUsageScenario.kt │ │ │ │ │ ├── MetadataStringsTooLargeScenario.kt │ │ │ │ │ ├── MultiProcessHandledCXXErrorScenario.kt │ │ │ │ │ ├── MultiProcessUnhandledCXXErrorScenario.kt │ │ │ │ │ └── UnhandledExceptionWithUsageScenario.kt │ │ │ │ └── jniLibs │ │ │ │ ├── arm64-v8a │ │ │ │ └── libmonochrome.so │ │ │ │ ├── armeabi-v7a │ │ │ │ └── libmonochrome.so │ │ │ │ ├── x86 │ │ │ │ └── libmonochrome.so │ │ │ │ └── x86_64 │ │ │ │ └── libmonochrome.so │ │ ├── cxx-scenarios │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── build.gradle │ │ │ ├── detekt-baseline.xml │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── cpp │ │ │ │ ├── CXXAbortScenario.cpp │ │ │ │ ├── CXXCallNullFunctionPointerScenario.cpp │ │ │ │ ├── CXXDereferenceNullScenario.cpp │ │ │ │ ├── CXXImproperTypecastScenario.cpp │ │ │ │ ├── CXXInvalidRethrow.cpp │ │ │ │ ├── CXXStackoverflowScenario.cpp │ │ │ │ ├── CXXThrowFromNoexcept.cpp │ │ │ │ ├── CXXTrapScenario.cpp │ │ │ │ ├── CXXWriteReadOnlyMemoryScenario.cpp │ │ │ │ ├── bugsnag-java-scenarios.cpp │ │ │ │ └── cxx-scenarios.cpp │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── bugsnag │ │ │ │ └── android │ │ │ │ └── mazerunner │ │ │ │ └── scenarios │ │ │ │ ├── AutoDetectNdkDisabledScenario.java │ │ │ │ ├── CXXAbortScenario.java │ │ │ │ ├── CXXAnrNdkDisabledScenario.kt │ │ │ │ ├── CXXAnrScenario.java │ │ │ │ ├── CXXCallNullFunctionPointerScenario.kt │ │ │ │ ├── CXXConfigurationMetadataNativeCrashScenario.java │ │ │ │ ├── CXXDelayedCrashScenario.kt │ │ │ │ ├── CXXDelayedErrorScenario.kt │ │ │ │ ├── CXXDereferenceNullScenario.java │ │ │ │ ├── CXXExceptionScenario.java │ │ │ │ ├── CXXExtraordinaryLongStringScenario.java │ │ │ │ ├── CXXFeatureFlagNativeCrashScenario.java │ │ │ │ ├── CXXIgnoredSigabrtScenario.kt │ │ │ │ ├── CXXImproperTypecastScenario.java │ │ │ │ ├── CXXInvalidRethrow.kt │ │ │ │ ├── CXXJavaBreadcrumbNativeCrashScenario.java │ │ │ │ ├── CXXJavaUserInfoNativeCrashScenario.java │ │ │ │ ├── CXXMarkLaunchCompletedScenario.kt │ │ │ │ ├── CXXMaxBreadcrumbCrashScenario.kt │ │ │ │ ├── CXXPausedSessionScenario.kt │ │ │ │ ├── CXXSessionInfoCrashScenario.kt │ │ │ │ ├── CXXSigabrtScenario.java │ │ │ │ ├── CXXSigbusScenario.java │ │ │ │ ├── CXXSigfpeScenario.java │ │ │ │ ├── CXXSigillScenario.java │ │ │ │ ├── CXXSigsegvScenario.java │ │ │ │ ├── CXXSigtrapScenario.java │ │ │ │ ├── CXXStackoverflowScenario.java │ │ │ │ ├── CXXStartSessionScenario.kt │ │ │ │ ├── CXXThrowFromNoexcept.kt │ │ │ │ ├── CXXThrowSomethingOutsideReleaseStagesScenario.kt │ │ │ │ ├── CXXThrowSomethingScenario.java │ │ │ │ ├── CXXTrapOutsideReleaseStagesScenario.kt │ │ │ │ ├── CXXTrapScenario.java │ │ │ │ ├── CXXUpdateContextCrashScenario.java │ │ │ │ ├── CXXWriteReadOnlyMemoryScenario.java │ │ │ │ ├── UnhandledNdkAutoNotifyFalseScenario.kt │ │ │ │ └── UnhandledNdkAutoNotifyTrueScenario.kt │ │ ├── gradle.properties │ │ ├── gradle │ │ │ ├── checkstyle.gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── jvm-scenarios │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── consumer-rules.pro │ │ │ ├── detekt-baseline.xml │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── bugsnag │ │ │ │ │ └── android │ │ │ │ │ ├── JavaHooks.java │ │ │ │ │ ├── TestHarnessHooks.kt │ │ │ │ │ ├── mazerunner │ │ │ │ │ ├── AnrHelper.kt │ │ │ │ │ ├── BugsnagConfig.kt │ │ │ │ │ ├── BugsnagIntentParams.kt │ │ │ │ │ ├── CustomSerializedException.java │ │ │ │ │ ├── InterceptingDelivery.kt │ │ │ │ │ ├── Log.kt │ │ │ │ │ ├── MazerunnerHttpClient.kt │ │ │ │ │ ├── NaughtyStrings.kt │ │ │ │ │ ├── SomeException.kt │ │ │ │ │ └── scenarios │ │ │ │ │ │ ├── ArrayEnabledReleaseStageScenario.kt │ │ │ │ │ │ ├── AsyncErrorConnectivityScenario.kt │ │ │ │ │ │ ├── AsyncErrorDoubleFlushScenario.kt │ │ │ │ │ │ ├── AsyncErrorLaunchScenario.kt │ │ │ │ │ │ ├── AutoDetectAnrsFalseScenario.kt │ │ │ │ │ │ ├── AutoDetectAnrsTrueScenario.kt │ │ │ │ │ │ ├── AutoRedactKeysScenario.kt │ │ │ │ │ │ ├── AutoSessionSmokeScenario.kt │ │ │ │ │ │ ├── BreadcrumbAutoScenario.kt │ │ │ │ │ │ ├── BreadcrumbDisabledScenario.kt │ │ │ │ │ │ ├── BreadcrumbScenario.kt │ │ │ │ │ │ ├── BugsnagInitScenario.kt │ │ │ │ │ │ ├── ConfigureStartupAnrScenario.kt │ │ │ │ │ │ ├── CrashHandlerScenario.kt │ │ │ │ │ │ ├── CustomHttpClientFlushScenario.kt │ │ │ │ │ │ ├── CustomHttpClientScenario.kt │ │ │ │ │ │ ├── CustomPluginExample.kt │ │ │ │ │ │ ├── CustomPluginNotifierDescriptionScenario.kt │ │ │ │ │ │ ├── DeliverOnCrashScenario.kt │ │ │ │ │ │ ├── DisableAutoDetectErrorsScenario.kt │ │ │ │ │ │ ├── DiscardBigEventsScenario.kt │ │ │ │ │ │ ├── DiscardOldEventsScenario.kt │ │ │ │ │ │ ├── DiscardOldSessionScenario.kt │ │ │ │ │ │ ├── DiscardOldSessionScenarioPart2.kt │ │ │ │ │ │ ├── DiscardOldSessionScenarioPart3.kt │ │ │ │ │ │ ├── EmptyEnabledReleaseStageScenario.kt │ │ │ │ │ │ ├── EmptyStacktraceScenario.kt │ │ │ │ │ │ ├── ErrorBreadcrumbsScenario.kt │ │ │ │ │ │ ├── FeatureFlagScenario.kt │ │ │ │ │ │ ├── HandledExceptionApiKeyChangeScenario.kt │ │ │ │ │ │ ├── HandledExceptionMaxThreadsScenario.kt │ │ │ │ │ │ ├── HandledExceptionScenario.kt │ │ │ │ │ │ ├── HandledExceptionWithoutMessageScenario.kt │ │ │ │ │ │ ├── HandledJavaSmokeScenario.java │ │ │ │ │ │ ├── HandledJvmAutoNotifyFalseScenario.kt │ │ │ │ │ │ ├── HandledKotlinSmokeScenario.kt │ │ │ │ │ │ ├── HandledOnSendCallbackScenario.kt │ │ │ │ │ │ ├── IgnoredExceptionScenario.kt │ │ │ │ │ │ ├── InForegroundScenario.kt │ │ │ │ │ │ ├── InternalErrorDisabledScenario.kt │ │ │ │ │ │ ├── InternalErrorScenario.kt │ │ │ │ │ │ ├── JvmAnrDisabledScenario.kt │ │ │ │ │ │ ├── JvmAnrLoopScenario.kt │ │ │ │ │ │ ├── JvmAnrMinimalFixtureScenario.kt │ │ │ │ │ │ ├── JvmAnrOutsideReleaseStagesScenario.java │ │ │ │ │ │ ├── JvmAnrSleepScenario.kt │ │ │ │ │ │ ├── JvmCrashLoopScenario.kt │ │ │ │ │ │ ├── JvmDelayedErrorScenario.kt │ │ │ │ │ │ ├── JvmMarkLaunchCompletedScenario.kt │ │ │ │ │ │ ├── LoadConfigurationFromManifestScenario.kt │ │ │ │ │ │ ├── LoadConfigurationKotlinScenario.kt │ │ │ │ │ │ ├── LoadConfigurationNullsScenario.java │ │ │ │ │ │ ├── ManualRedactKeysScenario.kt │ │ │ │ │ │ ├── ManualSessionSmokeScenario.kt │ │ │ │ │ │ ├── MetadataNestedNullScenario.kt │ │ │ │ │ │ ├── MetadataScenario.kt │ │ │ │ │ │ ├── MultiProcessHandledExceptionScenario.kt │ │ │ │ │ │ ├── MultiProcessUnhandledExceptionScenario.kt │ │ │ │ │ │ ├── NaughtyStringScenario.kt │ │ │ │ │ │ ├── NetworkBreadcrumbScenario.kt │ │ │ │ │ │ ├── NullReleaseStageScenario.kt │ │ │ │ │ │ ├── NullStackTraceScenario.kt │ │ │ │ │ │ ├── OkHttpDeliveryScenario.kt │ │ │ │ │ │ ├── OnSendCallbackScenario.kt │ │ │ │ │ │ ├── OomScenario.kt │ │ │ │ │ │ ├── OutsideReleaseStageScenario.kt │ │ │ │ │ │ ├── OverrideToHandledExceptionScenario.kt │ │ │ │ │ │ ├── OverrideToUnhandledExceptionScenario.kt │ │ │ │ │ │ ├── ReportCacheScenario.kt │ │ │ │ │ │ ├── Scenario.kt │ │ │ │ │ │ ├── SessionApiKeyResetScenario.kt │ │ │ │ │ │ ├── SessionCacheScenario.kt │ │ │ │ │ │ ├── SessionPersistUserDisabledScenario.kt │ │ │ │ │ │ ├── SessionPersistUserScenario.kt │ │ │ │ │ │ ├── SessionStoppingScenario.kt │ │ │ │ │ │ ├── SharedPrefMigrationScenario.kt │ │ │ │ │ │ ├── StackOverflowScenario.kt │ │ │ │ │ │ ├── StartSessionAutoModeScenario.kt │ │ │ │ │ │ ├── StartupCrashFlushScenario.kt │ │ │ │ │ │ ├── StrictModeDiscScenario.kt │ │ │ │ │ │ ├── StrictModeFileUriExposeScenario.kt │ │ │ │ │ │ ├── StrictModeNetworkScenario.kt │ │ │ │ │ │ ├── TrimmedStacktraceScenario.kt │ │ │ │ │ │ ├── UnhandledExceptionApiKeyChangeScenario.kt │ │ │ │ │ │ ├── UnhandledExceptionEventDetailChangeScenario.kt │ │ │ │ │ │ ├── UnhandledExceptionMaxThreadsScenario.kt │ │ │ │ │ │ ├── UnhandledExceptionScenario.kt │ │ │ │ │ │ ├── UnhandledJavaLoadedConfigScenario.java │ │ │ │ │ │ ├── UnhandledJvmAutoNotifyFalseScenario.kt │ │ │ │ │ │ ├── UnhandledJvmAutoNotifyTrueScenario.kt │ │ │ │ │ │ ├── UnsatisfiedLinkErrorScenario.java │ │ │ │ │ │ ├── UserCallbackScenario.kt │ │ │ │ │ │ ├── UserDisabledScenario.kt │ │ │ │ │ │ └── UserIdScenario.kt │ │ │ │ │ └── multiprocess │ │ │ │ │ ├── MultiProcessService.kt │ │ │ │ │ └── ProcessCompat.kt │ │ │ │ └── resources │ │ │ │ └── naughty_strings.txt │ │ └── settings.gradle │ └── minimalapp │ │ ├── .gitignore │ │ ├── Dangerfile │ │ ├── Gemfile │ │ ├── app │ │ ├── build.gradle │ │ ├── fakekeys.jks │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── bugsnag │ │ │ └── android │ │ │ └── minimalapp │ │ │ └── CustomApp.java │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle ├── full_tests │ ├── anr.feature │ ├── async_error_flush.feature │ ├── auto_notify.feature │ ├── breadcrumb.feature │ ├── bugsnag_init.feature │ ├── crash_handler.feature │ ├── custom_http_client.feature │ ├── detect_ndk_crashes.feature │ ├── discarded_events.feature │ ├── discarded_session.feature │ ├── empty_stacktrace.feature │ ├── error_callback_alters_fields.feature │ ├── event_callback_alters_api_key.feature │ ├── exit_information.feature │ ├── feature_flags.feature │ ├── filtering_metadata.feature │ ├── handled_exception.feature │ ├── identify_crashes_on_launch.feature │ ├── ignored_reports.feature │ ├── in_foreground.feature │ ├── internal_error_reports.feature │ ├── load_configuration.feature │ ├── max_reported_threads.feature │ ├── meta_data_scenario.feature │ ├── multi_process.feature │ ├── native_api.feature │ ├── native_breadcrumbs.feature │ ├── native_context.feature │ ├── native_crash_handling.feature │ ├── native_event_tracking.feature │ ├── native_feature_flags.feature │ ├── native_metadata.feature │ ├── native_on_error.feature │ ├── native_session_tracking.feature │ ├── native_signal_raise.feature │ ├── native_threads.feature │ ├── native_throw_crash.feature │ ├── native_user.feature │ ├── naughty_strings.feature │ ├── network_breadcrumbs.feature │ ├── null_stacktrace.feature │ ├── onsend_callback.feature │ ├── oom.feature │ ├── override_unhandled.feature │ ├── plugin_interface.feature │ ├── release_stage.feature │ ├── session_stopping.feature │ ├── session_tracking.feature │ ├── stackoverflow.feature │ ├── startup_anr.feature │ ├── strict_mode_legacy.feature │ ├── strict_mode_violations.feature │ ├── trimmed_stacktrace.feature │ ├── trimming.feature │ ├── usage.feature │ └── user.feature ├── minimal │ └── detect_anr_minimal.feature ├── scripts │ ├── close-anr-dialog.sh │ ├── generate_gpg_key │ └── tap-screen.sh ├── smoke_tests │ ├── 01_anr.feature │ ├── 02_handled.feature │ ├── 03_sessions.feature │ └── 04_unhandled.feature ├── steps │ ├── android_steps.rb │ ├── breadcrumb_metadata_steps.rb │ └── symbol_steps.rb └── support │ ├── env.rb │ ├── maze.all.cfg │ └── maze.buildkite.cfg ├── gradle.properties ├── gradle ├── detekt.gradle ├── license-check.gradle ├── release.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── maze_output └── .gitignore ├── scripts ├── audit-dependency-licenses.sh ├── bump-version.sh ├── copy-build-files.rb ├── docker-publish.sh ├── run-clang-format-ci-check.sh ├── run-clang-format.sh ├── run-connected-checks.rb ├── run-cpp-check.sh └── run-sizer.sh └── settings.gradle.kts /.buildkite/block.step.yml: -------------------------------------------------------------------------------- 1 | agents: 2 | queue: 'macos' 3 | 4 | steps: 5 | - label: 6 | block: 'Trigger full build' 7 | key: 'trigger-full-build' 8 | 9 | - label: 'Upload the full test pipeline' 10 | depends_on: 'trigger-full-build' 11 | command: buildkite-agent pipeline upload .buildkite/pipeline.full.yml 12 | timeout_in_minutes: 5 13 | -------------------------------------------------------------------------------- /.buildkite/pipeline_trigger.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | if [[ "$BUILDKITE_MESSAGE" == *"[full ci]"* || 4 | "$BUILDKITE_BRANCH" == "main" || 5 | "$BUILDKITE_PULL_REQUEST_BASE_BRANCH" == "main" || 6 | ! -z "$FULL_SCHEDULED_BUILD" ]]; then 7 | # Full build 8 | buildkite-agent pipeline upload .buildkite/pipeline.full.yml 9 | 10 | else 11 | # Basic build, but allow a full build to be triggered 12 | buildkite-agent pipeline upload .buildkite/block.step.yml 13 | fi 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/A.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Having trouble getting started? 3 | about: Please contact us at support@bugsnag.com for assistance with integrating BugSnag 4 | into your application. 5 | title: '' 6 | labels: '' 7 | assignees: '' 8 | 9 | --- 10 | Please check out our [documentation](https://docs.bugsnag.com/platforms/android/) for guides, references and tutorials. 11 | 12 | If you have questions about your integration, please contact us at [support@bugsnag.com](mailto:support@bugsnag.com). 13 | 14 | Alternatively, view additional options at [SUPPORT.md](../SUPPORT.md). -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ### Description 13 | 16 | 17 | **Describe the solution you'd like** 18 | 19 | 20 | **Describe alternatives you've considered** 21 | 22 | 23 | **Additional context** 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Goal 2 | 3 | 4 | 5 | ## Design 6 | 7 | 8 | 9 | ## Changeset 10 | 11 | 12 | 13 | ## Testing 14 | 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | version: 2 6 | updates: 7 | - package-ecosystem: "bundler" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | - package-ecosystem: "github-actions" 12 | directory: "/" 13 | schedule: 14 | interval: "weekly" 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | .gradle/ 3 | build/ 4 | 5 | # Local configuration file (sdk path, etc) 6 | local.properties 7 | 8 | # Android Studio generated folders 9 | captures/ 10 | .externalNativeBuild 11 | 12 | # IntelliJ project files 13 | *.iml 14 | .idea/ 15 | 16 | # Misc 17 | .DS_Store 18 | infer-out/ 19 | *.log 20 | CMakeFiles 21 | CMakeCache.txt 22 | Testing 23 | bugsnag_test 24 | *.crash 25 | .cxx/ 26 | .project 27 | decisions.yml 28 | Gemfile.lock 29 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "bugsnag-plugin-android-ndk/src/main/jni/external/libunwindstack-ndk"] 2 | path = bugsnag-plugin-android-ndk/src/main/jni/external/libunwindstack-ndk 3 | url = https://github.com/bugsnag/libunwindstack-ndk 4 | [submodule "bugsnag-android-core/dsl-json"] 5 | path = bugsnag-android-core/dsl-json 6 | url = https://github.com/bugsnag/dsl-json 7 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | bugsnag-android/ @lemnik @YYChen01988 2 | bugsnag-android-core/ @lemnik @YYChen01988 3 | bugsnag-plugin-android-anr/ @lemnik @YYChen01988 4 | bugsnag-plugin-android-exitinfo/ @lemnik @YYChen01988 5 | bugsnag-plugin-android-ndk/ @lemnik @YYChen01988 6 | bugsnag-plugin-android-okhttp/ @lemnik @YYChen01988 7 | bugsnag-plugin-react-native/ @lemnik @YYChen01988 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # You can run against local Maze Runner branches and uncommitted changes: 4 | #gem 'bugsnag-maze-runner', path: '../maze-runner' 5 | 6 | # Or a specific release: 7 | gem 'bugsnag-maze-runner', '~>9.0' 8 | 9 | # Or follow master: 10 | #gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner' 11 | 12 | gem "license_finder", "~> 7.0" 13 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | --------------------- | 7 | | 5.x | Critical patches only | 8 | | 6.x | Yes | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | If you find a vulnerability in this SDK, please report it to our [Support Team](mailto:support@bugsnag.com) for review. 13 | -------------------------------------------------------------------------------- /bugsnag-android-core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(bugsnag-android-core) 3 | add_subdirectory(src/main) 4 | -------------------------------------------------------------------------------- /bugsnag-android-core/README.md: -------------------------------------------------------------------------------- 1 | # bugsnag-android-core 2 | 3 | This module detects JVM exceptions and reports them to bugsnag. 4 | 5 | ## High-level Overview 6 | 7 | An `UncaughtExceptionHandler` is installed which generates an error report whenever an uncaught 8 | `Throwable` propagates. This module is also responsible for the delivery of JSON payloads to the 9 | Error Reporting API, and also provides the main public API for bugsnag-android. 10 | -------------------------------------------------------------------------------- /bugsnag-android-core/gradle.properties: -------------------------------------------------------------------------------- 1 | pomName=Bugsnag Android Core 2 | artefactId=bugsnag-android-core 3 | -------------------------------------------------------------------------------- /bugsnag-android-core/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes LineNumberTable,SourceFile 2 | -keep class com.bugsnag.android.NativeInterface { *; } 3 | -keep class com.bugsnag.android.NativeStackframe { *; } 4 | -keep class com.bugsnag.android.Breadcrumb { *; } 5 | -keep class com.bugsnag.android.BreadcrumbState { *; } 6 | -keep class com.bugsnag.android.BreadcrumbType { *; } 7 | -keep class com.bugsnag.android.Severity { *; } 8 | -keepclassmembers enum com.bugsnag.android.Telemetry { 9 | public static com.bugsnag.android.Telemetry[] values(); 10 | } 11 | -keepclassmembers enum com.bugsnag.android.ErrorType { 12 | public static com.bugsnag.android.Telemetry[] values(); 13 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/androidTest/java/android/os/strictmode/FakeStrictModeViolation.kt: -------------------------------------------------------------------------------- 1 | package android.os.strictmode 2 | 3 | internal class FakeStrictModeViolation : Violation() 4 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/androidTest/java/com/bugsnag/android/BugsnagKotlinTestUtils.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import android.os.Build 4 | 5 | inline fun withBuildSdkInt(sdk: Int, block: () -> R): R { 6 | val build = Build.VERSION::class.java 7 | val sdkInt = build.getDeclaredField("SDK_INT") 8 | .apply { isAccessible = true } 9 | 10 | val oldSdkInt = sdkInt.get(null) 11 | sdkInt.set(null, sdk) 12 | try { 13 | return block() 14 | } finally { 15 | sdkInt.set(null, oldSdkInt) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/androidTest/java/com/bugsnag/android/StrictModeWrapper.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import android.os.StrictMode; 4 | 5 | class StrictModeWrapper { 6 | 7 | static void setUp() { 8 | StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 9 | .detectDiskReads() 10 | .penaltyDeath() 11 | .build()); 12 | } 13 | 14 | static void tearDown() { 15 | StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(BUGSNAG_VERSION 1.0.1) 2 | add_library( # Specifies the name of the library. 3 | bugsnag-root-detection 4 | # Sets the library as a shared library. 5 | SHARED 6 | # Provides a relative path to your source file(s). 7 | jni/root_detection.c 8 | ) 9 | 10 | include_directories(jni) 11 | 12 | set(EXTRA_LINK_FLAGS "-Wl,-z,max-page-size=16384") 13 | 14 | set_target_properties( 15 | bugsnag-root-detection 16 | PROPERTIES 17 | COMPILE_OPTIONS -Werror -Wall -pedantic 18 | LINK_FLAGS "${EXTRA_LINK_FLAGS}" 19 | ) 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/CallbackAware.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal interface CallbackAware { 4 | fun addOnError(onError: OnErrorCallback) 5 | fun removeOnError(onError: OnErrorCallback) 6 | fun addOnBreadcrumb(onBreadcrumb: OnBreadcrumbCallback) 7 | fun removeOnBreadcrumb(onBreadcrumb: OnBreadcrumbCallback) 8 | fun addOnSession(onSession: OnSessionCallback) 9 | fun removeOnSession(onSession: OnSessionCallback) 10 | } 11 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/CollectionUtils.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import java.util.Collection; 6 | 7 | class CollectionUtils { 8 | static boolean containsNullElements(@Nullable Collection data) { 9 | if (data == null) { 10 | return true; 11 | } 12 | for (T datum : data) { 13 | if (datum == null) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/DeliveryParams.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * The parameters which should be used to deliver an Event/Session. 5 | */ 6 | class DeliveryParams( 7 | 8 | /** 9 | * The endpoint to which the payload should be sent 10 | */ 11 | val endpoint: String, 12 | 13 | /** 14 | * The HTTP headers which must be attached to the request 15 | */ 16 | val headers: Map 17 | ) 18 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/DeviceIdPersistence.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | interface DeviceIdPersistence { 4 | /** 5 | * Loads the device ID from storage. 6 | * 7 | * Device IDs are UUIDs which are persisted on a per-install basis. 8 | * 9 | * This method must be thread-safe and multi-process safe. 10 | * 11 | * Note: requestCreateIfDoesNotExist is only a request; an implementation may still refuse to create a new ID. 12 | */ 13 | fun loadDeviceId(requestCreateIfDoesNotExist: Boolean): String? 14 | } 15 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/Intrinsics.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | class Intrinsics { 4 | 5 | static boolean isEmpty(CharSequence str) { 6 | return str == null || str.length() == 0; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/JsonReadable.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import android.util.JsonReader 4 | 5 | /** 6 | * Classes which implement this interface are capable of deserializing a JSON input. 7 | */ 8 | internal interface JsonReadable { 9 | 10 | /** 11 | * Constructs an object from a JSON input. 12 | */ 13 | fun fromReader(reader: JsonReader): T 14 | } 15 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/LastRunInfo.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * Provides information about the last launch of the application, if there was one. 5 | */ 6 | class LastRunInfo( 7 | 8 | /** 9 | * The number times the app has consecutively crashed during its launch period. 10 | */ 11 | val consecutiveLaunchCrashes: Int, 12 | 13 | /** 14 | * Whether the last app run ended with a crash, or was abnormally terminated by the system. 15 | */ 16 | val crashed: Boolean, 17 | 18 | /** 19 | * True if the previous app run ended with a crash during its launch period. 20 | */ 21 | val crashedDuringLaunch: Boolean 22 | ) { 23 | override fun toString(): String { 24 | return "LastRunInfo(consecutiveLaunchCrashes=$consecutiveLaunchCrashes, crashed=$crashed, crashedDuringLaunch=$crashedDuringLaunch)" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/MetadataAware.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal interface MetadataAware { 4 | fun addMetadata(section: String, value: Map) 5 | fun addMetadata(section: String, key: String, value: Any?) 6 | 7 | fun clearMetadata(section: String) 8 | fun clearMetadata(section: String, key: String) 9 | 10 | fun getMetadata(section: String): Map? 11 | fun getMetadata(section: String, key: String): Any? 12 | } 13 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/NoopLogger.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal object NoopLogger : Logger 4 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/OnErrorCallback.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * A callback to be run before error reports are sent to Bugsnag. 5 | * 6 | * You can use this to add or modify information attached to an error 7 | * before it is sent to your dashboard. You can also return 8 | * `false` from any callback to halt execution. 9 | * 10 | * "on error" callbacks added via the JVM API do not run when a fatal C/C++ crash occurs. 11 | */ 12 | fun interface OnErrorCallback { 13 | /** 14 | * Runs the "on error" callback. If the callback returns 15 | * `false` any further OnErrorCallback callbacks will not be called 16 | * and the event will not be sent to Bugsnag. 17 | * 18 | * @param event the event to be sent to Bugsnag 19 | * @see Event 20 | */ 21 | fun onError(event: Event): Boolean 22 | } 23 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/OnSendCallback.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * A callback to be invoked before an [Event] is uploaded to a server. Similar to 5 | * [OnErrorCallback], an `OnSendCallback` may modify the `Event` 6 | * contents or even reject the entire payload by returning `false`. 7 | */ 8 | fun interface OnSendCallback { 9 | fun onSend(event: Event): Boolean 10 | } 11 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/OnSessionCallback.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * A callback to be run before sessions are sent to Bugsnag. 5 | * 6 | * You can use this to add or modify information attached to a session 7 | * before it is sent to your dashboard. You can also return 8 | * `false` from any callback to halt execution. 9 | */ 10 | fun interface OnSessionCallback { 11 | /** 12 | * Runs the "on session" callback. If the callback returns 13 | * `false` any further OnSessionCallback callbacks will not be called 14 | * and the session will not be sent to Bugsnag. 15 | * 16 | * @param session the session to be sent to Bugsnag 17 | * @see Session 18 | */ 19 | fun onSession(session: Session): Boolean 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/Plugin.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * A plugin allows for additional functionality to be added to the Bugsnag SDK. 5 | */ 6 | interface Plugin { 7 | 8 | /** 9 | * Loads a plugin with the given Client. When this method is invoked the plugin should 10 | * activate its behaviour - for example, by capturing an additional source of errors. 11 | */ 12 | fun load(client: Client) 13 | 14 | /** 15 | * Unloads a plugin. When this is invoked the plugin should cease all custom behaviour and 16 | * restore the application to its unloaded state. 17 | */ 18 | fun unload() 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/Severity.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import java.io.IOException 4 | 5 | /** 6 | * The severity of an Event, one of "error", "warning" or "info". 7 | * 8 | * By default, unhandled exceptions will be Severity.ERROR and handled 9 | * exceptions sent with bugsnag.notify will be Severity.WARNING. 10 | */ 11 | enum class Severity(private val str: String) : JsonStream.Streamable { 12 | ERROR("error"), 13 | WARNING("warning"), 14 | INFO("info"); 15 | 16 | @Throws(IOException::class) 17 | override fun toStream(writer: JsonStream) { 18 | writer.value(str) 19 | } 20 | 21 | internal companion object { 22 | internal fun fromDescriptor(desc: String) = values().find { it.str == desc } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/StrictModeOnErrorCallback.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal class StrictModeOnErrorCallback(private val errMsg: String) : OnErrorCallback { 4 | override fun onError(event: Event): Boolean { 5 | event.updateSeverityInternal(Severity.INFO) 6 | event.updateSeverityReason(SeverityReason.REASON_STRICT_MODE) 7 | val error = event.errors.firstOrNull() 8 | error?.errorMessage = errMsg 9 | return true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/Telemetry.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * Types of telemetry that may be sent to Bugsnag for product improvement purposes. 5 | */ 6 | enum class Telemetry { 7 | 8 | /** 9 | * Errors within the Bugsnag SDK. 10 | */ 11 | INTERNAL_ERRORS, 12 | 13 | /** 14 | * Differences from the default configuration. 15 | */ 16 | USAGE; 17 | 18 | internal companion object { 19 | fun fromString(str: String) = values().find { it.name == str } ?: INTERNAL_ERRORS 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/ThreadSendPolicy.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * Controls whether we should capture and serialize the state of all threads at the time 5 | * of an error. 6 | */ 7 | enum class ThreadSendPolicy { 8 | 9 | /** 10 | * Threads should be captured for all events. 11 | */ 12 | ALWAYS, 13 | 14 | /** 15 | * Threads should be captured for unhandled events only. 16 | */ 17 | UNHANDLED_ONLY, 18 | 19 | /** 20 | * Threads should never be captured. 21 | */ 22 | NEVER; 23 | 24 | internal companion object { 25 | fun fromString(str: String) = values().find { it.name == str } ?: ALWAYS 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/ThrowableExtensions.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("ThrowableUtils") 2 | package com.bugsnag.android 3 | 4 | /** 5 | * Unroll the list of causes for this Throwable, handling any recursion that may appear within 6 | * the chain. The first element returned will be this Throwable, and the last will be the root 7 | * cause or last non-recursive Throwable. 8 | */ 9 | internal fun Throwable.safeUnrollCauses(): List { 10 | val causes = LinkedHashSet() 11 | var currentEx: Throwable? = this 12 | 13 | // Set.add will return false if we have already "seen" currentEx 14 | while (currentEx != null && causes.add(currentEx)) { 15 | currentEx = currentEx.cause 16 | } 17 | 18 | return causes.toList() 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/TraceCorrelation.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import java.util.UUID 4 | 5 | internal data class TraceCorrelation(val traceId: UUID, val spanId: Long) : JsonStream.Streamable { 6 | override fun toStream(writer: JsonStream) { 7 | writer.beginObject() 8 | .name("traceId").value(traceId.toHexString()) 9 | .name("spanId").value(spanId.toHexString()) 10 | writer.endObject() 11 | } 12 | 13 | private fun UUID.toHexString(): String { 14 | return "%016x%016x".format(mostSignificantBits, leastSignificantBits) 15 | } 16 | 17 | private fun Long.toHexString(): String { 18 | return "%016x".format(this) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/UserAware.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal interface UserAware { 4 | fun getUser(): User 5 | fun setUser(id: String?, email: String?, name: String?) 6 | } 7 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/UserState.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal class UserState(user: User) : BaseObservable() { 4 | var user = user 5 | set(value) { 6 | field = value 7 | emitObservableEvent() 8 | } 9 | 10 | fun emitObservableEvent() = updateState { StateEvent.UpdateUser(user) } 11 | } 12 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/internal/BugsnagContentProvider.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.internal 2 | 3 | import android.app.Application 4 | 5 | class BugsnagContentProvider : AbstractStartupProvider() { 6 | override fun onCreate(): Boolean { 7 | (context?.applicationContext as? Application)?.let { app -> 8 | ForegroundDetector.registerOn(app) 9 | } 10 | 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/internal/ByteArrayExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.internal 2 | 3 | private const val HEX_RADIX = 16 4 | 5 | /** 6 | * Encode this `ByteArray` as a string of lowercase hex-pairs. 7 | */ 8 | internal fun ByteArray.toHexString(): String = buildString(size * 2) { 9 | for (byte in this@toHexString) { 10 | @Suppress("MagicNumber") 11 | val value = byte.toInt() and 0xff 12 | if (value < HEX_RADIX) append('0') 13 | append(value.toString(HEX_RADIX)) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/internal/InternalMetricsNoop.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.internal 2 | 3 | class InternalMetricsNoop : InternalMetrics { 4 | override fun toJsonableMap(): Map = emptyMap() 5 | override fun setConfigDifferences(differences: Map) = Unit 6 | override fun setCallbackCounts(newCallbackCounts: Map) = Unit 7 | override fun notifyAddCallback(callback: String) = Unit 8 | override fun notifyRemoveCallback(callback: String) = Unit 9 | override fun setMetadataTrimMetrics(stringsTrimmed: Int, charsRemoved: Int) = Unit 10 | override fun setBreadcrumbTrimMetrics(breadcrumbsRemoved: Int, bytesRemoved: Int) = Unit 11 | } 12 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/internal/StateObserver.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.internal 2 | 3 | import com.bugsnag.android.StateEvent 4 | 5 | fun interface StateObserver { 6 | /** 7 | * This is called whenever the notifier's state is altered, so that observers can react 8 | * appropriately. This is intended for internal use only. 9 | */ 10 | fun onStateChange(event: StateEvent) 11 | } 12 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/internal/dag/ConfigModule.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.internal.dag 2 | 3 | import com.bugsnag.android.Configuration 4 | import com.bugsnag.android.Connectivity 5 | import com.bugsnag.android.internal.BackgroundTaskService 6 | import com.bugsnag.android.internal.sanitiseConfiguration 7 | 8 | /** 9 | * A dependency module which constructs the configuration object that is used to alter 10 | * Bugsnag's default behaviour. 11 | */ 12 | internal class ConfigModule( 13 | contextModule: ContextModule, 14 | configuration: Configuration, 15 | connectivity: Connectivity, 16 | bgTaskExecutor: BackgroundTaskService 17 | ) : BackgroundDependencyModule(bgTaskExecutor) { 18 | val config = sanitiseConfiguration(contextModule.ctx, configuration, connectivity, bgTaskExecutor) 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/internal/dag/ContextModule.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.internal.dag 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.internal.BackgroundTaskService 5 | 6 | /** 7 | * A dependency module which accesses the application context object, falling back to the supplied 8 | * context if it is the base context. 9 | */ 10 | internal class ContextModule( 11 | appContext: Context, 12 | bgTaskService: BackgroundTaskService 13 | ) : BackgroundDependencyModule(bgTaskService) { 14 | 15 | val ctx: Context = when (appContext.applicationContext) { 16 | null -> appContext 17 | else -> appContext.applicationContext 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/main/java/com/bugsnag/android/internal/dag/SystemServiceModule.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.internal.dag 2 | 3 | import com.bugsnag.android.getActivityManager 4 | import com.bugsnag.android.getStorageManager 5 | import com.bugsnag.android.internal.BackgroundTaskService 6 | 7 | /** 8 | * A dependency module which provides a reference to Android system services. 9 | */ 10 | internal class SystemServiceModule( 11 | contextModule: ContextModule, 12 | bgTaskService: BackgroundTaskService 13 | ) : BackgroundDependencyModule(bgTaskService) { 14 | 15 | val storageManager = contextModule.ctx.getStorageManager() 16 | val activityManager = contextModule.ctx.getActivityManager() 17 | } 18 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/android/os/strictmode/FakeStrictModeViolation.kt: -------------------------------------------------------------------------------- 1 | package android.os.strictmode 2 | 3 | internal class FakeStrictModeViolation : Violation() 4 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/BreadcrumbMutabilityTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import org.junit.Assert.assertFalse 4 | import org.junit.Test 5 | import java.util.Date 6 | 7 | class BreadcrumbMutabilityTest { 8 | @Test 9 | fun breadcrumbProtectsMetadata() { 10 | val data = mutableMapOf() 11 | val breadcrumb = Breadcrumb("foo", BreadcrumbType.MANUAL, data, Date(0), NoopLogger) 12 | breadcrumb.metadata!!["a"] = "bar" 13 | assertFalse(breadcrumb.metadata!!.isEmpty()) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/BreadcrumbNullabilityTest.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNull; 5 | 6 | import org.junit.Test; 7 | 8 | import java.util.Date; 9 | 10 | public class BreadcrumbNullabilityTest { 11 | 12 | @Test 13 | public void testCreateFullBreadcrumbWithoutMetadata() { 14 | Date now = new Date(); 15 | Breadcrumb crumb = new Breadcrumb("badger spotted", BreadcrumbType.USER, 16 | null, now, NoopLogger.INSTANCE); 17 | assertEquals("badger spotted", crumb.getMessage()); 18 | assertEquals(BreadcrumbType.USER, crumb.getType()); 19 | assertEquals(now, crumb.getTimestamp()); 20 | assertNull(crumb.getMetadata()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/CollectionUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import org.junit.Test; 7 | 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | @SuppressWarnings("ConstantConditions") 12 | public class CollectionUtilsTest { 13 | 14 | @Test 15 | public void nullInput() { 16 | assertTrue(CollectionUtils.containsNullElements(null)); 17 | } 18 | 19 | @Test 20 | public void sanitiseSet() { 21 | Set input = new HashSet<>(); 22 | input.add("foo"); 23 | assertFalse(CollectionUtils.containsNullElements(input)); 24 | input.add(null); 25 | assertTrue(CollectionUtils.containsNullElements(input)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/EventPayloadTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Assert.assertNotSame 5 | import org.junit.Test 6 | 7 | class EventPayloadTest { 8 | 9 | @Test 10 | fun testCloneNotifier() { 11 | val original = Notifier() 12 | val config = BugsnagTestUtils.generateImmutableConfig() 13 | val payload = EventPayload("api-key", null, null, original, config) 14 | val copy = payload.notifier 15 | assertNotSame(original, copy) 16 | assertNotSame(original.dependencies, copy.dependencies) 17 | assertEquals(original.dependencies, copy.dependencies) 18 | assertEquals(original.name, copy.name) 19 | assertEquals(original.url, copy.url) 20 | assertEquals(original.version, copy.version) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/InterceptingLogger.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | class InterceptingLogger : Logger { 4 | 5 | var msg: String? = null 6 | 7 | override fun w(msg: String) { 8 | this.msg = msg 9 | } 10 | 11 | override fun w(msg: String, throwable: Throwable) { 12 | this.msg = msg 13 | } 14 | 15 | override fun e(msg: String) { 16 | this.msg = msg 17 | } 18 | 19 | override fun e(msg: String, throwable: Throwable) { 20 | this.msg = msg 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/JsonParser.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import java.io.StringWriter 4 | 5 | internal class JsonParser { 6 | 7 | fun read(resourceName: String): String { 8 | return JsonParser::class.java.classLoader!!.getResource(resourceName).readText() 9 | } 10 | 11 | fun toJsonString(streamable: JsonStream.Streamable): String { 12 | val writer = StringWriter() 13 | val jsonStream = JsonStream(writer) 14 | streamable.toStream(jsonStream) 15 | return writer.toString() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/LastRunInfoApiTest.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import org.junit.Test; 8 | 9 | public class LastRunInfoApiTest { 10 | 11 | /** 12 | * Verifies the LastRunInfo class contains the expected methods and hasn't broken 13 | * its API contract. 14 | */ 15 | @Test 16 | public void testLastRunInfo() { 17 | LastRunInfo lastRunInfo = new LastRunInfo(5, true, false); 18 | assertEquals(5, lastRunInfo.getConsecutiveLaunchCrashes()); 19 | assertTrue(lastRunInfo.getCrashed()); 20 | assertFalse(lastRunInfo.getCrashedDuringLaunch()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/OnErrorCallbackTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import com.bugsnag.android.BugsnagTestUtils.generateImmutableConfig 4 | import org.junit.Assert.assertEquals 5 | import org.junit.Test 6 | 7 | class OnErrorCallbackTest { 8 | 9 | private val config = generateImmutableConfig() 10 | 11 | @Test 12 | fun testRunModifiesError() { 13 | val context = "new-context" 14 | 15 | val onError = OnErrorCallback { 16 | it.context = context 17 | false 18 | } 19 | 20 | val handledState = SeverityReason.newInstance( 21 | SeverityReason.REASON_HANDLED_EXCEPTION 22 | ) 23 | val error = Event(RuntimeException("Test"), config, handledState, NoopLogger) 24 | onError.onError(error) 25 | assertEquals(context, error.context) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/SeveritySerializationTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import org.junit.Test 4 | import org.junit.runner.RunWith 5 | import org.junit.runners.Parameterized 6 | import org.junit.runners.Parameterized.Parameter 7 | import org.junit.runners.Parameterized.Parameters 8 | 9 | @RunWith(Parameterized::class) 10 | internal class SeveritySerializationTest { 11 | 12 | companion object { 13 | @JvmStatic 14 | @Parameters 15 | fun testCases() = generateSerializationTestCases( 16 | "severity", 17 | Severity.ERROR, 18 | Severity.WARNING, 19 | Severity.INFO 20 | ) 21 | } 22 | 23 | @Parameter 24 | lateinit var testCase: Pair 25 | 26 | @Test 27 | fun testJsonSerialisation() = verifyJsonMatches(testCase.first, testCase.second) 28 | } 29 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/StrictModeFacadeTest.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import static org.junit.Assert.assertNotNull; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Ensures that Bugsnag's API surface is able to deal with any unexpected null input that might 9 | * cause the SDK to crash. 10 | */ 11 | public class StrictModeFacadeTest { 12 | 13 | @Test 14 | public void testInvalidThreadListener() { 15 | BugsnagThreadViolationListener listener = new BugsnagThreadViolationListener(null); 16 | listener.onThreadViolation(null); 17 | assertNotNull(listener); 18 | } 19 | 20 | @Test 21 | public void testInvalidVmListener() { 22 | BugsnagVmViolationListener listener = new BugsnagVmViolationListener(null); 23 | listener.onVmViolation(null); 24 | assertNotNull(listener); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/ThreadSendPolicyTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import com.bugsnag.android.ThreadSendPolicy.ALWAYS 4 | import com.bugsnag.android.ThreadSendPolicy.NEVER 5 | import com.bugsnag.android.ThreadSendPolicy.UNHANDLED_ONLY 6 | import org.junit.Assert.assertEquals 7 | import org.junit.Test 8 | 9 | class ThreadSendPolicyTest { 10 | 11 | @Test 12 | fun invalidFromString() { 13 | assertEquals(ALWAYS, ThreadSendPolicy.fromString("")) 14 | assertEquals(ALWAYS, ThreadSendPolicy.fromString("foo")) 15 | } 16 | 17 | @Test 18 | fun validFromString() { 19 | assertEquals(ALWAYS, ThreadSendPolicy.fromString("ALWAYS")) 20 | assertEquals(NEVER, ThreadSendPolicy.fromString("NEVER")) 21 | assertEquals(UNHANDLED_ONLY, ThreadSendPolicy.fromString("UNHANDLED_ONLY")) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/UserSerializationTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import org.junit.Test 4 | import org.junit.runner.RunWith 5 | import org.junit.runners.Parameterized 6 | import org.junit.runners.Parameterized.Parameter 7 | import org.junit.runners.Parameterized.Parameters 8 | 9 | @RunWith(Parameterized::class) 10 | internal class UserSerializationTest { 11 | 12 | companion object { 13 | @JvmStatic 14 | @Parameters 15 | fun testCases() = generateSerializationTestCases( 16 | "user", 17 | User("123", "bob@example.com", "bob smith") 18 | ) 19 | } 20 | 21 | @Parameter 22 | lateinit var testCase: Pair 23 | 24 | @Test 25 | fun testJsonSerialisation() = verifyJsonMatches(testCase.first, testCase.second) 26 | } 27 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/java/com/bugsnag/android/UserTest.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | public class UserTest { 9 | 10 | private User user; 11 | 12 | @Before 13 | public void setUp() { 14 | user = new User("123", "bob@example.com", "bob smith"); 15 | } 16 | 17 | @Test 18 | public void testUserDefaults() { 19 | assertEquals("123", user.getId()); 20 | assertEquals("bob smith", user.getName()); 21 | assertEquals("bob@example.com", user.getEmail()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/app_data_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "binaryArch": "x86", 3 | "codeBundleId": "foo-99", 4 | "id": "com.example.foo", 5 | "releaseStage": "test-stage", 6 | "type": "React Native", 7 | "version": "1.2.3", 8 | "versionCode": 55 9 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/app_data_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "binaryArch": "x86", 3 | "codeBundleId": "foo-99", 4 | "id": "com.example.foo", 5 | "releaseStage": "test-stage", 6 | "type": "React Native", 7 | "version": "1.2.3", 8 | "versionCode": 55, 9 | "duration": 0, 10 | "durationInForeground": 0, 11 | "inForeground": false, 12 | "isLaunching": false 13 | } 14 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/app_meta_data_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "memoryTrimLevel": "None", 3 | "activeScreen": "MyActivity", 4 | "name": "MyApp", 5 | "lowMemory": false 6 | } 7 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/breadcrumb_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": "1970-01-01T00:00:00.000Z", 3 | "name": "hello world", 4 | "type": "manual", 5 | "metaData": {} 6 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/breadcrumb_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": "1970-01-01T00:00:00.000Z", 3 | "name": "metadata", 4 | "type": "process", 5 | "metaData": { 6 | "foo": true, 7 | "password": "[REDACTED]" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/breadcrumb_state_serialization_0.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "timestamp": "1970-01-01T00:00:00.000Z", 4 | "name": "hello world", 5 | "type": "manual", 6 | "metaData": { 7 | "direction": "left" 8 | } 9 | } 10 | ] -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/com/bugsnag/android/internal/classes.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/bugsnag-android-core/src/test/resources/com/bugsnag/android/internal/classes.dex -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/com/bugsnag/android/internal/empty-app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/bugsnag-android-core/src/test/resources/com/bugsnag/android/internal/empty-app-debug.apk -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/device_data_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "cpuAbi": [ 3 | "armeabi-v7a" 4 | ], 5 | "jailbroken": false, 6 | "id": "123", 7 | "locale": "en_GB", 8 | "manufacturer": "samsung", 9 | "model": "s7", 10 | "osName": "android", 11 | "osVersion": "7.1", 12 | "runtimeVersions": { 13 | "androidApiLevel": "24", 14 | "osBuild": "bulldog" 15 | }, 16 | "totalMemory": 502934020442 17 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/device_data_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "cpuAbi": [ 3 | "armeabi-v7a" 4 | ], 5 | "jailbroken": false, 6 | "id": "123", 7 | "locale": "en_GB", 8 | "manufacturer": "samsung", 9 | "model": "s7", 10 | "osName": "android", 11 | "osVersion": "7.1", 12 | "runtimeVersions": { 13 | "androidApiLevel": "24", 14 | "osBuild": "bulldog" 15 | }, 16 | "totalMemory": 502934020442, 17 | "freeDisk": 120935100007, 18 | "freeMemory": 2234092234234, 19 | "orientation": "landscape", 20 | "time": "1970-01-01T00:00:00.000Z" 21 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/device_metadata_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "locationStatus": "disallowed", 3 | "emulator": false, 4 | "networkAccess": "unknown", 5 | "screenDensity": 200.0, 6 | "dpi": 120, 7 | "screenResolution": "0x0", 8 | "brand": "google" 9 | } 10 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/error_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "errorClass": "foo", 3 | "message": "bar", 4 | "type": "android", 5 | "stacktrace": [] 6 | } 7 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/error_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "errorClass": "foo", 3 | "message": "bar", 4 | "type": "android", 5 | "stacktrace": [ 6 | { 7 | "method": "foo()", 8 | "file": "Bar.kt", 9 | "lineNumber": 55, 10 | "inProject": true, 11 | "columnNumber": 99, 12 | "code": { 13 | "54": "invoke()" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/error_serialization_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "errorClass": "com.bugsnag.android.StacktraceSerializationTest", 3 | "message": "bar", 4 | "type": "android", 5 | "stacktrace": [ 6 | { 7 | "method": "com.bugsnag.android.StacktraceSerializationTest$Companion.inProject", 8 | "file": "StacktraceSerializationTest.kt", 9 | "lineNumber": 47, 10 | "inProject": true 11 | }, 12 | { 13 | "method": "com.bugsnag.android.StacktraceSerializationTest$Companion.testCases", 14 | "file": "StacktraceSerializationTest.kt", 15 | "lineNumber": 31, 16 | "inProject": true 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/feature_flags_serialization_0.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "featureFlag": "sample_group", 4 | "variant": "a" 5 | }, 6 | { 7 | "featureFlag": "demo_mode" 8 | }, 9 | { 10 | "featureFlag": "view_mode", 11 | "variant": "modern" 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/feature_flags_serialization_1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "featureFlag": "sample_group", 4 | "variant": "b" 5 | }, 6 | { 7 | "featureFlag": "demo_mode" 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/feature_flags_serialization_2.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/json_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "bool": true, 3 | "string": "string", 4 | "int": 123, 5 | "long": 123, 6 | "float": 123.45, 7 | "streamable": { 8 | "timestamp": "1970-01-01T00:00:00.000Z", 9 | "name": "whoops", 10 | "type": "log", 11 | "metaData": {} 12 | }, 13 | "map": { 14 | "Baz": "What" 15 | }, 16 | "collection": [ 17 | "bar" 18 | ], 19 | "array": [ 20 | "foo" 21 | ], 22 | "object": "[OBJECT]" 23 | } 24 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/meta_data_serialization_0.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/meta_data_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "example": { 3 | "boolean": true, 4 | "string": "value", 5 | "array": [ 6 | "a", 7 | "b" 8 | ], 9 | "double": 123.45, 10 | "integer": 123, 11 | "collection": [ 12 | "Hello", 13 | "World" 14 | ], 15 | "map": { 16 | "key": "value" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/meta_data_serialization_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "example": { 3 | "map": { 4 | "key": { 5 | "key": "value" 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/meta_data_serialization_3.json: -------------------------------------------------------------------------------- 1 | { 2 | "example": { 3 | "list": [ 4 | [ 5 | "james", 6 | "test" 7 | ] 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/meta_data_serialization_4.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/metadata_redaction_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "example": { 3 | "normal": "safe", 4 | "password": "[REDACTED]", 5 | "confirm_password": "[REDACTED]" 6 | } 7 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/metadata_redaction_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "example": { 3 | "sensitiveMap": { 4 | "normal": "safe", 5 | "password": "[REDACTED]", 6 | "confirm_password": "[REDACTED]" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/metadata_redaction_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "password": "[REDACTED]" 4 | } 5 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/metadata_redaction_3.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/metadata_redaction_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "bar": "[REDACTED]", 4 | "password": "abc123" 5 | } 6 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/native_stackframe_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "method": "aMethod", 3 | "file": "aFile", 4 | "lineNumber": 1, 5 | "frameAddress": "0x2", 6 | "symbolAddress": "0x3", 7 | "loadAddress": "0x4", 8 | "isPC": true, 9 | "type": "c" 10 | } 11 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/native_stackframe_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "method": "aMethod", 3 | "file": "aFile", 4 | "lineNumber": 1 5 | } 6 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/native_stackframe_serialization_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "android" 3 | } 4 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/notifier_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AndroidBugsnagNotifier", 3 | "version": "9.9.9", 4 | "url": "https://bugsnag.com" 5 | } 6 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/notifier_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CustomNotifier", 3 | "version": "4.5.6", 4 | "url": "https://example.com", 5 | "dependencies": [ 6 | { 7 | "name": "AndroidBugsnagNotifier", 8 | "version": "9.9.9", 9 | "url": "https://bugsnag.com" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/null_json_stream.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/report_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKey": "api-key", 3 | "payloadVersion": "4.0", 4 | "notifier": { 5 | "name": "AndroidBugsnagNotifier", 6 | "version": "9.9.9", 7 | "url": "https://bugsnag.com" 8 | }, 9 | "events": [] 10 | } 11 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/session_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "notifier": { 3 | "name": "AndroidBugsnagNotifier", 4 | "version": "9.9.9", 5 | "url": "https://bugsnag.com" 6 | }, 7 | "app": { 8 | "type": "android", 9 | "versionCode": 0 10 | }, 11 | "device": { 12 | "cpuAbi": [], 13 | "manufacturer": "samsung", 14 | "model": "s7", 15 | "osName": "android", 16 | "osVersion": "7.1", 17 | "runtimeVersions": { 18 | "osBuild": "bulldog", 19 | "androidApiLevel": "24" 20 | }, 21 | "totalMemory": 10923250000 22 | }, 23 | "sessions": [ 24 | { 25 | "id": "123", 26 | "startedAt": "1970-01-01T00:00:00.000Z", 27 | "user": {} 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "unhandledException", 3 | "unhandledOverridden": false 4 | } 5 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "strictMode", 3 | "unhandledOverridden": false, 4 | "attributes": { 5 | "violationType": "diskRead" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "handledException", 3 | "unhandledOverridden": false 4 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_3.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "userSpecifiedSeverity", 3 | "unhandledOverridden": false 4 | } 5 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "userCallbackSetSeverity", 3 | "unhandledOverridden": false 4 | } 5 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_5.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "unhandledPromiseRejection", 3 | "unhandledOverridden": false 4 | } 5 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_6.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "log", 3 | "unhandledOverridden": false, 4 | "attributes": { 5 | "level": "warning" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_7.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "anrError", 3 | "unhandledOverridden": false 4 | } 5 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_8.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "handledException", 3 | "unhandledOverridden": true 4 | } 5 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_reason_serialization_9.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "handledError", 3 | "unhandledOverridden": false 4 | } 5 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_serialization_0.json: -------------------------------------------------------------------------------- 1 | "error" -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_serialization_1.json: -------------------------------------------------------------------------------- 1 | "warning" -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/severity_serialization_2.json: -------------------------------------------------------------------------------- 1 | "info" -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stackframe_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "method": "foo", 3 | "file": "Bar", 4 | "lineNumber": 55, 5 | "inProject": true, 6 | "type": "android" 7 | } 8 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stackframe_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "method": "aMethod", 3 | "file": "aFile", 4 | "lineNumber": 1, 5 | "frameAddress": "0x2", 6 | "symbolAddress": "0x3", 7 | "loadAddress": "0x4", 8 | "type": "c" 9 | } 10 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stackframe_serialization_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "method": "aMethod", 3 | "file": "aFile", 4 | "lineNumber": 1 5 | } 6 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stackframe_serialization_3.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stackframe_serialization_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "method": "_kDartIsolateSnapshotInstructions", 3 | "codeIdentifier": "b6951c7f8ae5ea368e83b65d81ff5c91", 4 | "type": "dart" 5 | } 6 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stacktrace_serialization_0.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stacktrace_serialization_1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "method": "foo()", 4 | "file": "Bar.kt", 5 | "lineNumber": 55, 6 | "inProject": true, 7 | "columnNumber": 99, 8 | "code": { 9 | "54": "invoke()" 10 | } 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stacktrace_serialization_2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "method": "com.bugsnag.android.StacktraceSerializationTest$Companion.basic", 4 | "file": "StacktraceSerializationTest.kt", 5 | "lineNumber": 41 6 | }, 7 | { 8 | "method": "com.bugsnag.android.StacktraceSerializationTest$Companion.testCases", 9 | "file": "StacktraceSerializationTest.kt", 10 | "lineNumber": 28 11 | } 12 | ] -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/stacktrace_serialization_3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "method": "com.bugsnag.android.StacktraceSerializationTest$Companion.inProject", 4 | "file": "StacktraceSerializationTest.kt", 5 | "lineNumber": 47, 6 | "inProject": true 7 | }, 8 | { 9 | "method": "com.bugsnag.android.StacktraceSerializationTest$Companion.testCases", 10 | "file": "StacktraceSerializationTest.kt", 11 | "lineNumber": 31, 12 | "inProject": true 13 | } 14 | ] -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/thread_deserialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "riker", 3 | "name": "will.riker", 4 | "type": "c" 5 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/thread_deserialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 321, 3 | "name": "mayne", 4 | "type": "android" 5 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/thread_deserialization_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482", 3 | "name": "smoke signal handler", 4 | "type": "android", 5 | "state": "happy" 6 | } -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/thread_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "24", 3 | "name": "main-one", 4 | "type": "android", 5 | "state": "RUNNABLE", 6 | "stacktrace": [ 7 | { 8 | "method": "run_func", 9 | "file": "librunner.so", 10 | "lineNumber": 5038 11 | }, 12 | { 13 | "method": "Runner.runFunc", 14 | "file": "Runner.java", 15 | "lineNumber": 14 16 | }, 17 | { 18 | "method": "App.launch", 19 | "file": "App.java", 20 | "lineNumber": 70 21 | } 22 | ], 23 | "errorReportingThread": true 24 | } 25 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/thread_serialization_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "24", 3 | "name": "main-one", 4 | "type": "android", 5 | "state": "RUNNABLE", 6 | "stacktrace": [ 7 | { 8 | "method": "run_func", 9 | "file": "librunner.so", 10 | "lineNumber": 5038 11 | }, 12 | { 13 | "method": "Runner.runFunc", 14 | "file": "Runner.java", 15 | "lineNumber": 14 16 | }, 17 | { 18 | "method": "App.launch", 19 | "file": "App.java", 20 | "lineNumber": 70 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/thread_serialization_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "24", 3 | "name": "main-one", 4 | "type": "android", 5 | "state": "RUNNABLE", 6 | "stacktrace": [ 7 | { 8 | "method": "run_func", 9 | "file": "librunner.so", 10 | "lineNumber": 5038 11 | }, 12 | { 13 | "method": "Runner.runFunc", 14 | "file": "Runner.java", 15 | "lineNumber": 14 16 | }, 17 | { 18 | "method": "App.launch", 19 | "file": "App.java", 20 | "lineNumber": 70 21 | } 22 | ], 23 | "errorReportingThread": true 24 | } 25 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/thread_serialization_3.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "24", 3 | "name": "main-one", 4 | "type": "android", 5 | "state": "RUNNABLE", 6 | "stacktrace": [ 7 | { 8 | "method": "run_func", 9 | "file": "librunner.so", 10 | "lineNumber": 5038 11 | }, 12 | { 13 | "method": "Runner.runFunc", 14 | "file": "Runner.java", 15 | "lineNumber": 14 16 | }, 17 | { 18 | "method": "App.launch", 19 | "file": "App.java", 20 | "lineNumber": 70 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /bugsnag-android-core/src/test/resources/user_serialization_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "123", 3 | "email": "bob@example.com", 4 | "name": "bob smith" 5 | } 6 | -------------------------------------------------------------------------------- /bugsnag-android/README.md: -------------------------------------------------------------------------------- 1 | # bugsnag-android 2 | 3 | This module is a meta package which contains no code itself. Its primary purpose is to 4 | publish an AAR + POM that adds a dependency on _all_ the bugsnag-android-* artefacts. This allows 5 | users to include bugsnag-android in their applications using the following syntax: 6 | 7 | ``` 8 | implementation "com.bugsnag:bugsnag-android:$version" 9 | ``` 10 | 11 | Which is simpler than manually specifying every single dependency: 12 | 13 | ``` 14 | implementation "com.bugsnag:bugsnag-android-core:$version" 15 | implementation "com.bugsnag:bugsnag-plugin-android-ndk:$version" 16 | implementation "com.bugsnag:bugsnag-plugin-android-anr:$version" 17 | ``` 18 | -------------------------------------------------------------------------------- /bugsnag-android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | load(Versions.Plugins.AGP) 3 | load(Versions.Plugins.licenseCheck) 4 | } 5 | 6 | android { 7 | compileSdk = Versions.Android.Build.compileSdkVersion 8 | namespace = "com.bugsnag.android" 9 | 10 | defaultConfig { 11 | minSdk = Versions.Android.Build.minSdkVersion 12 | ndkVersion = Versions.Android.Build.ndk 13 | } 14 | } 15 | 16 | dependencies { 17 | add("api", project(":bugsnag-android-core")) 18 | add("api", project(":bugsnag-plugin-android-anr")) 19 | add("api", project(":bugsnag-plugin-android-ndk")) 20 | } 21 | 22 | apply(from = rootProject.file("gradle/license-check.gradle")) 23 | apply(from = rootProject.file("gradle/release.gradle")) 24 | -------------------------------------------------------------------------------- /bugsnag-android/gradle.properties: -------------------------------------------------------------------------------- 1 | pomName=Bugsnag Android 2 | artefactId=bugsnag-android 3 | -------------------------------------------------------------------------------- /bugsnag-android/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /bugsnag-android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bugsnag-benchmarks/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /bugsnag-benchmarks/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(bugsnag-plugin-android-anr) 3 | add_subdirectory(src/main) 4 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/README.md: -------------------------------------------------------------------------------- 1 | # bugsnag-plugin-android-anr 2 | 3 | This module detects ANRs and reports them to bugsnag. 4 | 5 | ## High-level Overview 6 | 7 | When an ANR dialog is shown SIGQUIT is raised. This module installs a SIGQUIT handler and sets a 8 | ByteBuffer that is continuously monitored from the JVM. When the JVM code detects a ByteBuffer has 9 | been modified, it generates a report of the ANR. 10 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/api/bugsnag-plugin-android-anr.api: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/bugsnag-plugin-android-anr/api/bugsnag-plugin-android-anr.api -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/detekt-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SwallowedException:AnrDetailsCollector.kt$AnrDetailsCollector$exc: RuntimeException 6 | SwallowedException:AnrPlugin.kt$AnrPlugin$exc: Throwable 7 | ThrowingExceptionsWithoutMessageOrCause:AnrPlugin.kt$AnrPlugin$RuntimeException() 8 | UnusedPrivateMember:AnrPlugin.kt$AnrPlugin$private fun notifyAnrDetected(nativeTrace: List<NativeStackframe>) 9 | 10 | 11 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/gradle.properties: -------------------------------------------------------------------------------- 1 | pomName=Bugsnag Android ANR 2 | artefactId=bugsnag-plugin-android-anr 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes LineNumberTable,SourceFile 2 | -keep class com.bugsnag.android.AnrPlugin { *; } 3 | -keep class com.bugsnag.android.ErrorType { *; } 4 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(BUGSNAG_VERSION 1.0.1) 2 | add_library( # Specifies the name of the library. 3 | bugsnag-plugin-android-anr 4 | # Sets the library as a shared library. 5 | SHARED 6 | # Provides a relative path to your source file(s). 7 | jni/anr_google.c 8 | jni/anr_handler.c 9 | jni/bugsnag_anr.c 10 | jni/utils/string.c 11 | ) 12 | 13 | include_directories(jni) 14 | 15 | set(EXTRA_LINK_FLAGS "-Wl,-z,max-page-size=16384") 16 | 17 | target_link_libraries( # Specifies the target library. 18 | bugsnag-plugin-android-anr 19 | # Links the log library to the target library. 20 | log) 21 | 22 | set_target_properties( 23 | bugsnag-plugin-android-anr 24 | PROPERTIES 25 | COMPILE_OPTIONS -Werror -Wall -pedantic 26 | LINK_FLAGS "${EXTRA_LINK_FLAGS}" 27 | ) 28 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/jni/bsg_unwind.h: -------------------------------------------------------------------------------- 1 | #ifndef BSG_UNWIND_H 2 | #define BSG_UNWIND_H 3 | 4 | #include "include/event.h" 5 | 6 | // These are isolated because the ANR plugin symlinks to this file and to 7 | // ../assets/include/event.h 8 | 9 | #ifndef BUGSNAG_FRAMES_MAX 10 | /** 11 | * Number of frames in a stacktrace. Configures a default if not defined. 12 | */ 13 | #define BUGSNAG_FRAMES_MAX 192 14 | #endif 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/jni/bugsnag_anr.c: -------------------------------------------------------------------------------- 1 | #include "anr_handler.h" 2 | #include "unwind_func.h" 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | JNIEXPORT void JNICALL Java_com_bugsnag_android_AnrPlugin_enableAnrReporting( 11 | JNIEnv *env, jobject _this) { 12 | bsg_handler_install_anr(env, _this); 13 | } 14 | 15 | JNIEXPORT void JNICALL Java_com_bugsnag_android_AnrPlugin_disableAnrReporting( 16 | JNIEnv *env, jobject _this) { 17 | bsg_handler_uninstall_anr(); 18 | } 19 | 20 | JNIEXPORT void JNICALL Java_com_bugsnag_android_AnrPlugin_setUnwindFunction( 21 | JNIEnv *env, jobject thiz, jlong unwind_function) { 22 | bsg_set_unwind_function((unwind_func)unwind_function); 23 | } 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/jni/include/event.h: -------------------------------------------------------------------------------- 1 | ../../../../../bugsnag-plugin-android-ndk/src/main/jni/include/event.h -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/jni/unwind_func.h: -------------------------------------------------------------------------------- 1 | #ifndef UNWIND_FUNC_H 2 | #define UNWIND_FUNC_H 3 | 4 | #include "bsg_unwind.h" 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | typedef ssize_t (*unwind_func)( 13 | bugsnag_stackframe stacktrace[BUGSNAG_FRAMES_MAX], siginfo_t *info, 14 | void *user_context); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | #endif 20 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/jni/utils/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | void bsg_strncpy(char *dst, char *src, size_t len) { 4 | int i = 0; 5 | while (i <= len) { 6 | char current = src[i]; 7 | dst[i] = current; 8 | if (current == '\0') { 9 | break; 10 | } 11 | i++; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-anr/src/main/jni/utils/string.h: -------------------------------------------------------------------------------- 1 | #ifndef BUGSNAG_UTILS_STRING_H 2 | #define BUGSNAG_UTILS_STRING_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | /** 11 | * Copy the contents of src to dst where src is null-terminated 12 | */ 13 | void bsg_strncpy(char *dst, char *src, size_t len); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | #endif 19 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/README.md: -------------------------------------------------------------------------------- 1 | # bugsnag-plugin-android-exitinfo 2 | 3 | This module enhances your crash reports on Android 11+ devices by merging data captured in 4 | the [ApplicationExitInfo](https://developer.android.com/reference/android/app/ApplicationExitInfo). 5 | 6 | ## High-level Overview 7 | 8 | This module correlates `ApplicationExitInfo` traces and tombstones with reports being sent by 9 | bugsnag-android-core, and augments the existing error reports with information extracted from 10 | these files (such as the full stack-traces from all threads in native crashes). -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/gradle.properties: -------------------------------------------------------------------------------- 1 | pomName=Bugsnag Android ExitInfo 2 | artefactId=bugsnag-plugin-android-exitinfo 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.bugsnag.android.repackaged.server.os.* extends com.google.protobuf.GeneratedMessageLite { *; } -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/src/androidTest/java/com/bugsnag/android/TestHooks.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import com.bugsnag.android.internal.ImmutableConfig; 4 | import com.bugsnag.android.internal.ImmutableConfigKt; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | public class TestHooks { 9 | private TestHooks() { 10 | } 11 | 12 | public static ImmutableConfig convertToImmutableConfig( 13 | @NonNull Configuration configuration 14 | ) { 15 | return ImmutableConfigKt.convertToImmutableConfig(configuration); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/src/main/java/com/bugsnag/android/ExitInfoKey.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import android.app.ApplicationExitInfo 4 | import android.os.Build 5 | import androidx.annotation.RequiresApi 6 | 7 | internal data class ExitInfoKey(val pid: Int, val timestamp: Long) : JsonStream.Streamable { 8 | @RequiresApi(Build.VERSION_CODES.R) 9 | constructor(exitInfo: ApplicationExitInfo) : 10 | this(exitInfo.pid, exitInfo.timestamp) 11 | 12 | override fun toStream(stream: JsonStream) { 13 | stream.beginObject() 14 | .name("pid").value(pid) 15 | .name("timestamp").value(timestamp.toString()) 16 | .endObject() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-exitinfo/src/test/resources/tombstone_01.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/bugsnag-plugin-android-exitinfo/src/test/resources/tombstone_01.pb -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(bugsnag-plugin-android-ndk) 3 | project(TEST) 4 | add_subdirectory(src/main) 5 | 6 | if(${CMAKE_BUILD_TYPE} STREQUAL Debug) 7 | enable_testing() 8 | add_subdirectory(src/test) 9 | endif() 10 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/detekt-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CyclomaticComplexMethod:NativeBridge.kt$NativeBridge$override fun onStateChange(event: StateEvent) 6 | LongParameterList:NativeBridge.kt$NativeBridge$( apiKey: String, reportingDirectory: String, lastRunInfoPath: String, eventUUID: String, consecutiveLaunchCrashes: Int, autoDetectNdkCrashes: Boolean, apiLevel: Int, is32bit: Boolean, threadSendPolicy: Int, maxBreadcrumbs: Int, ) 7 | SwallowedException:ReportDiscardScanner.kt$ReportDiscardScanner$ex: Exception 8 | TooManyFunctions:NativeBridge.kt$NativeBridge : StateObserver 9 | UseCheckOrError:ResourceUtils.kt$throw IllegalStateException("Failed to read JSON from $resourceName") 10 | 11 | 12 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/gradle.properties: -------------------------------------------------------------------------------- 1 | pomName=Bugsnag Android NDK 2 | artefactId=bugsnag-plugin-android-ndk 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "development": { 3 | "silentbicycle/greatest": "v1.2.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes LineNumberTable,SourceFile 2 | -keep class com.bugsnag.android.ndk.OpaqueValue { 3 | java.lang.String getJson(); 4 | static java.lang.Object makeSafe(java.lang.Object); 5 | } 6 | -keep class com.bugsnag.android.ndk.NativeBridge { *; } 7 | -keep class com.bugsnag.android.NdkPlugin { *; } 8 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/NativeBreadcrumbTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import org.junit.Test 4 | 5 | class NativeBreadcrumbTest { 6 | 7 | companion object { 8 | init { 9 | System.loadLibrary("bugsnag-ndk") 10 | System.loadLibrary("bugsnag-ndk-test") 11 | } 12 | } 13 | 14 | external fun run(): Int 15 | 16 | @Test 17 | fun testPassesNativeSuite() { 18 | verifyNativeRun(run()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/NativeEventAppMutatorsTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import org.junit.Test 4 | 5 | class NativeEventAppMutatorsTest { 6 | 7 | companion object { 8 | init { 9 | System.loadLibrary("bugsnag-ndk") 10 | System.loadLibrary("bugsnag-ndk-test") 11 | } 12 | } 13 | 14 | external fun run(): Int 15 | 16 | @Test 17 | fun testPassesNativeSuite() { 18 | verifyNativeRun(run()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/NativeEventDeviceMutatorsTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import org.junit.Test 4 | 5 | class NativeEventDeviceMutatorsTest { 6 | 7 | companion object { 8 | init { 9 | System.loadLibrary("bugsnag-ndk") 10 | System.loadLibrary("bugsnag-ndk-test") 11 | } 12 | } 13 | 14 | external fun run(): Int 15 | 16 | @Test 17 | fun testPassesNativeSuite() { 18 | verifyNativeRun(run()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/NativeEventMutatorsTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import org.junit.Test 4 | 5 | class NativeEventMutatorsTest { 6 | 7 | companion object { 8 | init { 9 | System.loadLibrary("bugsnag-ndk") 10 | System.loadLibrary("bugsnag-ndk-test") 11 | } 12 | } 13 | 14 | external fun run(): Int 15 | 16 | @Test 17 | fun testPassesNativeSuite() { 18 | verifyNativeRun(run()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/NativeFeatureFlagsTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import org.junit.Test 4 | 5 | class NativeFeatureFlagsTest { 6 | companion object { 7 | init { 8 | System.loadLibrary("bugsnag-ndk") 9 | System.loadLibrary("bugsnag-ndk-test") 10 | } 11 | } 12 | 13 | external fun run(): Int 14 | 15 | @Test 16 | fun testPassesNativeSuite() { 17 | verifyNativeRun(run()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/NativeStringTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import org.junit.Test 4 | 5 | class NativeStringTest { 6 | 7 | companion object { 8 | init { 9 | System.loadLibrary("bugsnag-ndk") 10 | System.loadLibrary("bugsnag-ndk-test") 11 | } 12 | } 13 | 14 | external fun run(): Int 15 | 16 | @Test 17 | fun testPassesNativeSuite() { 18 | verifyNativeRun(run()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/ResourceUtils.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | internal fun loadJson(resourceName: String): String { 4 | val classLoader = requireNotNull(NativeJsonSerializeTest::class.java.classLoader) 5 | val resource = classLoader.getResource(resourceName) 6 | ?: throw IllegalArgumentException("Could not find $resourceName") 7 | val json = resource.readText() 8 | if (json.isEmpty()) { 9 | throw IllegalStateException("Failed to read JSON from $resourceName") 10 | } 11 | return json 12 | } 13 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/VerifyUtils.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import java.lang.IllegalStateException 4 | 5 | internal fun verifyNativeRun(code: Int): Boolean { 6 | if (code != 0) { 7 | throw IllegalStateException( 8 | "Native test suite failed." + 9 | " Filter the device logs by 'BugsnagNDKTest' to get the results." 10 | ) 11 | } else { 12 | return true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/exported_native_symbols-Debug.txt: -------------------------------------------------------------------------------- 1 | LIBBUGSNAG_NDK { 2 | global: 3 | bugsnag_*; 4 | Java_*; 5 | bsg_*; 6 | json_*; 7 | BSG_MIGRATOR_CURRENT_VERSION; 8 | migrate_app_v2; 9 | __gxx_*; 10 | __cxa_*; 11 | local: 12 | *; 13 | }; 14 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/exported_native_symbols-RelWithDebInfo.txt: -------------------------------------------------------------------------------- 1 | LIBBUGSNAG_NDK { 2 | global: 3 | bugsnag_*; 4 | __cxa_*; 5 | __dynamic_cast; 6 | __emutls_get_address; 7 | __gxx_personality_v0; 8 | Java_*; 9 | extern "C++" { 10 | "std::get_terminate()"; 11 | "std::set_terminate(void (*)())"; 12 | "std::set_unexpected(void (*)())"; 13 | "std::get_new_handler()"; 14 | "std::set_new_handler(void (*)())"; 15 | "std::rethrow_exception(std::exception_ptr)"; 16 | "std::__throw_bad_alloc()"; 17 | "std::uncaught_exception()"; 18 | "std::uncaught_exceptions()"; 19 | "std::nothrow"; 20 | "std::terminate()"; 21 | }; 22 | 23 | local: 24 | *; 25 | }; 26 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/java/com/bugsnag/android/ndk/BugsnagNDK.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.ndk 2 | 3 | import com.bugsnag.android.Bugsnag 4 | import com.bugsnag.android.ndkPlugin 5 | 6 | object BugsnagNDK { 7 | @JvmStatic 8 | fun refreshSymbolTable() { 9 | if (Bugsnag.isStarted()) { 10 | val client = Bugsnag.getClient() 11 | client.ndkPlugin?.nativeBridge?.refreshSymbolTable() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/bsg_unwind.h: -------------------------------------------------------------------------------- 1 | #ifndef BSG_UNWIND_H 2 | #define BSG_UNWIND_H 3 | 4 | #include "include/event.h" 5 | 6 | // These are isolated because the ANR plugin symlinks to this file and to 7 | // ../assets/include/event.h 8 | 9 | #ifndef BUGSNAG_FRAMES_MAX 10 | /** 11 | * Number of frames in a stacktrace. Configures a default if not defined. 12 | */ 13 | #define BUGSNAG_FRAMES_MAX 192 14 | #endif 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/build.h: -------------------------------------------------------------------------------- 1 | #ifndef BUGSNAG_ANDROID_BUILD_H 2 | #define BUGSNAG_ANDROID_BUILD_H 3 | #ifdef CLANG_ANALYZE_ASYNCSAFE 4 | #define __asyncsafe __attribute__((asyncsafe)); 5 | #else 6 | #define __asyncsafe 7 | #endif 8 | #endif // BUGSNAG_ANDROID_BUILD_H 9 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/crash_info.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Async-safe utilities for manipulating crash reports 3 | */ 4 | #ifndef BUGSNAG_CRASH_INFO_H 5 | #define BUGSNAG_CRASH_INFO_H 6 | 7 | #include "../bugsnag_ndk.h" 8 | #include "build.h" 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | /** 13 | * Add crash-time information to an event, respecting signal safety 14 | */ 15 | void bsg_populate_event_as(bsg_environment *env) __asyncsafe; 16 | 17 | /** 18 | * Increment the handled/unhandled count on the bugsnag event. 19 | */ 20 | void bsg_increment_unhandled_count(bugsnag_event *ptr); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | #endif 26 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifndef BUGSNAG_LOG 5 | #define BUGSNAG_LOG(fmt, ...) \ 6 | __android_log_print(ANDROID_LOG_WARN, "BugsnagNDK", fmt, ##__VA_ARGS__) 7 | #endif 8 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "memory.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /** 10 | * Global shared context for Bugsnag reports 11 | */ 12 | static bsg_environment *bsg_global_env; 13 | 14 | void bsg_init_memory(bsg_environment *env) { bsg_global_env = env; } 15 | 16 | void bsg_free(void *ptr) { 17 | /* 18 | * free is only "active" when there are no signal handlers active, if there is 19 | * a crash in progress the memory cannot be safely released within the process 20 | * (free is not async safe), and the heap will be released along with the rest 21 | * of the process when the crash is over. 22 | */ 23 | if (bsg_global_env->handling_crash) { 24 | return; 25 | } 26 | 27 | free(ptr); 28 | } 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef BUGSNAG_ANDROID_MEMORY_H 2 | #define BUGSNAG_ANDROID_MEMORY_H 3 | 4 | #include "bugsnag_ndk.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** 11 | * Crash-safe 'free' that won't cause deadlocks if a signal handler is active. 12 | * @param ptr 13 | */ 14 | void bsg_free(void *ptr); 15 | 16 | void bsg_init_memory(bsg_environment *env); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif // BUGSNAG_ANDROID_MEMORY_H 23 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/seqlock.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jason Morris on 02/02/2023. 3 | // 4 | 5 | #ifndef BUGSNAG_ANDROID_SEQLOCK_H 6 | #define BUGSNAG_ANDROID_SEQLOCK_H 7 | 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | typedef atomic_uint_fast64_t bsg_seqlock_t; 16 | typedef uint_fast64_t bsg_seqlock_status_t; 17 | 18 | void bsg_seqlock_init(bsg_seqlock_t *lock); 19 | 20 | void bsg_seqlock_acquire_write(bsg_seqlock_t *lock); 21 | 22 | void bsg_seqlock_release_write(bsg_seqlock_t *lock); 23 | 24 | bsg_seqlock_status_t bsg_seqlock_optimistic_read(bsg_seqlock_t *lock); 25 | 26 | bool bsg_seqlock_validate(bsg_seqlock_t *lock, bsg_seqlock_status_t expected); 27 | 28 | #define bsg_seqlock_is_write_locked(c) (((c) & 1uLL) != 0) 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #endif // BUGSNAG_ANDROID_SEQLOCK_H 35 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.c: -------------------------------------------------------------------------------- 1 | #include "serializer.h" 2 | #include "serializer/event_writer.h" 3 | 4 | bool bsg_serialize_last_run_info_to_file(bsg_environment *env) { 5 | return bsg_lastrun_write(env); 6 | } 7 | 8 | bool bsg_serialize_event_to_file(bsg_environment *env) { 9 | return bsg_event_write(env); 10 | } 11 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../bugsnag_ndk.h" 3 | #include "build.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | char *bsg_serialize_event_to_json_string(bugsnag_event *event); 10 | 11 | bool bsg_serialize_event_to_file(bsg_environment *env) __asyncsafe; 12 | 13 | /** 14 | * Serializes the LastRunInfo to the file. This persists information about 15 | * why the current launch crashed, for use on future launch. 16 | */ 17 | bool bsg_serialize_last_run_info_to_file(bsg_environment *env) __asyncsafe; 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/serializer/event_writer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * async-safe functions for writing an event to disk 3 | */ 4 | #pragma once 5 | #include "../../bugsnag_ndk.h" 6 | 7 | bool bsg_event_write(bsg_environment *env) __asyncsafe; 8 | 9 | bool bsg_write_event_file(bsg_environment *env, 10 | const char *filename) __asyncsafe; 11 | 12 | bool bsg_lastrun_write(bsg_environment *env) __asyncsafe; 13 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/main/jni/utils/threads.h: -------------------------------------------------------------------------------- 1 | #ifndef BUGSNAG_THREADS_H 2 | #define BUGSNAG_THREADS_H 3 | 4 | #include "../event.h" 5 | #include "build.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #define MAX_STAT_PATH_LENGTH 64 12 | 13 | size_t bsg_capture_thread_states(pid_t reporting_tid, bsg_thread *threads, 14 | size_t max_threads) __asyncsafe; 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | #endif // BUGSNAG_THREADS_H 20 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories( 2 | ../main/jni 3 | ../main/jni/deps 4 | cpp 5 | cpp/deps 6 | ) 7 | add_library(bugsnag-ndk-test SHARED 8 | cpp/main.c 9 | cpp/test_utils_string.c 10 | cpp/test_utils_serialize.c 11 | cpp/test_serializer.c 12 | cpp/test_breadcrumbs.c 13 | cpp/test_bsg_event.c 14 | cpp/test_featureflags.c 15 | cpp/test_bsg_event.c 16 | cpp/UnwindTest.cpp 17 | cpp/parson/parson.h 18 | ) 19 | target_link_libraries(bugsnag-ndk-test bugsnag-ndk) 20 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/test/cpp/deps/greatest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "greatest", 3 | "version": "v1.2.1", 4 | "repo": "silentbicycle/greatest", 5 | "src": ["greatest.h"], 6 | "description": "A C testing library in 1 file. No dependencies, no dynamic allocation.", 7 | "license": "ISC", 8 | "keywords": ["test", "unit", "testing"] 9 | } 10 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/test/cpp/parson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parson", 3 | "version": "0.0.0", 4 | "repo": "kgabis/parson", 5 | "description": "Small json parser and reader", 6 | "keywords": [ "json", "parser" ], 7 | "license": "MIT", 8 | "src": [ 9 | "parson.c", 10 | "parson.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-ndk/src/test/cpp/test_bsg_event.h: -------------------------------------------------------------------------------- 1 | #ifndef BUGSNAG_ANDROID_TEST_BSG_EVENT_H 2 | #define BUGSNAG_ANDROID_TEST_BSG_EVENT_H 3 | 4 | #include 5 | 6 | bugsnag_event *init_event(); 7 | 8 | #endif // BUGSNAG_ANDROID_TEST_BSG_EVENT_H 9 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-okhttp/README.md: -------------------------------------------------------------------------------- 1 | # bugsnag-plugin-android-okhttp 2 | 3 | This module captures a breadcrumb for each network request made by OkHttp. 4 | 5 | ## High-level Overview 6 | 7 | The module has a `compileOnly` dependency on OkHttp 4 and implements the `Plugin` and `EventListener` 8 | interfaces. The user should install the plugin while initializing Bugsnag and creating an 9 | `OkHttpClient`, and OkHttp's callbacks will then be used to automatically capture breadcrumbs 10 | for each request. 11 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-okhttp/detekt-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MagicNumber:BugsnagOkHttpPlugin.kt$100 6 | MagicNumber:BugsnagOkHttpPlugin.kt$399 7 | MagicNumber:BugsnagOkHttpPlugin.kt$400 8 | MagicNumber:BugsnagOkHttpPlugin.kt$599 9 | 10 | 11 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-okhttp/gradle.properties: -------------------------------------------------------------------------------- 1 | pomName=Bugsnag Android OkHttp 2 | artefactId=bugsnag-plugin-android-okhttp 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-okhttp/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-okhttp/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes LineNumberTable,SourceFile 2 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-okhttp/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-android-okhttp/src/main/java/com/bugsnag/android/BreadcrumbHooks.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal fun Client.shouldDiscardNetworkBreadcrumb() = config.shouldDiscardBreadcrumb(BreadcrumbType.REQUEST) 4 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/README.md: -------------------------------------------------------------------------------- 1 | # bugsnag-plugin-react-native 2 | 3 | This module detects errors in React Native apps and reports them to bugsnag. 4 | 5 | ## High-level Overview 6 | 7 | This module depends on bugsnag-android-core, and implements a `BugsnagReactNativePlugin` which is 8 | added in the native layer using the `Plugin` interface. This class is intended to be the sole 9 | internal API which `BugsnagReactNative` in the `bugsnag-js` repository invokes. 10 | 11 | The responsibility of this module is to serialize information into a format that can be understood 12 | by the React Bridge, and to forward method calls onto the appropriate site from `bugsnag-js`. 13 | 14 | The responsibility of Android code in the `bugsnag-js` package is to implement any functionality 15 | that requires the React Native Android dependency. A minimal number of classes require this and 16 | by default code should be implemented in this module. 17 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/detekt-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/gradle.properties: -------------------------------------------------------------------------------- 1 | pomName=Bugsnag Android React Native 2 | artefactId=bugsnag-plugin-react-native 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes LineNumberTable,SourceFile 2 | -keepnames class com.facebook.react.common.JavascriptException { *; } 3 | -keep class com.bugsnag.android.BugsnagReactNativePlugin { *; } 4 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/AppSerializer.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal class AppSerializer : MapSerializer { 4 | override fun serialize(map: MutableMap, app: AppWithState) { 5 | map["type"] = app.type 6 | map["binaryArch"] = app.binaryArch 7 | map["buildUuid"] = app.buildUuid 8 | map["codeBundleId"] = app.codeBundleId 9 | map["duration"] = app.duration 10 | map["durationInForeground"] = app.durationInForeground 11 | map["id"] = app.id 12 | map["inForeground"] = app.inForeground 13 | map["isLaunching"] = app.isLaunching 14 | map["releaseStage"] = app.releaseStage 15 | map["version"] = app.version 16 | map["versionCode"] = app.versionCode 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/BreadcrumbSerializer.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import com.bugsnag.android.internal.DateUtils 4 | 5 | internal class BreadcrumbSerializer : MapSerializer { 6 | override fun serialize(map: MutableMap, crumb: Breadcrumb) { 7 | map["timestamp"] = DateUtils.toIso8601(crumb.timestamp) 8 | map["message"] = crumb.message 9 | map["type"] = crumb.type.toString().lowercase() 10 | map["metadata"] = crumb.metadata 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/MapDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import java.util.Map; 4 | 5 | interface MapDeserializer { 6 | T deserialize(Map map); 7 | } 8 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/MapSerializer.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import java.util.Map; 4 | 5 | interface MapSerializer { 6 | void serialize(Map map, T obj); 7 | } 8 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/MessageEvent.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | /** 4 | * Holds information about a state change event which is serialized by the BugsnagReactNative 5 | * class and emitted to the JS layer. 6 | */ 7 | class MessageEvent( 8 | 9 | /** 10 | * The type of the event. E.g. `UpdateContext` 11 | */ 12 | val type: String, 13 | 14 | /** 15 | * The data which underwent a state change. For instance, if a user called 16 | * `Bugsnag.setContext()`, the new context value would be present in this field. 17 | */ 18 | val data: Any? 19 | ) 20 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/MetadataDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | class MetadataDeserializer implements MapDeserializer { 7 | @Override 8 | public Metadata deserialize(Map map) { 9 | // cast map to retain original signature until next major version bump, as this 10 | // method signature is used by Unity/React native 11 | @SuppressWarnings({"unchecked", "rawtypes"}) 12 | Map> data = (Map) map; 13 | ConcurrentHashMap> store = new ConcurrentHashMap<>(data); 14 | return new Metadata(store); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/StackframeDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import java.util.Map; 4 | 5 | class StackframeDeserializer implements MapDeserializer { 6 | 7 | @Override 8 | public Stackframe deserialize(Map map) { 9 | return new Stackframe( 10 | MapUtils.getOrNull(map, "method"), 11 | MapUtils.getOrNull(map, "file"), 12 | MapUtils.getOrNull(map, "lineNumber"), 13 | MapUtils.getOrNull(map, "inProject"), 14 | MapUtils.>getOrNull(map, "code"), 15 | MapUtils.getOrNull(map, "columnNumber") 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/ThreadSerializer.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | internal class ThreadSerializer : MapSerializer { 4 | override fun serialize(map: MutableMap, thread: Thread) { 5 | map["id"] = thread.id 6 | map["name"] = thread.name 7 | map["type"] = thread.type.toString().lowercase() 8 | map["errorReportingThread"] = thread.errorReportingThread 9 | map["state"] = thread.state.descriptor 10 | 11 | map["stacktrace"] = thread.stacktrace.map { 12 | val frame = mutableMapOf() 13 | frame["method"] = it.method 14 | frame["lineNumber"] = it.lineNumber 15 | frame["file"] = it.file 16 | frame["inProject"] = it.inProject 17 | frame 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/UserDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | import java.util.Map; 4 | 5 | class UserDeserializer implements MapDeserializer { 6 | @Override 7 | public User deserialize(Map map) { 8 | return new User( 9 | MapUtils.getOrNull(map, "id"), 10 | MapUtils.getOrNull(map, "email"), 11 | MapUtils.getOrNull(map, "name") 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/UserDeserializerTest.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Before 5 | import org.junit.Test 6 | import java.util.HashMap 7 | 8 | class UserDeserializerTest { 9 | 10 | private val map = HashMap() 11 | 12 | /** 13 | * Generates a map for verifying the serializer 14 | */ 15 | @Before 16 | fun setup() { 17 | map["id"] = "123" 18 | map["email"] = "joe@example.com" 19 | map["name"] = "Joe Bloggs" 20 | } 21 | 22 | @Test 23 | fun deserialize() { 24 | val user = UserDeserializer().deserialize(map) 25 | assertEquals("123", user.id) 26 | assertEquals("joe@example.com", user.email) 27 | assertEquals("Joe Bloggs", user.name) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bugsnag-plugin-react-native/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | compileOnly(gradleApi()) 11 | } 12 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "bugsnag-buildSrc" -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/Checkstyle.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.Project 2 | import org.gradle.api.plugins.quality.Checkstyle 3 | import org.gradle.api.plugins.quality.CheckstyleExtension 4 | import org.gradle.kotlin.dsl.get 5 | 6 | fun Project.configureCheckstyle() { 7 | extensions.getByType(CheckstyleExtension::class.java).apply { 8 | toolVersion = "8.18" 9 | } 10 | 11 | val checkstyle = tasks.register("checkstyle", Checkstyle::class.java) { 12 | configFile = rootProject.file("config/checkstyle/checkstyle.xml") 13 | source = fileTree("src/") { 14 | include("**/*.java") 15 | exclude("**/external/**/*.java") 16 | } 17 | classpath = files() 18 | } 19 | 20 | tasks["check"].dependsOn(checkstyle) 21 | } -------------------------------------------------------------------------------- /dockerfiles/Dockerfile.android-license-audit: -------------------------------------------------------------------------------- 1 | ARG BRANCH_NAME 2 | FROM 855461928731.dkr.ecr.us-west-1.amazonaws.com/android:ci-${BRANCH_NAME} as android 3 | 4 | RUN apt-get update && apt-get install -y ruby-full npm 5 | RUN gem install license_finder 6 | -------------------------------------------------------------------------------- /dockerfiles/Dockerfile.android-publisher: -------------------------------------------------------------------------------- 1 | FROM 855461928731.dkr.ecr.us-west-1.amazonaws.com/android:latest as android 2 | 3 | WORKDIR /app 4 | 5 | # Copy gradle files 6 | COPY gradlew gradle.properties /app/ 7 | COPY gradle/ /app/gradle/ 8 | COPY build.gradle.kts settings.gradle.kts /app/ 9 | COPY buildSrc/ buildSrc/ 10 | 11 | # Copy sdk source files 12 | COPY bugsnag-android/ bugsnag-android/ 13 | COPY bugsnag-android-core/ bugsnag-android-core/ 14 | COPY bugsnag-plugin-android-anr/ bugsnag-plugin-android-anr/ 15 | COPY bugsnag-plugin-android-exitinfo/ bugsnag-plugin-android-exitinfo/ 16 | COPY bugsnag-plugin-android-ndk/ bugsnag-plugin-android-ndk/ 17 | COPY bugsnag-plugin-android-okhttp/ bugsnag-plugin-android-okhttp/ 18 | COPY bugsnag-plugin-react-native/ bugsnag-plugin-react-native/ 19 | COPY scripts/ scripts/ 20 | COPY config/ config/ 21 | COPY LICENSE LICENSE 22 | 23 | CMD "scripts/docker-publish.sh" 24 | -------------------------------------------------------------------------------- /docs/NEW_MODULE_CHECKLIST.md: -------------------------------------------------------------------------------- 1 | # New Module Checklist 2 | 3 | A checklist of sanity checks for creating new modules in the repository. 4 | 5 | 1. Apply the `BugsnagBuildPlugin` to the new module and set plugin extension properties as necessary 6 | 2. Add a `README.md` describing the module 7 | 3. Ensure the module has consumer ProGuard rules (if necessary) 8 | 4. Confirm that the package name is correct and that a POM/AAR is generated correctly 9 | 5. Update the [Project Structure](PROJECT_STRUCTURE.md) docs 10 | 6. Claim the module on Google Play SDK Console 11 | -------------------------------------------------------------------------------- /examples/sdk-app-example/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /examples/sdk-app-example/README.md: -------------------------------------------------------------------------------- 1 | # Example Android integration with Bugsnag 2 | 3 | 1. Open the project root in `examples/sdk-app-example` with Android Studio 4 | 2. Insert your API key into the AndroidManifest.xml 5 | 3. Run the app! There are several examples of different kinds of errors which 6 | can be thrown. 7 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /examples/sdk-app-example/app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | find_package(bugsnag-plugin-android-ndk REQUIRED CONFIG) 4 | 5 | add_library(entrypoint SHARED 6 | src/main/cpp/entrypoint.cpp) 7 | 8 | set(EXTRA_LINK_FLAGS "-Wl,-z,max-page-size=16384") 9 | 10 | target_include_directories(entrypoint PRIVATE ${BUGSNAG_INCLUDE_DIR}) 11 | target_link_libraries(entrypoint bugsnag-plugin-android-ndk::bugsnag-ndk) 12 | 13 | set_target_properties( 14 | entrypoint 15 | PROPERTIES 16 | COMPILE_OPTIONS -Werror -Wall -pedantic 17 | LINK_FLAGS "${EXTRA_LINK_FLAGS}" 18 | ) 19 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/java/com/example/bugsnag/android/ExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.bugsnag.android 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | 6 | class ExampleActivity : BaseCrashyActivity() { 7 | override fun onCreate(savedInstanceState: Bundle?) { 8 | super.onCreate(savedInstanceState) 9 | findViewById(R.id.multi_process_header).visibility = View.VISIBLE 10 | findViewById(R.id.multi_process_start_btn).visibility = View.VISIBLE 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/java/com/example/bugsnag/android/MultiProcessActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.bugsnag.android 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | 6 | class MultiProcessActivity : BaseCrashyActivity() { 7 | override fun onCreate(savedInstanceState: Bundle?) { 8 | super.onCreate(savedInstanceState) 9 | findViewById(R.id.multi_process_title).visibility = View.VISIBLE 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/java/com/example/foo/CrashyClass.java: -------------------------------------------------------------------------------- 1 | package com.example.foo; 2 | 3 | public class CrashyClass { 4 | 5 | public static RuntimeException crash(String msg) { 6 | return sendMessage(msg); 7 | } 8 | 9 | private static RuntimeException sendMessage(String msg) { 10 | return new RuntimeException(msg); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #010E44 4 | #20212C 5 | #5BB6CB 6 | #010E44 7 | 8 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #010E44 4 | -------------------------------------------------------------------------------- /examples/sdk-app-example/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 11 | 12 | 18 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/sdk-app-example/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | alias(libs.plugins.android.application) apply false 4 | alias(libs.plugins.kotlin.android) apply false 5 | alias(libs.plugins.kotlin.compose) apply false 6 | alias(libs.plugins.bugsnag.gradle) apply false 7 | } -------------------------------------------------------------------------------- /examples/sdk-app-example/fakekeys.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/fakekeys.jks -------------------------------------------------------------------------------- /examples/sdk-app-example/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/examples/sdk-app-example/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/sdk-app-example/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri May 16 10:34:05 BST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /examples/sdk-app-example/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google { 4 | content { 5 | includeGroupByRegex("com\\.android.*") 6 | includeGroupByRegex("com\\.google.*") 7 | includeGroupByRegex("androidx.*") 8 | } 9 | } 10 | mavenCentral() 11 | gradlePluginPortal() 12 | } 13 | } 14 | dependencyResolutionManagement { 15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 16 | repositories { 17 | google() 18 | mavenCentral() 19 | } 20 | } 21 | 22 | rootProject.name = "Bugsnag Example" 23 | include(":app") 24 | -------------------------------------------------------------------------------- /features/fixtures/fakekeys.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/fakekeys.jks -------------------------------------------------------------------------------- /features/fixtures/mazerunner/README.md: -------------------------------------------------------------------------------- 1 | # Mazerunner fixture 2 | 3 | The test fixture uses Gradle modules to separate functionality, which makes it possible to assemble multiple fixtures. 4 | 5 | ## app 6 | 7 | Assembles an APK which provides a UI that Appium can use to drive scenarios. 8 | 9 | ## jvm-scenarios 10 | 11 | Library of scenarios that only require the JVM to crash. The `app` module always depends on this. 12 | 13 | ## cxx-scenarios 14 | 15 | Library of scenarios that only require the NDK (without bugsnag) to crash. The `app` module always depends on this. 16 | 17 | ## cxx-scenarios-bugsnag 18 | 19 | Library of scenarios that require the NDK and `bugsnag-plugin-android-ndk` to crash. The `app` module optionally depends on this. 20 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/fixtures/mazerunner/app/detekt-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MagicNumber:MainActivity.kt$MainActivity$1000 6 | MagicNumber:MainActivity.kt$MainActivity$250 7 | 8 | 9 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.bugsnag.android.mazerunner.** {*;} 2 | -keep class com.bugsnag.android.DeliveryDelegate {*;} 3 | -keepattributes LineNumberTable,SourceFile 4 | -renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /features/fixtures/mazerunner/app/src/main/java/com/bugsnag/android/BugsnagInternals.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android; 2 | 3 | public class BugsnagInternals { 4 | private BugsnagInternals() {} 5 | 6 | public static void flush() { 7 | Bugsnag.client.getEventStore().flushAsync(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/app/src/main/java/com/bugsnag/android/mazerunner/SecondActivity.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | 6 | class SecondActivity : Activity() { 7 | 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | super.onCreate(savedInstanceState) 10 | setContentView(R.layout.activity_main) 11 | log("Launched mazerunner fixture SecondActivity") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.1) 2 | project(cxx-scenarios-bugsnag) 3 | 4 | find_package(bugsnag-plugin-android-ndk REQUIRED CONFIG) 5 | 6 | add_library(cxx-scenarios-bugsnag SHARED 7 | src/main/cpp/cxx-scenarios-bugsnag.cpp 8 | src/main/cpp/CXXExternalStackElementScenario.cpp 9 | src/main/cpp/CXXExceptionSmokeScenario.cpp) 10 | 11 | set_target_properties(cxx-scenarios-bugsnag PROPERTIES 12 | CXX_STANDARD 11 13 | CXX_STANDARD_REQUIRED YES) 14 | 15 | target_include_directories(cxx-scenarios-bugsnag PRIVATE ${BUGSNAG_INCLUDE_DIR}) 16 | target_link_libraries(cxx-scenarios-bugsnag bugsnag-plugin-android-ndk::bugsnag-ndk) 17 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/cpp/CXXExceptionSmokeScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace magicstacks { 5 | 6 | class FatalProblem : std::runtime_error { 7 | using std::runtime_error::runtime_error; 8 | 9 | virtual ~FatalProblem() {} 10 | }; 11 | 12 | void __attribute__((optnone)) top() { 13 | throw new FatalProblem("well there it is!"); 14 | } 15 | 16 | void __attribute__((optnone)) middle() { top(); } 17 | 18 | void __attribute__((optnone)) start() { middle(); } 19 | } // namespace magicstacks 20 | 21 | extern "C" { 22 | JNIEXPORT int JNICALL 23 | Java_com_bugsnag_android_mazerunner_scenarios_CXXExceptionSmokeScenario_crash( 24 | JNIEnv *env, jobject instance) { 25 | magicstacks::start(); 26 | 27 | return 90; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXExceptionOnErrorTrueScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | class CXXExceptionOnErrorTrueScenario( 7 | config: Configuration, 8 | context: Context, 9 | eventMetadata: String? 10 | ) : Scenario(config, context, eventMetadata) { 11 | 12 | init { 13 | System.loadLibrary("bugsnag-ndk") 14 | System.loadLibrary("cxx-scenarios-bugsnag") 15 | } 16 | 17 | external fun crash() 18 | 19 | override fun startScenario() { 20 | super.startScenario() 21 | crash() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXHandledOverrideScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | internal class CXXHandledOverrideScenario( 8 | config: Configuration, 9 | context: Context, 10 | eventMetadata: String? 11 | ) : Scenario(config, context, eventMetadata) { 12 | 13 | init { 14 | System.loadLibrary("cxx-scenarios-bugsnag") 15 | } 16 | 17 | external fun activate() 18 | 19 | override fun startScenario() { 20 | super.startScenario() 21 | 22 | Bugsnag.startSession() 23 | activate() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXNaughtyStringsScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | import com.bugsnag.android.mazerunner.addNaughtyStringMetadata 6 | 7 | internal class CXXNaughtyStringsScenario( 8 | config: Configuration, 9 | context: Context, 10 | eventMetadata: String? 11 | ) : Scenario(config, context, eventMetadata) { 12 | 13 | init { 14 | System.loadLibrary("cxx-scenarios") 15 | } 16 | 17 | external fun crash() 18 | 19 | override fun startScenario() { 20 | super.startScenario() 21 | addNaughtyStringMetadata(javaClass) 22 | 23 | crash() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXRemoveOnErrorScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | class CXXRemoveOnErrorScenario( 7 | config: Configuration, 8 | context: Context, 9 | eventMetadata: String? 10 | ) : Scenario(config, context, eventMetadata) { 11 | 12 | init { 13 | System.loadLibrary("bugsnag-ndk") 14 | System.loadLibrary("cxx-scenarios-bugsnag") 15 | config.context = "CXXRemoveOnErrorScenario" 16 | } 17 | 18 | external fun activate() 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | activate() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/java/com/bugsnag/android/mazerunner/scenarios/ExitInfoScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | class ExitInfoScenario( 8 | config: Configuration, 9 | context: android.content.Context, 10 | eventMetadata: String? 11 | ) : Scenario(config, context, eventMetadata) { 12 | external fun crash(value: Int): Int 13 | override fun startScenario() { 14 | super.startScenario() 15 | Bugsnag.startSession() 16 | throw generateException() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/arm64-v8a/libmonochrome.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/arm64-v8a/libmonochrome.so -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/armeabi-v7a/libmonochrome.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/armeabi-v7a/libmonochrome.so -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/x86/libmonochrome.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/x86/libmonochrome.so -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/x86_64/libmonochrome.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/mazerunner/cxx-scenarios-bugsnag/src/main/jniLibs/x86_64/libmonochrome.so -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.1) 2 | project(cxx-scenarios) 3 | 4 | add_library(cxx-scenarios SHARED 5 | src/main/cpp/cxx-scenarios.cpp 6 | src/main/cpp/CXXAbortScenario.cpp 7 | src/main/cpp/CXXCallNullFunctionPointerScenario.cpp 8 | src/main/cpp/CXXDereferenceNullScenario.cpp 9 | src/main/cpp/CXXImproperTypecastScenario.cpp 10 | src/main/cpp/CXXInvalidRethrow.cpp 11 | src/main/cpp/CXXStackoverflowScenario.cpp 12 | src/main/cpp/CXXThrowFromNoexcept.cpp 13 | src/main/cpp/CXXTrapScenario.cpp 14 | src/main/cpp/CXXWriteReadOnlyMemoryScenario.cpp 15 | src/main/cpp/bugsnag-java-scenarios.cpp) 16 | 17 | set_target_properties(cxx-scenarios PROPERTIES 18 | CXX_STANDARD 11 19 | CXX_STANDARD_REQUIRED YES) 20 | 21 | target_link_libraries(cxx-scenarios) 22 | 23 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/detekt-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MagicNumber:CXXDelayedCrashScenario.kt$CXXDelayedCrashScenario$405 6 | MagicNumber:CXXIgnoredSigabrtScenario.kt$CXXIgnoredSigabrtScenario$2726 7 | MagicNumber:CXXSessionInfoCrashScenario.kt$CXXSessionInfoCrashScenario$3 8 | MagicNumber:CXXSessionInfoCrashScenario.kt$CXXSessionInfoCrashScenario$3837 9 | MagicNumber:CXXThrowSomethingOutsideReleaseStagesScenario.kt$CXXThrowSomethingOutsideReleaseStagesScenario$23 10 | 11 | 12 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXAbortScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace evictor { 5 | void __attribute__((optnone)) exit_with_style() { abort(); } 6 | } // namespace evictor 7 | 8 | extern "C" { 9 | JNIEXPORT void JNICALL 10 | Java_com_bugsnag_android_mazerunner_scenarios_CXXAbortScenario_crash( 11 | JNIEnv *env, jobject instance) { 12 | // added namespaces for variety between tests 13 | evictor::exit_with_style(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXCallNullFunctionPointerScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void (*definitely_valid_func)(jobject) = 0; 4 | 5 | namespace dispatch { 6 | class Handler { 7 | public: 8 | static void __attribute__((optnone)) handle(jobject obj) { 9 | definitely_valid_func(obj); 10 | } 11 | }; 12 | } // namespace dispatch 13 | 14 | extern "C" { 15 | JNIEXPORT void JNICALL 16 | Java_com_bugsnag_android_mazerunner_scenarios_CXXCallNullFunctionPointerScenario_crash( 17 | JNIEnv *env, jobject instance) { 18 | dispatch::Handler::handle(instance); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXDereferenceNullScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static volatile int *the_value; 4 | 5 | int __attribute__((optnone)) get_the_null_value() { 6 | // assume this function is very interesting 7 | return *the_value; 8 | } 9 | 10 | extern "C" { 11 | JNIEXPORT jint JNICALL 12 | Java_com_bugsnag_android_mazerunner_scenarios_CXXDereferenceNullScenario_crash( 13 | JNIEnv *env, jobject instance) { 14 | return get_the_null_value(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXImproperTypecastScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | char *text; 7 | } weird_obj_t; 8 | 9 | char *__attribute__((optnone)) crash_improper_cast(void *counter) { 10 | weird_obj_t *obj = (weird_obj_t *)counter; 11 | 12 | return obj->text; 13 | } 14 | 15 | extern "C" { 16 | 17 | JNIEXPORT void JNICALL 18 | Java_com_bugsnag_android_mazerunner_scenarios_CXXImproperTypecastScenario_crash( 19 | JNIEnv *env, jobject instance) { 20 | printf("This one here: %s\n", crash_improper_cast((void *)39)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXInvalidRethrow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void __attribute__((optnone)) print_last_exception() { 6 | try { 7 | throw; 8 | } catch (std::exception *ex) { 9 | // should never get here, since there is no exception. 10 | printf("ex: %p", ex); 11 | } 12 | } 13 | 14 | extern "C" { 15 | JNIEXPORT void JNICALL 16 | Java_com_bugsnag_android_mazerunner_scenarios_CXXInvalidRethrow_crash( 17 | JNIEnv *env, jobject instance) { 18 | print_last_exception(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXStackoverflowScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern "C" { 6 | int __attribute__((optnone)) __attribute__((noinline)) crash_stack_overflow(int counter, char *input) { 7 | char stack[7]; 8 | char *output = stack; 9 | 10 | while (*input) { 11 | *output = *input; 12 | input++; 13 | output++; 14 | } 15 | 16 | return 4 / counter; 17 | } 18 | 19 | JNIEXPORT void JNICALL 20 | Java_com_bugsnag_android_mazerunner_scenarios_CXXStackoverflowScenario_crash( 21 | JNIEnv *env, jobject instance, jint counter, jstring text_) { 22 | char *text = (char *)(*env).GetStringUTFChars(text_, 0); 23 | printf("This one here: %ld\n", 24 | (long)crash_stack_overflow((int)counter, text)); 25 | (*env).ReleaseStringUTFChars(text_, text); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXThrowFromNoexcept.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class FunkError : public std::runtime_error { 6 | using std::runtime_error::runtime_error; 7 | 8 | const char *toss_an_exception() const { 9 | throw new FunkError("you done it now!"); 10 | } 11 | 12 | public: 13 | virtual const char *what() const noexcept { return toss_an_exception(); } 14 | }; 15 | 16 | extern "C" { 17 | JNIEXPORT void JNICALL 18 | Java_com_bugsnag_android_mazerunner_scenarios_CXXThrowFromNoexcept_crash( 19 | JNIEnv *env, jobject instance) { 20 | auto err = new FunkError("mistakes were made"); 21 | printf("what? %s", err->what()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXTrapScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int __attribute__((optnone)) trap_it() { 7 | time_t now; 8 | now = time(&now); 9 | 10 | // do not format or bracket the following line, ndk r16 has a bug and 11 | // will write the wrong line number in the debug info: 12 | if (now > 0) __builtin_trap(); 13 | 14 | return 0; 15 | } 16 | 17 | extern "C" { 18 | 19 | JNIEXPORT void JNICALL 20 | Java_com_bugsnag_android_mazerunner_scenarios_CXXTrapScenario_crash( 21 | JNIEnv *env, jobject instance) { 22 | printf("This one here: %ld\n", (long)trap_it()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/cpp/CXXWriteReadOnlyMemoryScenario.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static char * __attribute__((used)) somefakefunc(void) { 6 | return NULL; 7 | }; 8 | 9 | int crash_write_read_only_mem(int counter) { 10 | if (counter > 2) { 11 | int *pointer = (int *)&somefakefunc; 12 | *pointer = counter; 13 | } 14 | return counter / 14; 15 | } 16 | 17 | extern "C" { 18 | 19 | JNIEXPORT void JNICALL 20 | Java_com_bugsnag_android_mazerunner_scenarios_CXXWriteReadOnlyMemoryScenario_crash(JNIEnv *env, 21 | jobject instance) { 22 | printf("This one here: %d\n", crash_write_read_only_mem(42)); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXAbortScenario.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios; 2 | 3 | import com.bugsnag.android.Configuration; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | public class CXXAbortScenario extends Scenario { 11 | 12 | static { 13 | System.loadLibrary("cxx-scenarios"); 14 | } 15 | 16 | public native void crash(); 17 | 18 | public CXXAbortScenario(@NonNull Configuration config, 19 | @NonNull Context context, 20 | @Nullable String eventMetadata) { 21 | super(config, context, eventMetadata); 22 | } 23 | 24 | @Override 25 | public void startScenario() { 26 | super.startScenario(); 27 | crash(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXAnrNdkDisabledScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | /** 7 | * Stops the app from responding for a time period 8 | */ 9 | internal class CXXAnrNdkDisabledScenario( 10 | config: Configuration, 11 | context: Context, 12 | eventMetadata: String? 13 | ) : Scenario(config, context, eventMetadata) { 14 | 15 | companion object { 16 | init { 17 | System.loadLibrary("cxx-scenarios") 18 | } 19 | } 20 | 21 | init { 22 | config.enabledErrorTypes.anrs = true 23 | config.enabledErrorTypes.ndkCrashes = false 24 | } 25 | 26 | external fun crash() 27 | 28 | override fun startScenario() { 29 | super.startScenario() 30 | crash() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXAnrScenario.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios; 2 | 3 | import com.bugsnag.android.Configuration; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | public class CXXAnrScenario extends Scenario { 11 | 12 | static { 13 | System.loadLibrary("cxx-scenarios"); 14 | } 15 | 16 | public native void crash(); 17 | 18 | public CXXAnrScenario(@NonNull Configuration config, 19 | @NonNull Context context, 20 | @Nullable String eventMetadata) { 21 | super(config, context, eventMetadata); 22 | } 23 | 24 | @Override 25 | public void startScenario() { 26 | super.startScenario(); 27 | crash(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXCallNullFunctionPointerScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | class CXXCallNullFunctionPointerScenario( 7 | config: Configuration, 8 | context: Context, 9 | eventMetadata: String? 10 | ) : Scenario(config, context, eventMetadata) { 11 | 12 | companion object { 13 | init { 14 | System.loadLibrary("cxx-scenarios") 15 | } 16 | } 17 | 18 | external fun crash() 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | crash() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXExceptionScenario.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios; 2 | 3 | import com.bugsnag.android.Configuration; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | public class CXXExceptionScenario extends Scenario { 11 | 12 | static { 13 | System.loadLibrary("cxx-scenarios"); 14 | } 15 | 16 | public native void crash(); 17 | 18 | public CXXExceptionScenario(@NonNull Configuration config, 19 | @NonNull Context context, 20 | @Nullable String eventMetadata) { 21 | super(config, context, eventMetadata); 22 | } 23 | 24 | @Override 25 | public void startScenario() { 26 | super.startScenario(); 27 | crash(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXIgnoredSigabrtScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | import java.util.regex.Pattern 6 | 7 | internal class CXXIgnoredSigabrtScenario( 8 | config: Configuration, 9 | context: Context, 10 | eventMetadata: String 11 | ) : Scenario(config, context, eventMetadata) { 12 | 13 | init { 14 | config.discardClasses = setOf(Pattern.compile(eventMetadata)) 15 | System.loadLibrary("cxx-scenarios") 16 | } 17 | 18 | external fun crash(value: Int): Int 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | crash(2726) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXInvalidRethrow.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | class CXXInvalidRethrow( 7 | config: Configuration, 8 | context: Context, 9 | eventMetadata: String? 10 | ) : Scenario(config, context, eventMetadata) { 11 | 12 | companion object { 13 | init { 14 | System.loadLibrary("cxx-scenarios") 15 | } 16 | } 17 | 18 | external fun crash() 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | crash() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXMaxBreadcrumbCrashScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | private const val MAX_BREADCRUMB_COUNT = 500 8 | 9 | class CXXMaxBreadcrumbCrashScenario( 10 | config: Configuration, 11 | context: Context, 12 | eventMetadata: String? 13 | ) : Scenario(config, context, eventMetadata) { 14 | init { 15 | config.maxBreadcrumbs = MAX_BREADCRUMB_COUNT 16 | } 17 | 18 | external fun activate() 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | repeat(config.maxBreadcrumbs) { index -> 23 | Bugsnag.leaveBreadcrumb("this is breadcrumb $index") 24 | } 25 | 26 | activate() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXThrowFromNoexcept.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | class CXXThrowFromNoexcept( 7 | config: Configuration, 8 | context: Context, 9 | eventMetadata: String? 10 | ) : Scenario(config, context, eventMetadata) { 11 | 12 | companion object { 13 | init { 14 | System.loadLibrary("cxx-scenarios") 15 | } 16 | } 17 | 18 | external fun crash() 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | crash() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXTrapScenario.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios; 2 | 3 | import com.bugsnag.android.Configuration; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | public class CXXTrapScenario extends Scenario { 11 | 12 | static { 13 | System.loadLibrary("cxx-scenarios"); 14 | } 15 | 16 | public native void crash(); 17 | 18 | public CXXTrapScenario(@NonNull Configuration config, 19 | @NonNull Context context, 20 | @Nullable String eventMetadata) { 21 | super(config, context, eventMetadata); 22 | } 23 | 24 | @Override 25 | public void startScenario() { 26 | super.startScenario(); 27 | crash(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/cxx-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UnhandledNdkAutoNotifyTrueScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.setAutoNotify 7 | 8 | class UnhandledNdkAutoNotifyTrueScenario( 9 | config: Configuration, 10 | context: Context, 11 | eventMetadata: String? 12 | ) : Scenario(config, context, eventMetadata) { 13 | 14 | init { 15 | System.loadLibrary("cxx-scenarios") 16 | } 17 | 18 | external fun crash() 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | setAutoNotify(Bugsnag.getClient(), false) 23 | setAutoNotify(Bugsnag.getClient(), true) 24 | crash() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/gradle.properties: -------------------------------------------------------------------------------- 1 | android.useAndroidX=true 2 | org.gradle.jvmargs=-Xmx4096m 3 | org.gradle.parallel=true 4 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/gradle/checkstyle.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "checkstyle" 2 | 3 | checkstyle { 4 | toolVersion = "8.18" 5 | } 6 | 7 | def checkstyle = task("checkstyle", type: Checkstyle) { 8 | configFile rootProject.file("config/checkstyle/checkstyle.xml") 9 | source "src/" 10 | include "**/*.java" 11 | exclude "**/external/**/*.java" 12 | classpath = files() 13 | } 14 | 15 | tasks.findByName("check").dependsOn(checkstyle) 16 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/mazerunner/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /features/fixtures/mazerunner/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.bugsnag.android.mazerunner.scenarios.** {*;} 2 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/NaughtyStrings.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner 2 | 3 | import com.bugsnag.android.Bugsnag 4 | 5 | fun addNaughtyStringMetadata(clz: Class) { 6 | val stream = clz.classLoader!!.getResourceAsStream("naughty_strings.txt") 7 | var count = 1 8 | stream.reader().forEachLine { line -> 9 | Bugsnag.addMetadata("custom", "val_$count", line) 10 | count += 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/SomeException.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner 2 | 3 | internal class SomeException : Exception() 4 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/ArrayEnabledReleaseStageScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Attempts to send a handled exception to Bugsnag, when the enabledReleaseStages is an array. 9 | */ 10 | internal class ArrayEnabledReleaseStageScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | init { 17 | config.releaseStage = "prod" 18 | config.enabledReleaseStages = setOf("dev", "prod") 19 | } 20 | 21 | override fun startScenario() { 22 | super.startScenario() 23 | Bugsnag.notify(generateException()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/AutoRedactKeysScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which contains metadata that should be filtered 9 | */ 10 | internal class AutoRedactKeysScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.addMetadata("user", "password", "hunter2") 19 | Bugsnag.addMetadata("custom", "password", "hunter2") 20 | Bugsnag.addMetadata("custom", "foo", "hunter2") 21 | Bugsnag.notify(generateException()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/BreadcrumbAutoScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.BreadcrumbType 5 | import com.bugsnag.android.Bugsnag 6 | import com.bugsnag.android.Configuration 7 | 8 | /** 9 | * Sends a handled exception to Bugsnag, which includes manual breadcrumbs. 10 | */ 11 | internal class BreadcrumbAutoScenario( 12 | config: Configuration, 13 | context: Context, 14 | eventMetadata: String 15 | ) : Scenario(config, context, eventMetadata) { 16 | 17 | init { 18 | config.enabledBreadcrumbTypes = setOf(BreadcrumbType.STATE) 19 | } 20 | 21 | override fun startScenario() { 22 | super.startScenario() 23 | Bugsnag.notify(generateException()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/BreadcrumbDisabledScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which includes manual breadcrumbs. 9 | */ 10 | internal class BreadcrumbDisabledScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | init { 17 | config.enabledBreadcrumbTypes = emptySet() 18 | } 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | Bugsnag.leaveBreadcrumb("Hello Breadcrumb!") 23 | Bugsnag.notify(generateException()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CustomPluginExample.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import com.bugsnag.android.Client 4 | import com.bugsnag.android.OnErrorCallback 5 | import com.bugsnag.android.Plugin 6 | 7 | class CustomPluginExample : Plugin { 8 | 9 | override fun load(client: Client) { 10 | client.addOnError( 11 | OnErrorCallback { event -> 12 | event.context = "Foo Handler Library" 13 | true 14 | } 15 | ) 16 | } 17 | 18 | override fun unload() {} 19 | } 20 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/CustomPluginNotifierDescriptionScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | internal class CustomPluginNotifierDescriptionScenario( 8 | config: Configuration, 9 | context: Context, 10 | eventMetadata: String 11 | ) : Scenario(config, context, eventMetadata) { 12 | 13 | init { 14 | config.addPlugin(CustomPluginExample()) 15 | } 16 | 17 | override fun startScenario() { 18 | super.startScenario() 19 | Bugsnag.notify(RuntimeException()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/DiscardOldSessionScenarioPart3.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | internal class DiscardOldSessionScenarioPart3( 7 | config: Configuration, 8 | context: Context, 9 | eventMetadata: String 10 | ) : Scenario(config, context, eventMetadata) { 11 | 12 | init { 13 | config.launchDurationMillis = 0 14 | // Note: No impediments to sending. 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/EmptyStacktraceScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import com.bugsnag.android.Bugsnag 6 | import com.bugsnag.android.Configuration 7 | 8 | /** 9 | * Attempts to deliver a handled exception with no stacktrace. 10 | */ 11 | internal class EmptyStacktraceScenario( 12 | config: Configuration, 13 | context: Context, 14 | eventMetadata: String 15 | ) : Scenario(config, context, eventMetadata) { 16 | 17 | override fun startScenario() { 18 | super.startScenario() 19 | Bugsnag.notify(EmptyException("EmptyStacktraceScenario")) 20 | } 21 | 22 | @SuppressLint("NewApi") 23 | class EmptyException(message: String?) : Throwable(message, null, true, false) 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/ErrorBreadcrumbsScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.BreadcrumbType 5 | import com.bugsnag.android.Bugsnag 6 | import com.bugsnag.android.Configuration 7 | 8 | class ErrorBreadcrumbsScenario( 9 | config: Configuration, 10 | context: Context, 11 | eventMetadata: String? 12 | ) : Scenario( 13 | config.apply { 14 | enabledBreadcrumbTypes = setOf(BreadcrumbType.ERROR) 15 | }, 16 | context, 17 | eventMetadata 18 | ) { 19 | override fun startScenario() { 20 | Bugsnag.notify(RuntimeException("first error")) 21 | throw NullPointerException("something broke") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/HandledExceptionApiKeyChangeScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag where the API key is changed in a callback 9 | */ 10 | internal class HandledExceptionApiKeyChangeScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.notify(generateException()) { event -> 19 | event.apiKey = "0000111122223333aaaabbbbcccc9999" 20 | true 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/HandledExceptionMaxThreadsScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which does not include session data. 9 | */ 10 | internal class HandledExceptionMaxThreadsScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | init { 17 | config.maxReportedThreads = 3 18 | } 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | Bugsnag.notify(generateException()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/HandledExceptionScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which does not include session data. 9 | */ 10 | internal class HandledExceptionScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.notify(generateException()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/HandledExceptionWithoutMessageScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.mazerunner.SomeException 7 | 8 | /** 9 | * Sends a handled exception to Bugsnag, which does not include session data. 10 | */ 11 | internal class HandledExceptionWithoutMessageScenario( 12 | config: Configuration, 13 | context: Context, 14 | eventMetadata: String 15 | ) : Scenario(config, context, eventMetadata) { 16 | 17 | override fun startScenario() { 18 | super.startScenario() 19 | Bugsnag.notify(SomeException()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/HandledJvmAutoNotifyFalseScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.setAutoNotify 7 | 8 | class HandledJvmAutoNotifyFalseScenario( 9 | config: Configuration, 10 | context: Context, 11 | eventMetadata: String? 12 | ) : Scenario(config, context, eventMetadata) { 13 | 14 | override fun startScenario() { 15 | super.startScenario() 16 | setAutoNotify(Bugsnag.getClient(), false) 17 | Bugsnag.notify(generateException()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/InternalErrorDisabledScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.JavaHooks.triggerInternalBugsnagForError 7 | 8 | internal class InternalErrorDisabledScenario( 9 | config: Configuration, 10 | context: Context, 11 | eventMetadata: String 12 | ) : Scenario(config, context, eventMetadata) { 13 | 14 | init { 15 | config.telemetry = setOf() 16 | } 17 | 18 | override fun startScenario() { 19 | super.startScenario() 20 | triggerInternalBugsnagForError(Bugsnag.getClient()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/InternalErrorScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.JavaHooks.triggerInternalBugsnagForError 7 | 8 | internal class InternalErrorScenario( 9 | config: Configuration, 10 | context: Context, 11 | eventMetadata: String 12 | ) : Scenario(config, context, eventMetadata) { 13 | 14 | override fun startScenario() { 15 | super.startScenario() 16 | triggerInternalBugsnagForError(Bugsnag.getClient()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/JvmAnrDisabledScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.mazerunner.createDeadlock 7 | 8 | /** 9 | * Stops the app from responding for a time period with ANR detection disabled 10 | */ 11 | internal class JvmAnrDisabledScenario( 12 | config: Configuration, 13 | context: Context, 14 | eventMetadata: String? 15 | ) : Scenario(config, context, eventMetadata) { 16 | 17 | init { 18 | config.enabledErrorTypes.anrs = false 19 | } 20 | 21 | override fun startScenario() { 22 | super.startScenario() 23 | Bugsnag.notify(generateException()) 24 | createDeadlock() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/JvmAnrMinimalFixtureScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.mazerunner.createDeadlock 7 | 8 | /** 9 | * Stops the app from responding for a time period 10 | */ 11 | internal class JvmAnrMinimalFixtureScenario( 12 | config: Configuration, 13 | context: Context, 14 | eventMetadata: String? 15 | ) : Scenario(config, context, eventMetadata) { 16 | 17 | init { 18 | config.enabledErrorTypes.anrs = false 19 | } 20 | 21 | override fun startScenario() { 22 | super.startScenario() 23 | Bugsnag.notify(generateException()) 24 | createDeadlock() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/JvmMarkLaunchCompletedScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a JVM error to Bugsnag after markLaunchCompleted() is invoked. 9 | */ 10 | internal class JvmMarkLaunchCompletedScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String? 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | init { 17 | config.launchDurationMillis = 0 18 | } 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | Bugsnag.notify(RuntimeException("first error")) 23 | Bugsnag.markLaunchCompleted() 24 | Bugsnag.notify(generateException()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/MetadataScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which includes custom metadata 9 | */ 10 | internal class MetadataScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.notify(RuntimeException("MetadataScenario")) { 19 | it.addMetadata("Custom", "foo", "Hello World!") 20 | true 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/NaughtyStringScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.mazerunner.addNaughtyStringMetadata 7 | 8 | /** 9 | * Sends a handled exception to Bugsnag containing unusual string data 10 | * from https://github.com/minimaxir/big-list-of-naughty-strings 11 | */ 12 | internal class NaughtyStringScenario( 13 | config: Configuration, 14 | context: Context, 15 | eventMetadata: String? 16 | ) : Scenario(config, context, eventMetadata) { 17 | 18 | override fun startScenario() { 19 | super.startScenario() 20 | addNaughtyStringMetadata(javaClass) 21 | Bugsnag.notify(generateException()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/NullStackTraceScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import com.bugsnag.android.Bugsnag 6 | import com.bugsnag.android.Configuration 7 | 8 | @SuppressLint("NewApi") 9 | class MyThrowable(message: String?) : Throwable(message, null, false, false) { 10 | override fun getStackTrace() = null 11 | } 12 | 13 | /** 14 | * Sends an unhandled exception to Bugsnag. 15 | */ 16 | internal class NullStackTraceScenario( 17 | config: Configuration, 18 | context: Context, 19 | eventMetadata: String 20 | ) : Scenario(config, context, eventMetadata) { 21 | 22 | override fun startScenario() { 23 | super.startScenario() 24 | Bugsnag.notify(MyThrowable("NullStackTraceScenario")) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/OverrideToUnhandledExceptionScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Generates a handled exception that is overridden so that unhandled is true. 9 | */ 10 | internal class OverrideToUnhandledExceptionScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String? 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.startSession() 19 | Bugsnag.notify(generateException()) { 20 | it.isUnhandled = true 21 | true 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/SessionPersistUserScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a session which is cached on disk to Bugsnag, then sent on a separate launch. 9 | */ 10 | internal class SessionPersistUserScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | init { 17 | config.persistUser = true 18 | } 19 | 20 | override fun startScenario() { 21 | super.startScenario() 22 | if (eventMetadata != "no_user") { 23 | Bugsnag.setUser("12345", "test@test.test", "test user") 24 | } 25 | Bugsnag.startSession() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/StackOverflowScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | /** 7 | * Triggers a StackOverflow by recursing infinitely 8 | */ 9 | internal class StackOverflowScenario( 10 | config: Configuration, 11 | context: Context, 12 | eventMetadata: String 13 | ) : Scenario(config, context, eventMetadata) { 14 | 15 | override fun startScenario() { 16 | super.startScenario() 17 | calculateValue(0) 18 | } 19 | 20 | private fun calculateValue(count: Long): Long { 21 | return calculateValue(count + 1) + calculateValue(count - 1) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UnhandledExceptionMaxThreadsScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | /** 7 | * Sends an unhandled exception to Bugsnag. 8 | */ 9 | internal class UnhandledExceptionMaxThreadsScenario( 10 | config: Configuration, 11 | context: Context, 12 | eventMetadata: String 13 | ) : Scenario(config, context, eventMetadata) { 14 | 15 | init { 16 | config.maxReportedThreads = 2 17 | } 18 | 19 | override fun startScenario() { 20 | super.startScenario() 21 | throw generateException() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UnhandledExceptionScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Configuration 5 | 6 | /** 7 | * Sends an unhandled exception to Bugsnag. 8 | */ 9 | internal class UnhandledExceptionScenario( 10 | config: Configuration, 11 | context: Context, 12 | eventMetadata: String 13 | ) : Scenario(config, context, eventMetadata) { 14 | 15 | override fun startScenario() { 16 | super.startScenario() 17 | throw generateException() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UnhandledJvmAutoNotifyTrueScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | import com.bugsnag.android.setAutoNotify 7 | 8 | class UnhandledJvmAutoNotifyTrueScenario( 9 | config: Configuration, 10 | context: Context, 11 | eventMetadata: String? 12 | ) : Scenario(config, context, eventMetadata) { 13 | 14 | override fun startScenario() { 15 | super.startScenario() 16 | setAutoNotify(Bugsnag.getClient(), false) 17 | setAutoNotify(Bugsnag.getClient(), true) 18 | throw generateException() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UnsatisfiedLinkErrorScenario.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios; 2 | 3 | import com.bugsnag.android.Configuration; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | public class UnsatisfiedLinkErrorScenario extends Scenario { 11 | 12 | public native void doesNotExist(); 13 | 14 | public UnsatisfiedLinkErrorScenario(@NonNull Configuration config, 15 | @NonNull Context context, 16 | @Nullable String eventMetadata) { 17 | super(config, context, eventMetadata); 18 | } 19 | 20 | @Override 21 | public void startScenario() { 22 | super.startScenario(); 23 | doesNotExist(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UserCallbackScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which overrides the default user via a callback 9 | */ 10 | internal class UserCallbackScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.setUser("abc", "user@example.com", "Jake") 19 | Bugsnag.notify(generateException()) { 20 | it.setUser("Agent Pink", "bob@example.com", "Zebedee") 21 | true 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UserDisabledScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which does not include user data. 9 | */ 10 | internal class UserDisabledScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.setUser(null, null, null) 19 | Bugsnag.notify(generateException()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/UserIdScenario.kt: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.mazerunner.scenarios 2 | 3 | import android.content.Context 4 | import com.bugsnag.android.Bugsnag 5 | import com.bugsnag.android.Configuration 6 | 7 | /** 8 | * Sends a handled exception to Bugsnag, which only includes a user's id 9 | */ 10 | internal class UserIdScenario( 11 | config: Configuration, 12 | context: Context, 13 | eventMetadata: String 14 | ) : Scenario(config, context, eventMetadata) { 15 | 16 | override fun startScenario() { 17 | super.startScenario() 18 | Bugsnag.setUser("abc", null, null) 19 | Bugsnag.notify(generateException()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/jvm-scenarios/src/main/resources/naughty_strings.txt: -------------------------------------------------------------------------------- 1 | ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя 2 | 田中さんにあげて下さい 3 | 𐐜 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐙𐐊𐐡𐐝𐐓/𐐝𐐇𐐗𐐊𐐤𐐔 𐐒𐐋𐐗 𐐒𐐌 𐐜 𐐡𐐀𐐖𐐇𐐤𐐓𐐝 𐐱𐑂 𐑄 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐏𐐆𐐅𐐤𐐆𐐚𐐊𐐡𐐝𐐆𐐓𐐆 4 | 表ポあA鷗ŒéB逍Üߪąñ丂㐀𠀀 5 | ,。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’ 6 | ❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙 7 | ✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿 8 | 👨‍👩‍👦 👨‍👩‍👧‍👦 👨‍👨‍👦 👩‍👩‍👧 👨‍👦 👨‍👧‍👦 👩‍👦 👩‍👧‍👦 9 | 🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧 10 | 123 11 | الكل في المجمو عة (5) 12 | ˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ 13 | 𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰 14 | گچپژ 15 | -------------------------------------------------------------------------------- /features/fixtures/mazerunner/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':cxx-scenarios-bugsnag' 2 | include ':cxx-scenarios' 3 | include ':jvm-scenarios' 4 | include ':app' -------------------------------------------------------------------------------- /features/fixtures/minimalapp/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /features/fixtures/minimalapp/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 6 | 7 | # gem "rails" 8 | 9 | gem "danger", "~> 9" 10 | gem "git", ">= 1.13.0" # Force update of git gem to avoid CVE-2022-46648 -------------------------------------------------------------------------------- /features/fixtures/minimalapp/app/fakekeys.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/minimalapp/app/fakekeys.jks -------------------------------------------------------------------------------- /features/fixtures/minimalapp/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /features/fixtures/minimalapp/app/src/main/java/com/bugsnag/android/minimalapp/CustomApp.java: -------------------------------------------------------------------------------- 1 | package com.bugsnag.android.minimalapp; 2 | 3 | import android.app.Application; 4 | 5 | class CustomApp extends Application { 6 | @Override 7 | public void onCreate() { 8 | super.onCreate(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /features/fixtures/minimalapp/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = "1.4.32" 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath "com.android.tools.build:gradle:7.0.3" 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | if (project.hasProperty("withBugsnag")) { 13 | classpath "com.bugsnag:bugsnag-android-gradle-plugin:7.1.0" 14 | } 15 | // NOTE: Do not place your application dependencies here; they belong 16 | // in the individual module build.gradle.kts files 17 | } 18 | } 19 | 20 | task clean(type: Delete) { 21 | delete rootProject.buildDir 22 | } 23 | -------------------------------------------------------------------------------- /features/fixtures/minimalapp/gradle.properties: -------------------------------------------------------------------------------- 1 | android.useAndroidX=true 2 | org.gradle.jvmargs=-Xmx4096m 3 | org.gradle.parallel=true 4 | -------------------------------------------------------------------------------- /features/fixtures/minimalapp/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/features/fixtures/minimalapp/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /features/fixtures/minimalapp/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /features/fixtures/minimalapp/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /features/full_tests/bugsnag_init.feature: -------------------------------------------------------------------------------- 1 | Feature: Verify the Bugsnag Initialization methods 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Test Bugsnag initializes correctly 7 | When I run "BugsnagInitScenario" 8 | And I wait to receive an error 9 | Then the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 10 | And the event "metaData.client.count" equals 1 11 | -------------------------------------------------------------------------------- /features/full_tests/detect_ndk_crashes.feature: -------------------------------------------------------------------------------- 1 | Feature: Verifies autoDetectNdkCrashes controls when NDK crashes are reported 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: No crash reported when autoDetectNdkCrashes disabled 7 | When I run "AutoDetectNdkDisabledScenario" and relaunch the crashed app 8 | And I configure Bugsnag for "AutoDetectNdkDisabledScenario" 9 | Then Bugsnag confirms it has no errors to send 10 | -------------------------------------------------------------------------------- /features/full_tests/empty_stacktrace.feature: -------------------------------------------------------------------------------- 1 | Feature: Empty Stacktrace reported 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Exceptions with empty stacktraces are sent 7 | When I run "EmptyStacktraceScenario" 8 | Then I wait to receive an error 9 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 10 | And the error payload field "notifier.name" equals "Android Bugsnag Notifier" 11 | And the error payload field "events" is an array with 1 elements 12 | And the exception "errorClass" equals "com.bugsnag.android.mazerunner.scenarios.EmptyStacktraceScenario$EmptyException" 13 | And the error payload field "events.0.exceptions.0.stacktrace" is an array with 0 elements 14 | -------------------------------------------------------------------------------- /features/full_tests/exit_information.feature: -------------------------------------------------------------------------------- 1 | Feature: Application exitInfo is reported in crashes 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | @skip_below_android_11 7 | Scenario: Application exitInfo is reported in crashes 8 | When I set the screen orientation to portrait 9 | And I run "ExitInfoScenario" and relaunch the crashed app 10 | And I configure Bugsnag for "ExitInfoScenario" 11 | And I wait to receive an error 12 | Then the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 13 | And the event "metaData.app.processImportance" equals "foreground" 14 | And the event "metaData.app.exitReason" is not null 15 | -------------------------------------------------------------------------------- /features/full_tests/handled_exception.feature: -------------------------------------------------------------------------------- 1 | Feature: Reporting handled Exceptions 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Report a handled exception without a message 7 | When I run "HandledExceptionWithoutMessageScenario" 8 | Then I wait to receive an error 9 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 10 | And the error payload field "events" is an array with 1 elements 11 | And the exception "errorClass" equals "com.bugsnag.android.mazerunner.SomeException" 12 | And the event "exceptions.0.message" is null 13 | And the error payload field "events.0.device.cpuAbi" is a non-empty array 14 | -------------------------------------------------------------------------------- /features/full_tests/in_foreground.feature: -------------------------------------------------------------------------------- 1 | Feature: In foreground field populates correctly 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Test handled exception in background 7 | When I run "InForegroundScenario" 8 | Then I wait to receive an error 9 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 10 | # PLAT-9155 Flaky: the event "app.inForeground" is false 11 | And the error is correct for "InForegroundScenario" or I allow a retry 12 | -------------------------------------------------------------------------------- /features/full_tests/meta_data_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: Reporting metadata 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Sends a handled exception which includes custom metadata added in a notify callback 7 | When I run "MetadataScenario" 8 | Then I wait to receive an error 9 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 10 | And the event "metaData.Custom.foo" equals "Hello World!" 11 | 12 | Scenario: Add nested null value to metadata tab 13 | When I run "MetadataNestedNullScenario" 14 | Then I wait to receive an error 15 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 16 | -------------------------------------------------------------------------------- /features/full_tests/native_context.feature: -------------------------------------------------------------------------------- 1 | Feature: Native Context API 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Changing intents followed by notifying in C 7 | When I run "CXXAutoContextScenario" 8 | Then I wait to receive 2 errors 9 | 10 | Then the error payload contains a completed handled native report 11 | And the event "severity" equals "info" 12 | And the event "context" equals "SecondActivity" 13 | And the exception "errorClass" equals "Hello hello" 14 | And the exception "message" equals "This is a new world" 15 | And the event "unhandled" is false 16 | And I discard the oldest error 17 | 18 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 19 | And the exception "message" equals "CXXAutoContextScenario" 20 | And the event "context" equals "SecondActivity" 21 | -------------------------------------------------------------------------------- /features/full_tests/null_stacktrace.feature: -------------------------------------------------------------------------------- 1 | Feature: Null Stacktrace reported 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Exceptions with null stacktraces are sent 7 | When I run "NullStackTraceScenario" 8 | Then I wait to receive an error 9 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 10 | And the error payload field "notifier.name" equals "Android Bugsnag Notifier" 11 | And the error payload field "events" is an array with 1 elements 12 | And the exception "errorClass" equals "com.bugsnag.android.mazerunner.scenarios.MyThrowable" 13 | And the error payload field "events.0.exceptions.0.stacktrace" is an array with 0 elements 14 | -------------------------------------------------------------------------------- /features/full_tests/oom.feature: -------------------------------------------------------------------------------- 1 | Feature: Reporting OOMs 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: Out of Memory Error captured 7 | When I run "OomScenario" and relaunch the crashed app 8 | And I configure Bugsnag for "OomScenario" 9 | Then I wait to receive an error 10 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 11 | And the error payload field "notifier.name" equals "Android Bugsnag Notifier" 12 | And the error payload field "events" is an array with 1 elements 13 | And the exception "errorClass" equals "java.lang.OutOfMemoryError" 14 | -------------------------------------------------------------------------------- /features/full_tests/plugin_interface.feature: -------------------------------------------------------------------------------- 1 | Feature: Add custom behavior through a plugin interface 2 | 3 | Some internal libraries may build on top of the Bugsnag Android library and 4 | require custom behavior prior to the library being fully initialized. This 5 | interface allows for installing that behavior before calling the regular 6 | initialization process. 7 | 8 | Background: 9 | Given I clear all persistent data 10 | 11 | Scenario: Changing payload notifier description 12 | When I run "CustomPluginNotifierDescriptionScenario" 13 | Then I wait to receive an error 14 | Then the event "context" equals "Foo Handler Library" 15 | And the error payload field "events" is an array with 1 elements 16 | And the exception "errorClass" equals "java.lang.RuntimeException" 17 | 18 | -------------------------------------------------------------------------------- /features/full_tests/startup_anr.feature: -------------------------------------------------------------------------------- 1 | Feature: onCreate ANR 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | # Android 10 Note: Android 10 devices appear to allow much longer times for startup without an ANR 7 | # and then terminate the "misbehaving" app with a KILL (9) signal (almost like the ANR code doesn't 8 | # fire at all). Since we can't cover a KILL signal in a test, we skip Android 10. 9 | @skip_android_10 10 | # Android 13+ Note: we no longer have permission to inject BACK button events, which are used to 11 | # trigger the ANR - so the test is not valid on Android 13 either 12 | @skip_above_android_13 13 | Scenario: onCreate ANR is reported 14 | When I clear any error dialogue 15 | And I run "ConfigureStartupAnrScenario" 16 | And I relaunch the app after a crash 17 | Then I wait to receive an error 18 | And the exception "errorClass" equals "ANR" 19 | -------------------------------------------------------------------------------- /features/full_tests/trimmed_stacktrace.feature: -------------------------------------------------------------------------------- 1 | Feature: Reporting large stacktrace 2 | 3 | Background: 4 | Given I clear all persistent data 5 | 6 | Scenario: A large stacktrace should have its frames trimmed to a reasonable number 7 | When I run "TrimmedStacktraceScenario" 8 | And I wait to receive an error 9 | And the error is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier 10 | And the error payload field "events.0.exceptions.0.stacktrace" is an array with 200 elements 11 | -------------------------------------------------------------------------------- /features/scripts/close-anr-dialog.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | tmp_file=/tmp/emulator_view.xml 4 | adb pull $(adb shell uiautomator dump | awk '{ print $NF }') $tmp_file 5 | if grep -q aerr_close "$tmp_file"; then 6 | # Find element with close button resource ID 7 | coords=$(perl -ne 'printf "%d %d\n", ($1+$3)/2, ($2+$4)/2 if /resource-id="android:id\/aerr_close"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/' "$tmp_file") 8 | adb shell input tap $coords 9 | fi 10 | -------------------------------------------------------------------------------- /features/scripts/generate_gpg_key: -------------------------------------------------------------------------------- 1 | %echo Generating a default key 2 | Key-Type: RSA 3 | Key-Length: 1024 4 | Subkey-Type: ELG-E 5 | Subkey-Length: 1024 6 | Name-Real: maze-tester 7 | Name-Comment: a testing key 8 | Name-Email: none@none.none 9 | Expire-Date: 0 10 | Passphrase: password 11 | %commit 12 | %echo Done -------------------------------------------------------------------------------- /features/scripts/tap-screen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | adb shell input tap 100 100 4 | -------------------------------------------------------------------------------- /features/support/maze.all.cfg: -------------------------------------------------------------------------------- 1 | --fail-fast 2 | --app-activity=com.bugsnag.android.mazerunner.MainActivity 3 | --app-package=com.bugsnag.android.mazerunner 4 | -------------------------------------------------------------------------------- /features/support/maze.buildkite.cfg: -------------------------------------------------------------------------------- 1 | --format=junit 2 | --out=reports 3 | --format=pretty 4 | -------------------------------------------------------------------------------- /gradle/detekt.gradle: -------------------------------------------------------------------------------- 1 | detekt { 2 | input = files("src/androidTest", "src/main/java", "src/test") 3 | baseline = file("detekt-baseline.xml") 4 | buildUponDefaultConfig = true 5 | config = files("$rootDir/config/detekt/detekt.yml") 6 | } 7 | -------------------------------------------------------------------------------- /gradle/license-check.gradle: -------------------------------------------------------------------------------- 1 | // license checking 2 | license { 3 | header rootProject.file('LICENSE') 4 | ignoreFailures true 5 | } 6 | downloadLicenses { 7 | dependencyConfiguration = "api" 8 | } 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugsnag/bugsnag-android/984a528aae7101b3711d63932cd372568bcb1c1a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /maze_output/.gitignore: -------------------------------------------------------------------------------- 1 | **/* 2 | -------------------------------------------------------------------------------- /scripts/audit-dependency-licenses.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl https://raw.githubusercontent.com/bugsnag/license-audit/master/config/decision_files/global.yml -o decisions.yml 4 | 5 | license_finder --enabled-package-managers=gradle --decisions-file=decisions.yml 6 | license_finder --project-path=bugsnag-plugin-android-ndk/src/test/cpp/parson --enabled-package-managers=npm --decisions-file=decisions.yml 7 | -------------------------------------------------------------------------------- /scripts/run-clang-format-ci-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | find bugsnag-plugin-android-anr/src/main -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --dry-run -Werror && 4 | find bugsnag-plugin-android-ndk/src/main -iname *.h -o -iname *.cpp -o -iname *.c | grep -v src/main/jni/external/ | grep -v src/main/jni/deps/ | xargs clang-format --dry-run -Werror && 5 | find examples/sdk-app-example/app/src/main -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --dry-run -Werror 6 | -------------------------------------------------------------------------------- /scripts/run-clang-format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | find bugsnag-plugin-android-anr/src/main -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format -i && 4 | find bugsnag-plugin-android-ndk/src/main -iname *.h -o -iname *.cpp -o -iname *.c | grep -v src/main/jni/external/ | grep -v src/main/jni/deps/ | xargs clang-format -i && 5 | find examples/sdk-app-example/app/src/main -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format -i 6 | -------------------------------------------------------------------------------- /scripts/run-cpp-check.sh: -------------------------------------------------------------------------------- 1 | cppcheck --error-exitcode=2 --enable=warning,performance --check-level=exhaustive bugsnag-plugin-android-anr/src/main/jni && \ 2 | cppcheck --error-exitcode=2 --enable=warning,performance --check-level=exhaustive bugsnag-plugin-android-ndk/src/main/jni -i bugsnag-plugin-android-ndk/src/main/jni/deps -i bugsnag-plugin-android-ndk/src/main/jni/external 3 | -------------------------------------------------------------------------------- /scripts/run-sizer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | cd features/fixtures/minimalapp 4 | rm -rf .git 5 | ln -s ../../../.git 6 | bundle install 7 | bundle exec danger 8 | rm -f .git 9 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | 9 | plugins { 10 | id("com.gradle.enterprise") version "3.5" 11 | } 12 | 13 | gradleEnterprise { 14 | buildScan { 15 | termsOfServiceUrl = "https://gradle.com/terms-of-service" 16 | termsOfServiceAgree = "yes" 17 | } 18 | } 19 | 20 | include( 21 | ":bugsnag-android", 22 | ":bugsnag-android-core", 23 | ":bugsnag-plugin-android-anr", 24 | ":bugsnag-plugin-android-exitinfo", 25 | ":bugsnag-plugin-android-ndk", 26 | ":bugsnag-plugin-react-native", 27 | ":bugsnag-plugin-android-okhttp", 28 | ":bugsnag-benchmarks" 29 | ) 30 | --------------------------------------------------------------------------------