Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
4c67ea9
feat(android-sqlite): Add SentrySQLiteDriver (JAVA-275)
0xadam-brown May 20, 2026
02edd2a
Use lambda for nanoTimeProvider default
0xadam-brown May 28, 2026
37591e7
Address Roman's comments
0xadam-brown Jun 3, 2026
e689907
Bump androidx.sqlite to 2.6.2 to pick up new hasConnectionPool method
0xadam-brown Jun 2, 2026
d4ab6b7
Merge branch 'main' into feat/support-sqlite-driver
0xadam-brown Jun 5, 2026
f2207a5
Guard SQLiteDriver.hasConnectionPool for sqlite 2.5.x delegates
0xadam-brown Jun 5, 2026
d4ffab7
chore(android-sqlite): Add SQLite samples to sentry-samples-android
0xadam-brown Jun 2, 2026
0b1a52e
Prevent db reset while statement is in flight; warm up Room3 db upon โ€ฆ
0xadam-brown Jun 5, 2026
8b3c175
Serialize demo SQL and block concurrent taps
0xadam-brown Jun 8, 2026
a16a9da
Guard UiLoadActivity against missing demo extra
0xadam-brown Jun 8, 2026
5ae931e
chore(android-sqlite): Skip wrapping SupportSQLiteDriver bridge to avโ€ฆ
0xadam-brown Jun 6, 2026
804f413
chore(android-sqlite): Add SupportSQLiteDriver bridge mode to Androidโ€ฆ
0xadam-brown Jun 8, 2026
4aacc70
fix(android-sqlite): Use warm-up generation counter for stale run guard
0xadam-brown Jun 8, 2026
007c537
Add Proguard keep rule for SupportSQLiteDriver
0xadam-brown Jun 11, 2026
6766950
Merge branch 'main' into feat/no-double-wrapping-sqlite-driver
0xadam-brown Jun 18, 2026
b5725ea
Format code
getsentry-bot Jun 18, 2026
f28dcf5
Restore SQLiteSpanManager changes from main + fix merge conflicts
0xadam-brown Jun 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions sentry-android-sqlite/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
# https://developer.android.com/studio/build/shrink-code#decode-stack-trace
-keepattributes LineNumberTable,SourceFile

# SentrySQLiteDriver.create() uses a runtime class-name check to skip wrapping the Room 2.7+
# SupportSQLiteDriver bridge adapter and avoid duplicate spans.
-keepnames class androidx.sqlite.driver.SupportSQLiteDriver

##---------------End: proguard configuration for SQLite ----------
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ import org.jetbrains.annotations.ApiStatus
* .build()
* ```
*
* **Warning:** Do not use [SentrySQLiteDriver] together with
* [SentrySupportSQLiteOpenHelper][io.sentry.android.sqlite.SentrySupportSQLiteOpenHelper] on the
* same database file. Both wrappers instrument at different layers and combining them will produce
* duplicate spans.
*
* @param delegate The [SQLiteDriver] instance to delegate calls to.
*/
@ApiStatus.Experimental
Expand Down Expand Up @@ -73,11 +68,32 @@ public class SentrySQLiteDriver private constructor(private val delegate: SQLite
public companion object {

/**
* Wraps the provided delegate in a [SentrySQLiteDriver]. Returns the delegate as-is if already
* wrapped.
* Name of the bridge adapter often used with Room 2.7+. It implements the `SQLiteDriver`
* interface and its constructor consumes a `SupportSQLiteOpenHelper`. (Users of the Sentry
* Android Gradle Plugin will have the `SupportSQLiteOpenHelper` wrapped for them
* automatically.) We deliberately avoid wrapping the adapter to prevent duplicate spans.
*
* String (rather than an `is` check) lets us avoid a compile-time dependency on
* androidx.sqlite:sqlite-framework.
*/
private const val SUPPORT_SQLITE_DRIVER_FQN = "androidx.sqlite.driver.SupportSQLiteDriver"
Comment thread
0xadam-brown marked this conversation as resolved.

/**
* Wraps the provided delegate in a [SentrySQLiteDriver].
*
* To avoid duplicate spans, returns the delegate as-is if:
* 1. it's already wrapped, or
* 2. it's an `androidx.sqlite.driver.SupportSQLiteDriver`.
*
* In the case of (2), wrap the open helper passed to the `SupportSQLiteDriver` constructor via
* `SentrySupportSQLiteOpenHelper` instead.
*/
@JvmStatic
public fun create(delegate: SQLiteDriver): SQLiteDriver =
delegate as? SentrySQLiteDriver ?: SentrySQLiteDriver(delegate)
if (delegate is SentrySQLiteDriver || delegate.javaClass.name == SUPPORT_SQLITE_DRIVER_FQN) {
delegate
} else {
SentrySQLiteDriver(delegate)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package androidx.sqlite.driver

import androidx.sqlite.SQLiteConnection
import androidx.sqlite.SQLiteDriver

/**
* Minimal stub of `androidx.sqlite.driver.SupportSQLiteDriver` (which lives in
Comment thread
markushi marked this conversation as resolved.
* `androidx.sqlite:sqlite-framework`, not on this module's compile/test classpath) for verifying
* behavior of `SentrySQLiteDriver.create(SupportSQLiteDriver)`.
*/
internal class SupportSQLiteDriver : SQLiteDriver {

override val hasConnectionPool: Boolean = false

override fun open(fileName: String): SQLiteConnection {
throw UnsupportedOperationException("Test stub; not for runtime use")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.sentry.sqlite
import androidx.sqlite.SQLiteConnection
import androidx.sqlite.SQLiteDriver
import androidx.sqlite.SQLiteStatement
import androidx.sqlite.driver.SupportSQLiteDriver
import io.sentry.IScopes
import io.sentry.Sentry
import io.sentry.SentryIntegrationPackageStorage
Expand Down Expand Up @@ -64,6 +65,16 @@ class SentrySQLiteDriverTest {
assertSame(wrapped, doubleWrapped)
}

@Test
fun `create with SupportSQLiteDriver bridge returns same instance without wrapping`() {
val bridge = SupportSQLiteDriver()

val result = SentrySQLiteDriver.create(bridge)

assertSame(bridge, result)
assertFalse(result is SentrySQLiteDriver)
}

@Test
fun `hasConnectionPool forwards delegate value when supported`() {
whenever(fixture.mockDriver.hasConnectionPool).thenReturn(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ internal val OPENHELPER_ROOM =
.trimIndent(),
)

// Bridge demos run the same SQL as the driver paths; spans come from the open-helper layer.
internal val BRIDGE_DIRECT = DRIVER_DIRECT

internal val BRIDGE_ROOM2 = DRIVER_ROOM2

internal val OPENHELPER_SQLDELIGHT =
DisplayInfo(
sql =
Expand Down
Loading
Loading