amitshekhariitbhu / Android-Debug-Database

A library for debugging android databases and shared preferences - Make Debugging Great Again
https://outcomeschool.com
Apache License 2.0
8.39k stars 872 forks source link

ClientServer Exception with Application database context #185

Open vdbemden opened 4 years ago

vdbemden commented 4 years ago

Hi, And at first thanks for this great tool. I used it today on test code and it worked great but after a while, I decided to put my DB at the application context level and to put it into a private static volatile variable. While the DB still works well, your debug tool doesn't like it...

The exception raised is the following one : E/ClientServer: Exception. net.sqlcipher.database.SQLiteException: file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master; at net.sqlcipher.database.SQLiteCompiledSql.native_compile(Native Method) at net.sqlcipher.database.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:91) at net.sqlcipher.database.SQLiteCompiledSql.(SQLiteCompiledSql.java:64) at net.sqlcipher.database.SQLiteProgram.(SQLiteProgram.java:89) at net.sqlcipher.database.SQLiteQuery.(SQLiteQuery.java:48) at net.sqlcipher.database.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:60) at net.sqlcipher.database.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1867) at net.sqlcipher.database.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1785) at net.sqlcipher.database.SQLiteDatabase.keyDatabase(SQLiteDatabase.java:2486) at net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal(SQLiteDatabase.java:2415) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1149) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1116) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1065) at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1226) at com.amitshekhar.server.RequestHandler.openDatabase(RequestHandler.java:185) at com.amitshekhar.server.RequestHandler.getTableListResponse(RequestHandler.java:304) at com.amitshekhar.server.RequestHandler.handle(RequestHandler.java:113) at com.amitshekhar.server.ClientServer.run(ClientServer.java:76) at java.lang.Thread.run(Thread.java:764)

And the code I used is this one :

@Database(entities = {Review.class}, version = 1, exportSchema = false)
public abstract class ReviewsDatabase extends RoomDatabase {

    private static volatile ReviewsDatabase INSTANCE;

    public abstract ReviewDao reviewDao();

    public static ReviewsDatabase getInstance(Context context) {
        if (INSTANCE == null) {
            synchronized (ReviewsDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            ReviewsDatabase.class, "myPersonalTest.db")
                            .allowMainThreadQueries()
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

Thanks for your help,

Loïc

amitshekhariitbhu commented 4 years ago

This seems weird. Is this working when you do not put it into a private static volatile variable?

vdbemden commented 4 years ago

I dig a bit further and the bug is much more weird than I thought... It seems to me that the "private static volatile" isn't involved in the process. But everytime I start with a fresh installation and a database name like "myDB.db", your debug app crashes. After that, starting the app without cleaning it produces an exception like that :

E/ClientServer: Exception. java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.util.HashMap.get(java.lang.Object)' on a null object reference at com.amitshekhar.server.RequestHandler.openDatabase(RequestHandler.java:182) at com.amitshekhar.server.RequestHandler.getTableListResponse(RequestHandler.java:304) at com.amitshekhar.server.RequestHandler.handle(RequestHandler.java:113) at com.amitshekhar.server.ClientServer.run(ClientServer.java:76) at java.lang.Thread.run(Thread.java:764)

Moreover it seems that sometimes my db logs and your web view aren't synchronized anymore. Restarting the app shows me sometimes a db corresponding to my log or to your web view, randomly... Could it be that using "synchronized" keywords or "allowMainThreadQueries()" function generate concurrent access to the database?