fix(startup): stop a throwing initializer from killing cold start - #1339
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bugsnag
6a8f47a7b5ee91bed8ac6cacis a cold-start crash 123 ms into launch:NoSuchMethodErrorout ofProcessCameraProvider.getInstance(), thrown fromCameraXInitializer.CameraX 1.6.1's
ContextUtilcallsContext.getDeviceId()behind a bareBuild.VERSION.SDK_INT >= 34check. The reporting runtime claims API 34 — it also claims to be a Pixel 8 Pro, while listingcpuAbi: [x86_64, arm64-v8a]withbinaryArch: arm64— but its framework has no such method. No CameraX version guards against a runtime that lies about its API level, so the call site is not fixable upstream.What made that fatal is ours.
CameraXInitializerran the warm-up in a bareCoroutineScope(Dispatchers.IO).launch { }with no handler, duringContentProvidercreation, before any UI exists — so the throwable went straight to the default uncaught-exception handler and took the process with it. Three other initializers had the same shape. Wrapping the block incatch (e: Exception)would not have helped:NoSuchMethodErroris aLinkageError, which extendsError.So this adds one
launchBestEfforthelper that owns the pattern — catchesThrowable, re-throwsCancellationExceptionso structured cancellation still works, and routes failures throughtrace()so they land in Bugsnag as handled errors instead of crashes. All four initializers (camerax, curves, clock, trace) now use it.CameraXInitializerandDiscreteBondingCurveInitializeralso gainTraceInitializeras a dependency.trace()early-returns untilTraceManager.initializehas run, so without that edge a failure in either would be swallowed silently — the failure sink has to exist before the task that might need it.Not covered here:
CodeScanner.kt:283callsgetCameraProvider()unwrapped, so the sameNoSuchMethodErrorcan still surface when the scanner opens. That's a feature-level failure on a device that cannot run the camera anyway, not a launch crash, and it wants its own error path.