Skip to content

feat(plugin): Auto-instrument SQLiteDriver for Room users (GRADLE-107)#1285

Open
0xadam-brown wants to merge 2 commits into
mainfrom
feat/wrap-sqlite-driver
Open

feat(plugin): Auto-instrument SQLiteDriver for Room users (GRADLE-107)#1285
0xadam-brown wants to merge 2 commits into
mainfrom
feat/wrap-sqlite-driver

Conversation

@0xadam-brown

@0xadam-brown 0xadam-brown commented Jun 9, 2026

Copy link
Copy Markdown
Member

📜 Description

Adds a new bytecode method visitor that lets us auto-wrap all occurrences of SQLiteDriver with SentrySQLiteDriver whenever the driver is passed to Room.DatabaseBuilder.setDriver(SQLiteDriver) (Room's sole driver access point – see the "Coverage" section from #1281 for why we don't need to worry about anything else).

In other words, this:

val database = Room.databaseBuilder(context, MyDatabase::class.java, "dbName")
     .setDriver(AndroidSQLiteDriver())
     .build()

becomes:

val database = Room.databaseBuilder(context, MyDatabase::class.java, "dbName")
     .setDriver(SentrySQLiteDriver.create(AndroidSQLiteDriver()))
     .build()

The wrapping policy is naive in that every SQLiteDriver passed to Room.DatabaseBuilder.setDriver() is wrapped. That's deliberate because SentrySQLiteDriver protects against double-wrapping internally, which lets us keep our visitor implementation simple.

💡 Motivation and Context

Room 2.7 introduced RoomDatabase.Builder.setDriver(SQLiteDriver) as the new way to configure an underlying SQLite implementation (link), with the intention of eventually replacing SupportSQLiteOpenHelper. (Room 3.0+ does just that.)

The Sentry Android Gradle Plugin currently auto-instruments only the open helper path. Apps that adopt the driver-based API will lose automatic SQL performance instrumentation unless they manually wrap their driver with SentrySQLiteDriver.create(...) at every setDriver(...) call site.

This PR provides auto-wrapping for the driver path too.

Addresses GRADLE-107 / #1281

Preconditions

  1. sentry-android-sqlite version in the SAGP build must include SentrySQLiteDriver
  2. InstrumentationFeature.DATABASE must be enabled (⚠️ in other words, we piggyback on the existing DATABASE toggle used to auto-instrument the SupportSQLiteOpenHelper + Room DAO spans)

Coverage

  • Auto-wraps SQLiteDriver for all Room users.
  • SQLDelight users don't need driver auto-wrapping (they still use SupportSQLiteOpenHelper, which we already auto-instrument).
  • The (very) few developers who use SQLiteDriver directly will need to wrap it manually.

Impact on build times

Near zero. The new instrumentation gates on a two-entry allowlist (androidx.room.RoomDatabase$Builder / androidx.room3.RoomDatabase$Builder), which means 0-1 classes will be visited per build in virtually all scenarios. The rest of the per-class cost is a single Set.contains check.

Interactions with other db instrumentation

SupportSQLiteOpenHelper

Driver instrumentation operates alongside our existing instrumentation of SupportSQLiteOpenHelper. (It's fine to use both drivers and open helpers in the same project, so long as a given db file is associated with exactly one of them. Room's APIs help enforce that restriction.)

The Sentry Android SDK – and not the SAGP – is responsible for protecting against double-wrapping and duplicate spans. In general that's easy (just check the type being passed to the wrapper). In the case of the SupportSQLiteDriver used with Room [2.7, 3.0) things get a bit trickier, as it's both a driver and consumes an open helper. But the SDK has that covered as well (see #5514).

Room DAO methods

Driver instrumentation also operates in tandem with our existing Room DAO spans – in theory, at least. Unfortunately DAO instrumentation broke under API changes in Room 2.7, which is the same version that introduced SQLiteDriver. So for now the two are never active at the same time. Fixing that is a task for another day...

💚 How did you test it?

[1] Added unit tests + integration tests in this PR

[2] Verified that all the (for now) @Ignored integration tests pass against a local sentry-java SDK artifact containing SentrySQLiteDriver.

[3] Built out a local version of the Sentry Android sample app that let me manually test SAGP + sentry-java compatibility end-to-end. Verified that auto-instrumentation of SQLiteDriver works as expected.

📝 Checklist

  • I reviewed the submitted code
  • I added tests to verify the changes
  • I updated the docs if needed
  • No breaking changes

🔮 Next steps

  • ⚠️ Prior to merging this PR: Update VERSION_SQLITE_DRIVER to match the sentry-android version that introduces SentrySQLiteDriver (PR here) + address other inline TODOs.
  • Update Android sample app to accept an SAGP enabled/disabled flag + manually verify auto-wrap functionality.
  • Coordinate merging and release of all sentry-java + sentry-android-gradle-plugin PRs supporting SQLiteDriver spans.
  • Consider a CI cron job that checks Room's latest API for changes that would impact our implementation here and in the Sentry Android SDK.
  • Consider fixing our Room DAO instrumentation for Room 2.7+ and 3.0+

@github-actions

github-actions Bot commented Jun 9, 2026

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 2ff8ac5

@0xadam-brown 0xadam-brown linked an issue Jun 9, 2026 that may be closed by this pull request
Comment thread CHANGELOG.md
### Features

- Auto-wrap SQLiteDriver with SentrySQLiteDriver for Room users ([#1281](https://github.com/getsentry/sentry-android-gradle-plugin/issues/1281))
- Gated on `sentry-android-sqlite` >= 8.44.0 and the existing `tracingInstrumentation` `DATABASE` feature

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

TODO: Update version number once we ship the SentrySQLiteDriver in sentry-android.

internal val VERSION_LOGCAT = SemVer(6, 17, 0)
internal val VERSION_APP_START = SemVer(7, 1, 0)
internal val VERSION_SQLITE = SemVer(6, 21, 0)
internal val VERSION_SQLITE_DRIVER = SemVer(8, 44, 0)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

TODO: Update version number once we ship the SentrySQLiteDriver in sentry-android.

@0xadam-brown 0xadam-brown force-pushed the feat/wrap-sqlite-driver branch 2 times, most recently from f64ad3f to 1c821b7 Compare June 10, 2026 14:41
}
}

@Ignore(SQLITE_DRIVER_IGNORE_REASON)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

TODO: Remove @Ignore once we ship the SentrySQLiteDriver in sentry-android.

)
}

@Ignore(SQLITE_DRIVER_IGNORE_REASON)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

TODO: Remove @Ignore once we ship the SentrySQLiteDriver in sentry-android.

assertInstrumentableChain(build, "AndroidXSQLiteOpenHelper", "AndroidXRoomDao")
}

@Ignore(SQLITE_DRIVER_IGNORE_REASON)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

TODO: Remove @Ignore once we ship the SentrySQLiteDriver in sentry-android.

)
}

@Ignore(SQLITE_DRIVER_IGNORE_REASON)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

TODO: Remove @Ignore once we ship the SentrySQLiteDriver in sentry-android.

… users (GRADLE-107)

Adds a new ASM bytecode method visitor that lets us auto-wrap all occurrences of SQLiteDriver with SentrySQLiteDriver whenever the driver is passed to Room.DatabaseBuilder.setDriver(...).

For instance:

val database = Room.databaseBuilder(context, MyDatabase::class.java, "dbName")
     .setDriver(AndroidSQLiteDriver())
     .build()

becomes:

val database = Room.databaseBuilder(context, MyDatabase::class.java, "dbName")
     .setDriver(SentrySQLiteDriver.create(AndroidSQLiteDriver()))
     .build()

The wrapping policy is naive in that every SQLiteDriver passed to setDriver() is wrapped. That's deliberate because SentrySQLiteDriver protects against double-wrapping internally, which lets us keep our visitor implementation simple.

Preconditions:

1. InstrumentationFeature.DATABASE is enabled
2. The owning app is using a version of sentry-android-sqlite that includes SentrySQLiteDriver

Coverage:

- Auto-wraps SQLiteDriver for all Room users (sole Room access point is via its Room.DatabaseBuilder.setDriver() method).
- SQLDelight users don't need driver auto-wrapping (they still use SupportSQLiteOpenHelper, which we already auto-wrap).
- The few developers who use SQLiteDriver directly will need to wrap it manually.
@0xadam-brown 0xadam-brown force-pushed the feat/wrap-sqlite-driver branch from 1c821b7 to 1548c9c Compare June 10, 2026 15:27
@0xadam-brown 0xadam-brown marked this pull request as ready for review June 10, 2026 15:31
@0xadam-brown 0xadam-brown changed the title feat(plugin): Auto-wrap SQLiteDriver with SentrySQLiteDriver for Room users feat(plugin): Auto-instrument SQLiteDriver for Room users Jun 10, 2026
@0xadam-brown 0xadam-brown changed the title feat(plugin): Auto-instrument SQLiteDriver for Room users feat(plugin): Auto-instrument SQLiteDriver for Room users (GRADLE-107) Jun 10, 2026
@linear-code

linear-code Bot commented Jun 10, 2026

Copy link
Copy Markdown

GRADLE-107

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.

Auto-instrument SQLiteDriver for Room users

1 participant