Skip to content

perf(android): Init shake detector off the main thread#5784

Merged
runningcode merged 4 commits into
mainfrom
no/feedbackshake-register-async
Jul 21, 2026
Merged

perf(android): Init shake detector off the main thread#5784
runningcode merged 4 commits into
mainfrom
no/feedbackshake-register-async

Conversation

@runningcode

Copy link
Copy Markdown
Contributor

Summary

FeedbackShakeIntegration.register() resolved the accelerometer via SensorManager synchronously on the calling thread — the main thread under auto-init. On a Pixel 10 (Android 17, release build) this first SensorManager access measured ~1.75 ms, making it the single most expensive integration in the Sentry.init register loop (the loop total was ~5.1 ms).

This moves the pre-warm shakeDetector.init(...) onto options.getExecutorService(). SentryShakeDetector.start() already re-runs the idempotent init() on demand, so shake detection still works if an activity resumes before the warm-up finishes. SentryShakeDetector's lifecycle methods (init/start/stop/close) are now synchronized so the executor warm-up and a main-thread start() cannot race on the sensor fields.

Measurement (Pixel 10, release, median of 10 cold starts)

before after
FeedbackShakeIntegration.register() ~1754 µs ~40 µs
register loop total ~5.1 ms ~3.3 ms

Follow-up to JAVA-618. Companion PR defers the other big synchronous item (NDK init).

FeedbackShakeIntegration.register() resolved the accelerometer via
SensorManager synchronously on the calling thread, which under auto-init
is the main thread. On a Pixel 10 this first SensorManager access
measured ~1.75ms, making it the single most expensive integration in the
Sentry.init register loop.

Submit the pre-warm init() to the executor service instead. start()
already re-runs the idempotent init() on demand, so shake detection still
works if an activity resumes before the warm-up completes. SentryShakeDetector's
lifecycle methods are now synchronized so the executor warm-up and a
main-thread start() cannot race on the sensor fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sentry

sentry Bot commented Jul 17, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.49.0 (1) release

⚙️ sentry-android Build Distribution Settings

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 349.33 ms 419.08 ms 69.75 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
5b1a06b 352.27 ms 413.70 ms 61.43 ms
2124a46 319.19 ms 415.04 ms 95.85 ms
ad8da22 314.52 ms 352.47 ms 37.95 ms
d15471f 304.55 ms 408.43 ms 103.87 ms
0ee65e9 317.37 ms 366.50 ms 49.13 ms
2195398 351.77 ms 433.22 ms 81.45 ms
ee747ae 358.21 ms 389.41 ms 31.20 ms
abfcc92 309.54 ms 380.32 ms 70.78 ms
8558cac 306.16 ms 355.24 ms 49.09 ms
d15471f 310.26 ms 377.04 ms 66.78 ms

App size

Revision Plain With Sentry Diff
5b1a06b 0 B 0 B 0 B
2124a46 1.58 MiB 2.12 MiB 551.51 KiB
ad8da22 1.58 MiB 2.29 MiB 719.83 KiB
d15471f 1.58 MiB 2.13 MiB 559.54 KiB
0ee65e9 0 B 0 B 0 B
2195398 0 B 0 B 0 B
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
abfcc92 1.58 MiB 2.13 MiB 557.31 KiB
8558cac 0 B 0 B 0 B
d15471f 1.58 MiB 2.13 MiB 559.54 KiB

Previous results on branch: no/feedbackshake-register-async

Startup times

Revision Plain With Sentry Diff
d1671cb 292.45 ms 328.67 ms 36.22 ms

App size

Revision Plain With Sentry Diff
d1671cb 0 B 0 B 0 B

@runningcode
runningcode marked this pull request as ready for review July 20, 2026 07:09

@romtsn romtsn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the bot comment needs addressing but LGTM otherwise, pre-approving

…618)

A warm-up init submitted to the executor could be drained after the
integration's close() ran, since integrations shut down before the
executor. That re-resolved the sensor and leaked a HandlerThread. Guard
init()/start() with a closed latch so a late warm-up is a no-op.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6b4dae5. Configure here.

The closed latch added to neutralize a warm-up drained after close()
was permanent, so re-registering the same integration (e.g. a second
Sentry.init reusing the same options) left shake detection off with no
recovery. register() now re-arms the detector via reopen(), which the
stale-warm-up path (init()) deliberately does not, preserving the
drain-after-close guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@runningcode
runningcode enabled auto-merge (squash) July 21, 2026 12:29
@runningcode
runningcode merged commit 8d299fc into main Jul 21, 2026
67 of 71 checks passed
@runningcode
runningcode deleted the no/feedbackshake-register-async branch July 21, 2026 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants