Commit 96913b6
Add sqlcipher-loader module and migrate PIR/autofill (#8009)
Task/Issue URL:
https://app.asana.com/1/137249556945/project/488551667048375/task/1213721049904377?focus=true
### Description
Introduces a dedicated `sqlcipher-loader` module that centralises
SQLCipher native library loading and fixes a JNI deadlock causing a 7x
spike in `LIBRARY_LOAD_TIMEOUT_SQLCIPHER` (350 → 2,500/day).
**Root cause:** removing PIR's eager `System.loadLibrary("sqlcipher")`
call (f6c879e) inadvertently removed the pre-warm that autofill depended
on. Autofill's `SqlCipherLibraryLoader` then performed the first full
load on a background thread, and when PIR's lazy load raced
concurrently, a JNI loading deadlock could occur — triggering the 10s
timeout.
**Fix:**
- New `sqlcipher-loader-api` module exposes a `SqlCipherLoader`
interface with a single `waitForLibraryLoad(): Result<Unit>` API.
- New `sqlcipher-loader-impl` provides `RealSqlCipherLoader`, which:
- Implements `MainProcessLifecycleObserver` to eagerly pre-warm
SQLCipher on the IO dispatcher at app startup, before autofill or PIR
need it.
- Uses a `CompletableDeferred<Unit>` (initialised at construction) so
all callers share the same load — concurrent `complete()` calls are
no-ops, making the race structurally impossible.
- Fires `LIBRARY_LOAD_FAILURE_SQLCIPHER` (daily pixel) if the load
throws.
- PIR and autofill both now inject `SqlCipherLoader` and call
`waitForLibraryLoad()` instead of loading independently.
- `SqlCipherLibraryLoader` (autofill-local) and its test deleted.
- `sqlCipherAsyncLoading` feature flag and
`LIBRARY_LOAD_TIMEOUT_SQLCIPHER` pixel removed — no timeout needed when
the load is predictable and early.
### Steps to test this PR
_SQLCipher loads correctly_
- [x] Install the app and open a page with a password field — autofill
suggestion should appear normally
- [x] Open the PIR screen — it should load without errors
- [x] Check logcat for `SqlCipher: native library loaded successfully`
appearing once at startup (not twice, not on demand)
_No regression on autofill_
- [x] Save a login and verify it autofills on the target site
- [x] Confirm no `LIBRARY_LOAD_TIMEOUT_SQLCIPHER` or
`LIBRARY_LOAD_FAILURE_SQLCIPHER` pixels fire under normal conditions
_Verify build_
- [x] `./gradlew :sqlcipher-loader-impl:testDebugUnitTest`
- [x] `./gradlew :autofill-impl:testDebugUnitTest`
- [x] `./gradlew :pir-impl:testDebugUnitTest`
_SQLCipher loads correctly on PIR process_
- [x] Obtain subscription
- [x] Start a PIR scan via the PIR dashboard
- [x] Logcat should show "SqlCipher: Attempting to load native library
loaded on the PIR process”
- [x] Logcat should show " SqlCipher-Init: Library load wait completed
successfully”
- [x] Logcat should show "PIR-DB: sqlcipher native library loaded ok"
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Moderate risk because it changes when/how the SQLCipher native library
is loaded and gates creation of encrypted databases for both Autofill
and PIR, which can impact data access and startup behavior.
>
> **Overview**
> Centralizes SQLCipher native library loading into a new
`sqlcipher-loader` module (`SqlCipherLoader` API + `RealSqlCipherLoader`
impl) that eagerly starts async loading via process lifecycle observers
and provides a shared `waitForLibraryLoad` for all callers (with
timeout/failure pixels).
>
> Migrates Autofill and PIR secure DB factories to inject
`SqlCipherLoader` instead of doing their own loads, deleting Autofill’s
local `SqlCipherLibraryLoader` and its feature flag
(`sqlCipherAsyncLoading`) and moving the SQLCipher load pixels out of
`autofill.json5` into `sqlcipher_loader.json5`. The app wiring is
updated to depend on the new modules and to strip ATB params for the new
SQLCipher pixels.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
33c8a5f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Karl Dimla <klmbdimla@gmail.com>1 parent b3616e2 commit 96913b6
19 files changed
Lines changed: 519 additions & 564 deletions
File tree
- PixelDefinitions/pixels
- app
- src/main/java/com/duckduckgo/app/global/api
- autofill
- autofill-api/src/main/java/com/duckduckgo/autofill/api
- autofill-impl
- src
- main/java/com/duckduckgo/autofill/impl
- pixel
- securestorage
- test/java/com/duckduckgo/autofill/impl/securestorage
- pir/pir-impl
- src
- main/java/com/duckduckgo/pir/impl/store/secure
- test/kotlin/com/duckduckgo/pir/impl/store/secure
- sqlcipher-loader
- sqlcipher-loader-api
- src/main/java/com/duckduckgo/sqlcipher/loader/api
- sqlcipher-loader-impl
- src
- main/java/com/duckduckgo/sqlcipher/loader/impl
- test/kotlin/com/duckduckgo/sqlcipher/loader/impl
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
384 | 384 | | |
385 | 385 | | |
386 | 386 | | |
387 | | - | |
388 | | - | |
389 | | - | |
390 | | - | |
391 | | - | |
392 | | - | |
393 | | - | |
394 | | - | |
395 | | - | |
396 | | - | |
397 | | - | |
398 | | - | |
399 | | - | |
400 | | - | |
401 | 387 | | |
402 | 388 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
317 | 317 | | |
318 | 318 | | |
319 | 319 | | |
| 320 | + | |
| 321 | + | |
320 | 322 | | |
321 | 323 | | |
322 | 324 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| 40 | + | |
40 | 41 | | |
41 | 42 | | |
42 | 43 | | |
| |||
202 | 203 | | |
203 | 204 | | |
204 | 205 | | |
| 206 | + | |
| 207 | + | |
205 | 208 | | |
206 | 209 | | |
207 | 210 | | |
Lines changed: 0 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
184 | 184 | | |
185 | 185 | | |
186 | 186 | | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | 187 | | |
196 | 188 | | |
197 | 189 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| |||
Lines changed: 0 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
75 | | - | |
76 | | - | |
77 | 75 | | |
78 | 76 | | |
79 | 77 | | |
| |||
238 | 236 | | |
239 | 237 | | |
240 | 238 | | |
241 | | - | |
242 | | - | |
243 | 239 | | |
244 | 240 | | |
245 | 241 | | |
| |||
332 | 328 | | |
333 | 329 | | |
334 | 330 | | |
335 | | - | |
336 | | - | |
337 | 331 | | |
338 | 332 | | |
339 | 333 | | |
Lines changed: 2 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
43 | 44 | | |
44 | 45 | | |
45 | 46 | | |
46 | | - | |
| 47 | + | |
47 | 48 | | |
48 | 49 | | |
49 | 50 | | |
| |||
Lines changed: 0 additions & 198 deletions
This file was deleted.
Lines changed: 2 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
| |||
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
53 | | - | |
| 54 | + | |
54 | 55 | | |
55 | 56 | | |
56 | 57 | | |
| |||
0 commit comments