Skip to content

feat(android-sqlite): Add SentrySQLiteDriver (JAVA-275)#5466

Draft
0xadam-brown wants to merge 2 commits into
mainfrom
feat/support-sqlite-driver
Draft

feat(android-sqlite): Add SentrySQLiteDriver (JAVA-275)#5466
0xadam-brown wants to merge 2 commits into
mainfrom
feat/support-sqlite-driver

Conversation

@0xadam-brown
Copy link
Copy Markdown
Member

@0xadam-brown 0xadam-brown commented May 22, 2026

📜 Description

Introduces SentrySQLiteDriver for wrapping and instrumenting androidx.sqlite.SQLiteDriver. Like our existing SentrySupportSQLiteOpenHelper, the new wrapper produces a span per executed SQL statement.

Example use:

  Room.databaseBuilder(context, AppDatabase::class.java, "myapp.db")
      .setDriver(SentrySQLiteDriver(AndroidSQLiteDriver()))
      .build()

The wrapper protects against duplicate span creation, but users migrating from SentrySupportSQLiteOpenHelper to SentrySQLiteDriver should be careful not to wrap both the helper and driver when using Room's bridge adapter (see the README for more details).

💡 Motivation and Context

Room 2.7 introduced the SQLiteDriver API as a replacement for SupportSQLiteOpenHelper; Room 3.0+ makes use of SQLiteDriver mandatory.

A key motivation behind the introduction of SQLiteDriver was Kotlin Multiplatform compatibility. This PR makes SentrySQLiteDriver available on Android only, but the wrapper has been packaged so that we can lift it into our KMP module in the future without having to break clients.

Background: Click to expand

Background

Android has three separate APIs for accessing on-device SQLite dbs:

[1] SQLiteOpenHelper → Original framework API, available since Android 1.0.

[2] SupportSQLiteOpenHelper → An AndroidX abstraction layer that mirrors the SQLiteOpenHelper API. Introduced so that SQL mapping libraries like Room and SQLDelight could swap out the ORM-provided SQLite library for alternatives like SQLCipher. Delegates to SQLiteOpenHelper and ORM SQLite by default. On the deprecation runway.

[3] SQLiteDriver → Kotlin Multiplatform-compatible API introduced with Room 2.7+. Uses the ORM SQLite library by default. The Google-recommended API, and required by Room 3.0+. Scrubs all Android-specific dependencies, and has a relatively narrow API in comparison with (Support)SQLiteOpenHelper.

Sentry already supports [2]; this PR is about extending support to [3].

Addresses JAVA-275.

⚠️ Callouts

[1] Unlike SentrySupportSQLiteOpenHelper, the SentrySQLiteDriver is not automatically wrapped via the sentry-android-gradle-plugin. (Can add byte code support later if we want.)

[2] Behavior differences

Click to expand

Behavior differences

Aspect SentrySupportSQLiteOpenHelper (old) SentrySQLiteDriver (new) Evaluation
Span duration Whole performSql call (incl. app time during cursor materialization) Accumulated step() db time only – app time between steps excluded New is more accurate. Span duration is now limited to SQLite work, not the read loop plus arbitrary app-side row processing, I/O, or GC pauses between rows. Cleaner p95s for db performance dashboards; teams using span duration as a proxy for end-to-end read time will see it shrink.
Cursor iteration Only first getCount/onMove/fillWindow timed; later rows untimed Every step() contributes to cumulative span time New is more complete. A 10k-row read now reflects the full cumulative db cost rather than just the first window fill. The old path silently under-reported large reads.
Span wall-clock anchor Captured before the operation runs Captured at first step() of the cycle Visually, new span sits slightly later in trace New anchor tracks when SQLite actually started working; old anchor included setup/dispatch overhead in the span timeline.
db.name derivation Reads open helper databaseName (for Room, the builder name, e.g., "tracks" from databaseBuilder(ctx, MyDb, "tracks")). Reads File(fileName).name — the on-disk filename of the path Room passes to driver.open() (e.g., "tracks.db"). The same db can show up under two different db.name values during migration. Both paths report data correctly, but will attribute it to different sources.
Multi-statement scripts execSQL("CREATE TABLE …; INSERT …; INSERT …;") produces one span whose description is the full script. The Driver API compiles one statement per prepare(...), so multi-statement scripts must be split by Room (or the caller) into separate prepare/step cycles → one span per statement. New is more accurate but more verbose. Migration scripts and seed scripts that previously appeared as one bundled span will now appear as N smaller spans, each with its own timing and description. Useful for finding the slow statement; expect span counts to rise for these code paths.

💚 How did you test it?

Unit tests cover:

  • SentrySQLiteDriver delegation and wrapping
  • SentrySQLiteConnection delegation and wrapping
  • SentrySQLiteStatement span creation, cancellation, and success/error tagging
  • SQLiteSpanRecorder span lifecycle (start/finish/cancel)
  • LegacyInstrumentedSQLiteStatement no-op passthrough

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

If there's sufficient demand, support auto-wrapping SQLiteDriver via the sentry-android-gradle-plugin.

Introduces support for AndroidX's SQLiteDriver via a new SentrySQLiteDriver wrapper.

SentrySQLiteDriver automatically creates Sentry spans for each SQL statement. It's
the Driver API / KMP-compatible equivalent of SentrySupportSQLiteOpenHelper.

---

Co-authored-by: Angus Holder <7407345+angusholder@users.noreply.github.com>
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 22, 2026

JAVA-275

@github-actions
Copy link
Copy Markdown
Contributor

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against e646444

@sentry
Copy link
Copy Markdown

sentry Bot commented May 22, 2026

📲 Install Builds

Android

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

⚙️ sentry-android Build Distribution Settings

@github-actions
Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 303.45 ms 392.65 ms 89.20 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
91bb874 310.68 ms 359.24 ms 48.56 ms
ad8da22 314.38 ms 352.29 ms 37.91 ms
27d7cf8 306.76 ms 366.66 ms 59.90 ms
092f017 353.13 ms 433.84 ms 80.71 ms
b750b96 421.25 ms 444.09 ms 22.84 ms
a1eadfa 345.67 ms 411.26 ms 65.59 ms
5f14e5d 325.76 ms 368.32 ms 42.56 ms
22f4345 325.23 ms 454.66 ms 129.43 ms
9054d65 330.94 ms 403.24 ms 72.30 ms
cf708bd 408.35 ms 458.98 ms 50.63 ms

App size

Revision Plain With Sentry Diff
91bb874 1.58 MiB 2.13 MiB 559.07 KiB
ad8da22 1.58 MiB 2.29 MiB 719.83 KiB
27d7cf8 1.58 MiB 2.12 MiB 549.42 KiB
092f017 0 B 0 B 0 B
b750b96 1.58 MiB 2.10 MiB 533.20 KiB
a1eadfa 0 B 0 B 0 B
5f14e5d 1.58 MiB 2.19 MiB 620.00 KiB
22f4345 1.58 MiB 2.29 MiB 719.83 KiB
9054d65 1.58 MiB 2.29 MiB 723.38 KiB
cf708bd 1.58 MiB 2.11 MiB 539.71 KiB

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.

1 participant