Skip to content

First encrypted Room database unlock is up to ~4x slower after upgrading Room 2.5.2 → 2.8.4 and sqlcipher-android 4.11.0 → 4.17.0 #91

Description

@1530120997

First encrypted Room database unlock is up to ~4x slower after upgrading Room 2.5.2 → 2.8.4 and sqlcipher-android 4.11.0 → 4.17.0

Summary

After upgrading Room from 2.5.2 to 2.8.4 and net.zetetic:sqlcipher-android from 4.11.0 to 4.17.0, opening existing encrypted Room databases became up to approximately four times slower during application startup.

The slowdown is concentrated in the first SQL statement executed after SQLiteDatabaseHook.postKey(). Queries issued after the connection is fully open do not show the same regression.

Environment

  • Platform: Android
  • Database integration: Room with a SQLCipher-backed SupportSQLiteOpenHelper.Factory
  • Database type: existing SQLCipher-encrypted Room databases
  • Journal mode: WAL
  • Password, database files, device and build configuration: unchanged between measurements
  • Device /RMX6688

Dependency change

Configuration Room sqlcipher-android Observed first-unlock cost
Before 2.5.2 4.14.0 Baseline
After 2.8.4 4.17.0 Up to approximately 4x slower

Additional controlled measurements

We also held Room at 2.8.4 and compared sqlcipher-android 4.11.0 with 4.17.0 on the same test setup. This independently shows a substantial regression on the SQLCipher version axis:

Room sqlcipher-android Samples Mean Median P90 Min–max
2.8.4 4.11.0 80 529.46 ms 494.30 ms 809.51 ms 197.19–1,011.59 ms
2.8.4 4.17.0 137 1,588.07 ms 1,314.43 ms 2,919.85 ms 654.63–3,519.30 ms

The 4.17.0 result is:

  • 3.00x higher by mean;
  • 2.66x higher by median;
  • 3.61x higher at P90.

Representative log entries:

# Room 2.8.4 + sqlcipher-android 4.17.0
SQLCipher key derivation and verification cost: 2775.801539ms
SQLCipher key derivation and verification cost: 3244.882154ms
SQLCipher key derivation and verification cost: 3519.295308ms

# Room 2.8.4 + sqlcipher-android 4.11.0
SQLCipher key derivation and verification cost: 346.516385ms
SQLCipher key derivation and verification cost: 478.817230ms
SQLCipher key derivation and verification cost: 562.362538ms

Instrumentation

The measurements were collected with the following SQLiteDatabaseHook:

internal class SqlCipherDebugLogHook private constructor(
    private val delegate: SQLiteDatabaseHook?,
) : SQLiteDatabaseHook {

    override fun preKey(connection: SQLiteConnection) {
        delegate?.preKey(connection)
    }

    override fun postKey(connection: SQLiteConnection) {
        delegate?.postKey(connection)
        val startNs = System.nanoTime()
        runCatching {
            connection.executeForLong(
                "SELECT COUNT(*) FROM sqlite_schema;",
                null,
                null,
            )
        }.onSuccess {
            val elapsedMs = (System.nanoTime() - startNs) / 1_000_000.0
            logd(TAG, "SQLCipher key derivation and verification cost: ${elapsedMs}ms")
        }
    }
}

SQLCipher performs key derivation lazily. Therefore, the measured interval is not the duration of the postKey() callback itself and should not be interpreted as isolated PBKDF time. It measures the first schema query after postKey(), which forces lazy KDF, first-page decryption, and key verification. The trivial COUNT(*) query overhead is also included.

Steps to reproduce

  1. Create an encrypted Room database, then close it or kill the application process.
  2. Configure Room with a SQLCipher-backed SupportSQLiteOpenHelper.Factory and WAL.
  3. Install a SQLiteDatabaseHook that runs and times SELECT COUNT(*) FROM sqlite_schema; in postKey().
  4. Open the existing database during application startup.
  5. Record the first-query duration logged by the hook.
  6. Repeat across fresh process starts using the same device, database, passphrase, and build configuration.
  7. Compare the old and new dependency combinations.

Expected behavior

First unlock/open performance should remain close to the earlier version when the database, passphrase, cipher settings, device, and build configuration are unchanged.

Actual behavior

The first SQL statement that forces key derivation and verification is substantially slower on sqlcipher-android 4.17.0. The original joint Room/SQLCipher upgrade showed an increase of up to approximately 4x; the controlled Room 2.8.4 measurements show a 3.00x mean and 3.61x P90 increase from SQLCipher 4.11.0 to 4.17.0.

Isolation matrix

The following matrix would separate the Room and SQLCipher effects for the exact versions in the original report:

Room sqlcipher-android Status
2.8.4 4.11.0 Measured: mean 529.46 ms, P90 809.51 ms
2.8.4 4.17.0 Measured: mean 1,588.07 ms, P90 2,919.85 ms

Questions

  1. Were there changes between sqlcipher-android 4.11.0 and 4.17.0 that could increase lazy KDF, first-page decryption, or key verification time for an existing database?
  2. Did any default cipher, KDF, compatibility, or native build settings change across these versions?
  3. Could 4.17.0 derive or verify the key more than once when Room opens multiple WAL connections?
  4. Is timing the first trivial schema query from postKey() a valid way to compare SQLCipher first-unlock cost across versions?
  5. Which safe diagnostics or PRAGMA values would help isolate the increase without exposing the database key?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions