androidx crashing the app with a SQLiteDiskIOException - android

I do not have any database-related code in my android app. Still, I do see database-related crashes from the usage of androidx in my app. Please help me understand and find a fix for this issue.
Fatal Exception: android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 4874): , while compiling: PRAGMA journal_mode
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:897)
at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:642)
at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:323)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:218)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:196)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:464)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:186)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:178)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:916)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:893)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:796)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:1309)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:268)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)
at androidx.room.RoomDatabase.beginTransaction(RoomDatabase.java:328)
at androidx.work.impl.utils.ForceStopRunnable.cleanUp(ForceStopRunnable.java:135)
at androidx.work.impl.utils.ForceStopRunnable.run(ForceStopRunnable.java:79)
at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:75)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)

Based on this issue and this issue, you may be out of disk space.
WorkManager stores job information in a SQLite database, and that is where you are crashing.
It appears that a future version of WorkManager (2.6.x) might offer better APIs for dealing with this case.

Related

android studio SQL lite database error (android.database.sqlite.SQLiteException)

I copy/paste the already created .db file to my android studio project, but it is crashing my app. That database file is working fine on another android studio project but it is giving exceptions and causing the app to crash on my current project. Following is the logcat
2022-05-26 19:42:18.147 21758-21758/com.learning.kidslearningzone E/TAG: setAppAdId:BeforeChange::::: ca-app-pub-3940256099942544~3347511713
2022-05-26 19:42:18.147 21758-21758/com.learning.kidslearningzone E/TAG: setAppAdId:AfterChange:::: ca-app-pub-3940256099942544~3347511713
2022-05-26 19:42:30.180 21758-21758/com.learning.kidslearningzone E/SQLiteLog: (1) no such table: kids in "SELECT * FROM kids WHERE id=2"
2022-05-26 19:42:30.183 21758-21758/com.learning.kidslearningzone E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.learning.kidslearningzone, PID: 21758
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.learning.kidslearningzone/com.learning.kidslearningzone.Courses.ListVideoActivity}: android.database.sqlite.SQLiteException: no such table: kids (code 1 SQLITE_ERROR[1]): , while compiling: SELECT * FROM kids WHERE id=2
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3835)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4011)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2325)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8633)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Caused by: android.database.sqlite.SQLiteException: no such table: kids (code 1 SQLITE_ERROR[1]): , while compiling: SELECT * FROM kids WHERE id=2
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1463)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:901)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:590)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:62)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:2063)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:2002)
at com.learning.kidslearningzone.Databases.DatabaseHelper.getVideoDetails(DatabaseHelper.kt:20)
at com.learning.kidslearningzone.Courses.ListVideoActivity.setRvVideoListAdapter(ListVideoActivity.java:60)
at com.learning.kidslearningzone.Courses.ListVideoActivity.initDefine(ListVideoActivity.java:49)
at com.learning.kidslearningzone.Courses.ListVideoActivity.onCreate(ListVideoActivity.java:39)
at android.app.Activity.performCreate(Activity.java:8207)
at android.app.Activity.performCreate(Activity.java:8191)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3808)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4011) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2325) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:246) 
at android.app.ActivityThread.main(ActivityThread.java:8633) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
 
plz someone tell me what is the problem or what i have done wrong. Thanks
Every project has its own database may it be Room or Sqlite once you build your project the database will be created locally, so it is unique to the project and your need to add elements manually. What you did is you brought that file to another project and the query which you wrote is very SUS cause your present project database do not have any id:2 entry so it is failing.
You cannot just cut and paste the database into the project. For such a pre-existing database you would typically copy and paste the database into the assets folder and then use an adapted custom class that extends SQLiteOpenHelper (from your stack trace Databases.DatabaseHelper).
This adapted custom class MUST, in addition to the usual implementation have code that will:-
check to see if the database already exists.
if the database file does not exists copy the database file from the assets folder to the ultimate location (typically data/data/<the_package_name>/databases/<the_database_file_name)
Should the database then not exist (if no exception has stopped the app) or if the database is corrupt then the database will be created WITHOUT anything but the sqlite_master table and the android_metadata table, so effectively , from the user/developer viewpoint, an empty database and hence a table not found.
I would suspect that this is what is happening.
However, another scenario where this can happen if exceptions are caught/trapped and allow processing to continue. Is when the SQLiteDatabase's getWritableDatabase or getReadableDatabase are used for later Android versions when WAL (Write-Ahead Logging is the default). In short this creates a -wal file, which is NOT owned by the original database file created by the methods as that database file has been overwritten by the one copied from the asset. The too friendly openOrCreate method used then sees the corrupt database and gives you a new database devoid of any tables.
It is suggested that one of the above is the issue that you face. Although a bit over the top this may be of use.

Android SQLiteDiskIOException (code 522 SQLITE_IOERR_SHORT_READ)

I am on Android O and using Room database, from time to time, I experience SQLiteDisckIOException, I try to troubleshoot problem but the stack doesn't tell me where the failing point is. Can some give me some hint or how to troubleshoot this kind of problem and what is the potential problem here? The app that I am writing will write to database when location change, and also there are couple background task that periodic update database when needed.
Here is the stack I see:
10-07 22:29:41.404 22214-22226/? E/DataBuffer: Internal data leak within a DataBuffer object detected! Be sure to explicitly call release() on all DataBuffer extending objects when you are done with them. (internal object: com.google.android.gms.common.data.DataHolder#b0fef92)
10-07 22:29:41.405 22214-22226/? E/DataBuffer: Internal data leak within a DataBuffer object detected! Be sure to explicitly call release() on all DataBuffer extending objects when you are done with them. (internal object: com.google.android.gms.common.data.DataHolder#db3ad63)
10-07 22:29:41.415 19847-19847/com.firsapp.testing E/Periodic: from PIM->onCreateOptionMenu
10-07 22:29:41.442 19847-21824/com.firsapp.testing E/SQLiteLog: (522) statement aborts at 7: [SELECT DISTINCT tag FROM worktag WHERE work_spec_id=?] disk I/O error
10-07 22:29:41.443 19847-21824/com.firsapp.testing E/SQLiteQuery: exception: disk I/O error (code 522 SQLITE_IOERR_SHORT_READ); query: SELECT DISTINCT tag FROM worktag WHERE work_spec_id=?
10-07 22:29:41.449 19847-21824/com.firsapp.testing E/AndroidRuntime: FATAL EXCEPTION: pool-6-thread-2
Process: com.firsapp.testing, PID: 19847
android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 522 SQLITE_IOERR_SHORT_READ)
at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:859)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:836)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:149)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:137)
at androidx.work.impl.model.WorkTagDao_Impl.getTagsForWorkSpecId(WorkTagDao_Impl.java:92)
at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:102)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
10-07 22:29:41.579 890-890/? E/lowmemorykiller: Error writing /proc/19847/oom_score_adj; errno=22
From the SQLite documentation SQLITE_IOERR_SHORT_READ refers to a case where the database was unable to read the requested number of bytes from the file system.
https://www.sqlite.org/rescode.html#ioerr_short_read
Do you allow your apps to be installed on the external storage directory ?
https://developer.android.com/guide/topics/manifest/manifest-element.html#install
My guess is that:
Either the file system on the device is problematic.
The app was in an external storage directory, and the SD card was removed while the user was using your app, and that caused SQLite to throw this exception.

Room Database: Crash on RoomOpenHelper.checkIdentity()

I've got a legacy app that's using Room that's crashing as soon as the first database query is executed, no matter what the query is.
java.lang.RuntimeException: Unable to start service com.someco.android.nettasks.PushQueueService#24ccdca6 with Intent { cmp=com.someco.android/.nettasks.PushQueueService }: android.database.sqlite.SQLiteException: Cannot execute this statement because it might modify the database but the connection is read-only.
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3439)
at android.app.ActivityThread.access$2200(ActivityThread.java:181)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1572)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6117)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Caused by: android.database.sqlite.SQLiteException: Cannot execute this statement because it might modify the database but the connection is read-only.
at io.requery.android.database.sqlite.SQLiteConnection.throwIfStatementForbidden(SQLiteConnection.java:1091)
at io.requery.android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:755)
at io.requery.android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:764)
at io.requery.android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:71)
at io.requery.android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1867)
at io.requery.android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1808)
at android.arch.persistence.room.RoomOpenHelper.createMasterTableIfNotExists(RoomOpenHelper.java:131)
at android.arch.persistence.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:107)
at android.arch.persistence.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:100)
at io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory$CallbackSQLiteOpenHelper.onOpen(RequerySQLiteOpenHelperFactory.java:67)
at io.requery.android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:283)
at io.requery.android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:174)
at io.requery.android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:44)
at com.someco.android.dmodel.OurDB.writableDb(OurDB.java:363)
at com.someco.android.nettasks.PushQueueService.startExecution(PushQueueService.java:202)
at com.someco.android.nettasks.PushQueueService.onStartCommand(PushQueueService.java:157)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3422)
at android.app.ActivityThread.access$2200(ActivityThread.java:181)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1572)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6117)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
From my investigations on the debugger, what's happening is that there's some sort of racing issue with regard to calls to sqlite3_stmt_readonly() in sqlite itself. This is the actual query that causes the crash, from RoomOpenHelper#createMastertableIfNotExists:
CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
In RoomOpenHelper#onCreate, the table is created successfully. A statement seems to be compiled two times and checked for read-only status those two times:
Once in SQLiteProgram's constructor (via SQLiteStatement)
Once in SQLiteConnection#executeForChangedRowCount
What happens is that the connection fetched for the first one is opened with more permissive permissions (6, for me - 1 is the bit that denotes read-only status), and it's correctly evaluated to not be read-only. That means that the connection for the second statement compilation is requested with read-only flags (5, for me). The crash happens because for some reason, the query is evaluated to not be read-only once again.
I'm at a total loss for this one. Why does this crash? How is the same statement read-only sometimes and not read-only other times?
The problem is that room 1.0.0 does not support the Write-Ahead Log. I removed a line that enabled it in the app:
db.getOpenHelper().setWriteAheadLoggingEnabled(true);
The WAL is supported in version 1.1.0-alpha2. After trying out the new alpha, everything worked, so the change log pointed me to the answer. I've an example project with a brief write-up of the issue.

Cursor window allocation of 2048 kb failed with rxjava adapter on room

I'm using Room with RxJava2 version 1.0.0 in my app. Previously I was using Realm and all was fine. Now when I've migrated on Room I get random rare crashes with similar stacktrace:
Fatal Exception: android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed.
at android.database.CursorWindow.<init>(CursorWindow.java:109)
at android.database.CursorWindow.<init>(CursorWindow.java:100)
at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
at android.database.sqlite.SQLiteCursor.clearOrCreateWindow(SQLiteCursor.java:301)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:139)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:197)
at android.database.AbstractCursor.moveToNext(AbstractCursor.java:245)
at android.arch.persistence.room.InvalidationTracker.run(InvalidationTracker.java:372)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Some times its even don't have room mentions in there. I'm not using any Cursors directly, only thru Room and 3rd party libraries (which I haven't changed during migration).
I've checked Room generated code and it all seems to close Cursors properly.
Any thoughts on what is going on and how I can debug this crashes?
It turns out that the problem was in RxJava's .subscribeOn(Schedulers.io()) for Flowable responses in RxJava Room adapter. Apparently it was starting threads but has never released them.
I've swapped Schedulers.io() on fixed thread pool with up to 20 threads and it does go away.

Android SQLite exceptions caused by firebase modules

We recently added Firebase to our app and noticed a high increase of SQLite exceptions.
Logs:
android.database.sqlite.SQLiteReadOnlyDatabaseException:
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method:0)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:788)
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1474)
at bkf.a(:com.google.android.gms.DynamiteModulesC:70)
at bkw.run(:com.google.android.gms.DynamiteModulesC:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)>
or
android.database.sqlite.SQLiteDiskIOException:
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method:0)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:788)
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1472)
at bkf.a(:com.google.android.gms.DynamiteModulesC:70)
at bkw.run(:com.google.android.gms.DynamiteModulesC:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
In our app we're using SQLite too (multiple threads, single instances of SQLiteOpenHelper), however we don't get any exceptions there.
We also noticed that these exceptions were thrown for about 90% on Sony devices. (SDK 23 and above)
Which comes first in my mind, is a failed SQLite implementation on these devices but I'm not able to reproduce it on our Sony devices, so my questions are:
is this a known Firebase issue?
can anyone confirm my guess?
and well,
what will be a possible workaround
Any help would be appreciated.
Edit:
For sure it's related to SQLiteReadOnlyDatabaseException (it's mentioned in the logs ;) ) but it affects mostly Sony devices and it's not our db which fails but Googles, so I don't think it's duplicated to SQLiteReadOnlyDatabaseException: attempt to write a readonly database

Categories

Resources