diff --git a/.buildkite/pipeline.full.yml b/.buildkite/pipeline.full.yml index 39928e0f18..b5e71d8abe 100644 --- a/.buildkite/pipeline.full.yml +++ b/.buildkite/pipeline.full.yml @@ -39,7 +39,9 @@ steps: # BitBar steps # + # Minimal tests job skipped as there are only ANR scenarios, run separately using BS - label: ':bitbar: Minimal fixture end-to-end tests' + skip: "Only ANR scenarios are run again the minimal fixture at present" depends_on: "fixture-minimal" timeout_in_minutes: 30 plugins: @@ -62,6 +64,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" concurrency: 25 concurrency_group: 'bitbar' concurrency_method: eager @@ -86,11 +95,20 @@ steps: - "--farm=bs" - "--device=ANDROID_9" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" concurrency: 5 concurrency_group: 'browserstack-app' concurrency_method: eager + # Minimal tests job skipped as there are only ANR scenarios, run separately using BS - label: ':bitbar: Debug fixture smoke tests' + skip: "Only ANR scenarios are run again the minimal fixture at present" depends_on: "fixture-debug" timeout_in_minutes: 30 plugins: @@ -116,6 +134,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-debug" concurrency: 25 @@ -144,6 +169,13 @@ steps: - "--farm=bs" - "--device=ANDROID_9" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-debug" concurrency: 5 @@ -178,6 +210,13 @@ steps: - "--exclude=features/full_tests/[^a-k].*.feature" - "--exclude=features/full_tests/anr.feature" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 25 @@ -211,6 +250,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 25 @@ -242,6 +288,13 @@ steps: - "--farm=bs" - "--device=ANDROID_7" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 5 @@ -274,6 +327,13 @@ steps: - "--exclude=features/full_tests/[^a-k].*.feature" - "--exclude=features/full_tests/anr.feature" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 25 @@ -306,6 +366,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 25 @@ -335,6 +402,13 @@ steps: - "--farm=bs" - "--device=ANDROID_8" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 5 @@ -369,6 +443,13 @@ steps: - "--exclude=features/full_tests/[^a-k].*.feature" - "--exclude=features/full_tests/anr.feature" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -403,6 +484,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -434,6 +522,13 @@ steps: - "--farm=bs" - "--device=ANDROID_9" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -468,6 +563,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -502,6 +604,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -532,6 +641,13 @@ steps: - "--farm=bs" - "--device=ANDROID_10" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -570,6 +686,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -604,6 +727,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -634,6 +764,13 @@ steps: - "--farm=bs" - "--device=ANDROID_11" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -668,6 +805,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -702,6 +846,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -732,6 +883,13 @@ steps: - "--farm=bs" - "--device=ANDROID_13" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -766,6 +924,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -800,6 +965,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -830,6 +1002,13 @@ steps: - "--farm=bs" - "--device=ANDROID_14" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 3839238e47..baf34f0931 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -130,6 +130,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 25 @@ -160,6 +167,13 @@ steps: - "--farm=bs" - "--device=ANDROID_7" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 5 @@ -191,6 +205,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 25 @@ -219,6 +240,13 @@ steps: - "--farm=bs" - "--device=ANDROID_8" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r19" concurrency: 5 @@ -252,6 +280,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -315,6 +350,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -345,6 +387,13 @@ steps: - "--farm=bs" - "--device=ANDROID_10" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -379,6 +428,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -410,6 +466,13 @@ steps: - "--farm=bs" - "--device=ANDROID_11" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -449,6 +512,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -480,6 +550,13 @@ steps: - "--farm=bs" - "--device=ANDROID_12" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -515,6 +592,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -548,6 +632,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -578,6 +669,13 @@ steps: - "--farm=bs" - "--device=ANDROID_13" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 @@ -611,6 +709,13 @@ steps: - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 25 @@ -641,6 +746,13 @@ steps: - "--farm=bs" - "--device=ANDROID_14" - "--fail-fast" + - "--format=junit" + - "--out=reports" + - "--format=pretty" + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^master|next$$" env: TEST_FIXTURE_SYMBOL_DIR: "build/fixture-r21" concurrency: 5 diff --git a/CHANGELOG.md b/CHANGELOG.md index fbfa4b275d..8863390830 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ * Add original error class and message to metadata for link errors loading BugSnag libraries [#2070](https://github.com/bugsnag/bugsnag-android/pull/2070) +### Bug fixes + +* Sending startup crashes synchronously now uses a flexible timeout so that apps with slower startups don't ANR + [#2075](https://github.com/bugsnag/bugsnag-android/pull/2075) + ## 6.7.0 (2024-08-08) ### Enhancements diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventStore.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventStore.kt index 4f2183eb2c..1ed219d95b 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventStore.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventStore.kt @@ -1,15 +1,16 @@ package com.bugsnag.android +import android.os.SystemClock import com.bugsnag.android.EventFilenameInfo.Companion.findTimestampInFilename import com.bugsnag.android.EventFilenameInfo.Companion.fromEvent import com.bugsnag.android.EventFilenameInfo.Companion.fromFile import com.bugsnag.android.JsonStream.Streamable import com.bugsnag.android.internal.BackgroundTaskService +import com.bugsnag.android.internal.ForegroundDetector import com.bugsnag.android.internal.ImmutableConfig import com.bugsnag.android.internal.TaskType import java.io.File import java.util.Calendar -import java.util.Comparator import java.util.Date import java.util.concurrent.Callable import java.util.concurrent.ExecutionException @@ -17,10 +18,10 @@ import java.util.concurrent.Future import java.util.concurrent.RejectedExecutionException import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException +import kotlin.math.max /** - * Store and flush Event reports which couldn't be sent immediately due to - * lack of network connectivity. + * Store and flush Event reports. */ internal class EventStore( private val config: ImmutableConfig, @@ -41,7 +42,8 @@ internal class EventStore( override val logger: Logger /** - * Flush startup crashes synchronously on the main thread + * Flush startup crashes synchronously on the main thread. Startup crashes block the main thread + * when being sent (subject to [Configuration.setSendLaunchCrashesSynchronously]) */ fun flushOnLaunch() { if (!config.sendLaunchCrashesSynchronously) { @@ -57,13 +59,20 @@ internal class EventStore( return } try { - future.get(LAUNCH_CRASH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + // Calculate the maximum amount of time we are prepared to block while sending + // startup crashes, based on how long we think startup has taken so-far. + // This attempts to mitigate possible startup ANRs that can occur when other SDKs + // have blocked the main thread before this code is reached. + val currentStartupDuration = + SystemClock.elapsedRealtime() - ForegroundDetector.startupTime + val timeout = max(0, LAUNCH_CRASH_TIMEOUT_MS - currentStartupDuration) + future.get(timeout, TimeUnit.MILLISECONDS) } catch (exc: InterruptedException) { - logger.d("Failed to send launch crash reports within 2s timeout, continuing.", exc) + logger.d("Failed to send launch crash reports within timeout, continuing.", exc) } catch (exc: ExecutionException) { - logger.d("Failed to send launch crash reports within 2s timeout, continuing.", exc) + logger.d("Failed to send launch crash reports within timeout, continuing.", exc) } catch (exc: TimeoutException) { - logger.d("Failed to send launch crash reports within 2s timeout, continuing.", exc) + logger.d("Failed to send launch crash reports within timeout, continuing.", exc) } } @@ -158,6 +167,7 @@ internal class EventStore( deleteStoredFiles(setOf(eventFile)) logger.i("Deleting sent error file $eventFile.name") } + DeliveryStatus.UNDELIVERED -> undeliveredEventPayload(eventFile) DeliveryStatus.FAILURE -> { val exc: Exception = RuntimeException("Failed to deliver event payload") diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/FileStore.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/FileStore.kt index 0cd0bafc50..a5b9a0ec8c 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/FileStore.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/FileStore.kt @@ -113,6 +113,7 @@ internal abstract class FileStore( if (isStorageDirValid(storageDir)) { val listFiles = storageDir.listFiles() ?: return if (listFiles.size < maxStoreCount) return +<<<<<<< HEAD // Number of files to discard takes into account that a new file may need to be written val numberToDiscard = listFiles.size - maxStoreCount + 1 deleteStoredFiles( @@ -132,6 +133,24 @@ internal abstract class FileStore( } .toSet() ) +======= + val sortedListFiles = listFiles.sortedBy { it.lastModified() } + // Number of files to discard takes into account that a new file may need to be written + val numberToDiscard = listFiles.size - maxStoreCount + 1 + var discardedCount = 0 + for (file in sortedListFiles) { + if (discardedCount == numberToDiscard) { + return + } else if (!queuedFiles.contains(file)) { + logger.w( + "Discarding oldest error as stored error limit reached: '" + + file.path + '\'' + ) + deleteStoredFiles(setOf(file)) + discardedCount++ + } + } +>>>>>>> 3aabb9e6ce6479ddbf471051052a9d60ac45ceb0 } } diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/internal/ForegroundDetector.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/internal/ForegroundDetector.kt index 4308c8ee9a..548c56ebdc 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/internal/ForegroundDetector.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/internal/ForegroundDetector.kt @@ -55,6 +55,12 @@ internal object ForegroundDetector : ActivityLifecycleCallbacks, Handler.Callbac private var waitingForActivityRestart: Boolean = false + /** + * Marks the timestamp (relative to [SystemClock.elapsedRealtime]) that we initialised for the + * first time. + */ + internal val startupTime = SystemClock.elapsedRealtime() + @VisibleForTesting internal var backgroundSent = true diff --git a/docker-compose.yml b/docker-compose.yml index 0b1b4d07fe..3a1a174510 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,6 +61,7 @@ services: - ./build:/app/build - ./features/:/app/features/ - ./maze_output:/app/maze_output + - ./reports/:/app/reports/ - /var/run/docker.sock:/var/run/docker.sock android-license-audit: