net.zetetic.database.sqlcipher.SQLiteConnectionPool.throwIfClosedLocked
Exception java.lang.RuntimeException: An error occurred while executing doInBackground()
at androidx.loader.content.ModernAsyncTask$3.done (ModernAsyncTask.java:164)
at java.util.concurrent.FutureTask.finishCompletion (FutureTask.java:381)
at java.util.concurrent.FutureTask.setException (FutureTask.java:250)
at java.util.concurrent.FutureTask.run (FutureTask.java:269)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:644)
at java.lang.Thread.run (Thread.java:1012)
Caused by java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at net.zetetic.database.sqlcipher.SQLiteConnectionPool.throwIfClosedLocked (SQLiteConnectionPool.java:974)
at net.zetetic.database.sqlcipher.SQLiteConnectionPool.waitForConnection (SQLiteConnectionPool.java:689)
at net.zetetic.database.sqlcipher.SQLiteConnectionPool.acquireConnection (SQLiteConnectionPool.java:360)
at net.zetetic.database.sqlcipher.SQLiteSession.acquireConnection (SQLiteSession.java:929)
at net.zetetic.database.sqlcipher.SQLiteSession.executeForCursorWindow (SQLiteSession.java:869)
at net.zetetic.database.sqlcipher.SQLiteQuery.fillWindow (SQLiteQuery.java:68)
at net.zetetic.database.sqlcipher.SQLiteCursor.fillWindow (SQLiteCursor.java:196)
at net.zetetic.database.sqlcipher.SQLiteCursor.getCount (SQLiteCursor.java:135)
at android.content.ContentResolver.query (ContentResolver.java:1252)
at android.content.ContentResolver.query (ContentResolver.java:1165)
at androidx.core.content.ContentResolverCompat$Api16Impl.query (ContentResolverCompat.java:119)
at androidx.core.content.ContentResolverCompat.query (ContentResolverCompat.java:87)
at androidx.loader.content.CursorLoader.loadInBackground (CursorLoader.java:63)
at androidx.loader.content.CursorLoader.loadInBackground (CursorLoader.java:41)
at androidx.loader.content.AsyncTaskLoader.onLoadInBackground (AsyncTaskLoader.java:307)
at androidx.loader.content.AsyncTaskLoader$LoadTask.doInBackground (AsyncTaskLoader.java:60)
at androidx.loader.content.AsyncTaskLoader$LoadTask.doInBackground (AsyncTaskLoader.java:48)
at androidx.loader.content.ModernAsyncTask$2.call (ModernAsyncTask.java:141)
at java.util.concurrent.FutureTask.run (FutureTask.java:264)
Hi @Akshay,
Is this something you can produce in an isolated application for review? Additionally, you might consider updating sqlcipher-android
, currently the latest version is 4.7.2.
Hi @developernotes,
We are using sqlcipher-android 4.6.1 version and recently uploaded it to production. We don’t have any sample app to share. Do you have any suggestion based upon the shared logs.
Hi @Akshay,
We have just released SQLCipher 4.8.0 [1]. Our suggestion would be to update to the latest version of the library and perform internal testing. If you’re able to reproduce the issue with 4.8.0, I would suggest trying to narrow down a reproduction of the issue, potentially creating a small standalone reproduction case which would allow us to review further.
Hello @Akshay - how are you managing the lifecycle of the relevant SQLiteDatabase
? Are you calling close()
on it while there may be pending operations in other threads?
Hi Team,
As we never observed any crash related to SQLiteConnectionPool.throwIfClosedLocked when we were using “4.5.3” version of SQLCipher library with same code base i.e. whatever we are using currently with library version 4.6.1.
But as soon as we upgraded the library with 4.6.1 due to 16KB device support, and published the app to store, we are observing aprox 200+ crashes reported every day.
So how it could be an issue with SQLiteDatabase close().
Could you please confirm if it is something due to bugs in the 4.6.1 version of the library?
Also could you please confirm if we upgrade the library with latest released version 4.8.0, we will not observe such crashes and we should go with the latest version? Since we can’t go back with older library version 4.5.3, as it will not support 16KB devices at all.
Hello Akshay,
The relationship between this issue and SQLiteDatabse.close() is based on an analysis of the stack trace alongside the Android Bindings code used in sqlcipher-android. The SQLiteDatabase manages a connection pool of lower level connection handles. Connections are requested opportunistically from the pool as need to fulfil database operations, including when filling CursorWIndows.
The SQLiteDatabase class attempts to do some basic reference counting to prevent premature connection closure cleanup, but I don’t think it will detect deferred use of the pool from a separate thread. Thus, one possible route to generate the throwIfClosedLocked exception you reported is to have a cursor loading in a separate thread, while the SQLiteDatabase connection managing the Connection Pool is closed or disposed of on the original thread. That looks like it is a definite possibility based on your stack trace. Thus, the question about how you are managing the lifecycle on the SQLiteDatabase object.
Unfortunately, since there is no tangible reproduction case for this, we can’t confirm it is a problem with the 4.6.1 library, or that it would be fixed in 4.8.0. It is equally possible that it a problem with library misuse, as described above. If you can provide a simple, standalone project which reproduces the problem we can investigate further.
Barring that, our recommendation would be to revisit the lifecycle of the SQLiteDatabase object, ensuring that it is in scope and remains open until all background operations that might use its connections are complete.