SQLCipher for Android, WAL, and Parallel I/O

While working on some compatibility tests for SafeRoom, I ran into what appears to be an irreconcilable conflict between SQLCipher for Android and Room. This does not appear to be a huge problem right now, though that might change in the future.

SQLCipher for Android was developed in the early days of Android and was based on Android 1.x/2.x implementations of things like SQLiteDatabase. Needless to say, the framework implementation of SQLiteDatabase has changed over the years. One of those changes is in how SQLiteDatabase interacts with SQLite itself.

Back in the day, SQLiteDatabase had native methods to talk to SQLite (by way of some native framework code). Each SQLiteDatabase had an individual separate “connection” to the underlying SQLite database.

Nowadays, the story is more complicated. SQLiteDatabase has a ThreadLocal SQLiteSession object, so a SQLiteDatabase used across multiple threads will use multiple sessions. Each session uses a database connection from a small pool of connections, with some guarantees that a connection will be used by only one thread at a time. But, connections might be used by parallel threads simultaneously. In particular, with write-ahead logging (WAL) mode enabled, it is possible to have an open transaction for writing, while in a separate thread execute a read operation, and have both succeed, with the read returning a result even while the write transaction is still open and outstanding.

While SQLCipher for Android is moving to adopt some of the newer SQLiteDatabase capabilities, this is not one of them. It will continue to use the older one-connection-per-database approach, as I understand it. So, while we can enable WAL mode, and that may have some benefits, this sort of parallel I/O is not going to be possible. This situation might improve, but for the moment, “it is what it is”.

Right now, this means that one of Room’s tests fails with SafeRoom (actually, it hangs indefinitely, and if I hack the test to avoid the deadlock, then it fails). It remains to be seen how much this limitation will be a problem with real-world uses of Room and SafeRoom.