Skip to content
This repository has been archived by the owner on Jun 18, 2023. It is now read-only.

SQLiteCantOpenDatabaseException - Android 10 #276

Open
ChristopherBull opened this issue Oct 21, 2019 · 4 comments
Open

SQLiteCantOpenDatabaseException - Android 10 #276

ChristopherBull opened this issue Oct 21, 2019 · 4 comments
Labels

Comments

@ChristopherBull
Copy link

I am experiencing app crashes on every app startup (OnePlus 7t Pro & Google Pixel 3a, both Android 10). The app is failing to create (and therefore not load) the AWARE databases. On fresh app installs (uninstall the app and delete the AWARE folder), the app crashes immediately after AWARE requests contacts and storage permissions.

Development context/background:

  • I have been developing with AWARE for months without a problem, I came back to the project recently with fresh new phones and am now facing problems.
  • I am using the AWARE framework as suggested in the documentation: api "com.github.denzilferreira:aware-client:master-SNAPSHOT" (though also explicitly tried versions 4.0.820 and 4.0.821)
  • I have stripped my app back to bare minimum and only call the following during the app's onCreate(): Aware.startAWARE(this)

Reproducing the issue:

  • Bizzarely, the app works fine (loads the AWARE DBs) when using two Google Pixel 3a (Android 9) phones, so perhaps it may be an Android 10 issue? I can confirm my app does have Storage permission on all devices.
  • I just updated one of the Google Pixel 3a's to Android 10. The app now also crashes on that phone in the same way.

Stacktrace

Logcat stacktrace: stack.txt

This is a stacktrace of the OnePlus 7T Pro (Android 10), with a fresh install of my app, and checked that the AWARE folder did not exist before (and still does not after the app crashed).

Relevant error stacktraces start at: 2019-10-21 14:50:28.066

I have copied what I believe to be the pertinent errors from Logcat, to give you somewhere to jump to in the trace file.

2019-10-21 14:50:28.069 31891-31891/? E/SQLiteLog: (14) cannot open file at line 36683 of [c255889bd9]
2019-10-21 14:50:28.069 31891-31891/? E/SQLiteLog: (14) os_unix.c:36683: (2) open(/storage/emulated/0/AWARE/aware.db) -
2019-10-21 14:50:28.069 31891-31891/? E/SQLiteDatabase: Failed to open database '/storage/emulated/0/AWARE/aware.db'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database

Main crash occurs here:

--------- beginning of crash
2019-10-21 14:50:28.299 31891-31891/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: uk.ac.lancaster.spaceapp, PID: 31891
java.lang.RuntimeException: Unable to start service com.aware.utils.Scheduler@cbacc2c with Intent { cmp=uk.ac.lancaster.spaceapp/com.aware.utils.Scheduler }: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.database.sqlite.SQLiteDatabase.validateSql(java.lang.String, android.os.CancellationSignal)' on a null object reference
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4222)
at android.app.ActivityThread.access$2100(ActivityThread.java:231)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1984)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void
android.database.sqlite.SQLiteDatabase.validateSql(java.lang.String, android.os.CancellationSignal)' on a null object reference
at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:496)
at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:392)
at com.aware.providers.Scheduler_Provider.query(Scheduler_Provider.java:198)
at android.content.ContentProvider.query(ContentProvider.java:1276)
at android.content.ContentProvider.query(ContentProvider.java:1369)
at android.content.ContentProvider$Transport.query(ContentProvider.java:275)
at android.content.ContentResolver.query(ContentResolver.java:962)
at android.content.ContentResolver.query(ContentResolver.java:890)
at android.content.ContentResolver.query(ContentResolver.java:846)
at com.aware.utils.Scheduler.onStartCommand(Scheduler.java:635)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4204)
at android.app.ActivityThread.access$2100(ActivityThread.java:231) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1984) 
at android.os.Handler.dispatchMessage(Handler.java:107) 
at android.os.Looper.loop(Looper.java:214) 
at android.app.ActivityThread.main(ActivityThread.java:7682) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) 

Note: All devices (Android 9 and 10) spew out the first batch of SQLiteCantOpenDatabaseException errors during the first app load after a fresh install, but presumably the applications that launch successfully (Android 9) are able to eventually create the AWARE DBs.

@ChristopherBull
Copy link
Author

I tried digging for more useful info, but was not very successful.

I grabbed a more succinct stacktrace:
stack.txt

Two lines that stood out, just before all the Failed to open database exceptions:

E/Perf: Fail to get file list uk.ac.lancaster.spaceapp
E/Perf: getFolderSize() : Exception_1 = java.lang.NullPointerException: Attempt to get length of null array

I'm not sure why it is failing with file operations (double-checked storage permissions were given). I couldn't find getFolderSize() in the AWARE codebase. Perhaps it is an Aware dependecy?

@nleo575
Copy link

nleo575 commented Jan 27, 2020

@denzilferreira This issue could be directly related to the contacts plugin. I filed issue #275. Has there been any progress made with either of these issues?

@ChristopherBull
Copy link
Author

I have figured out the problem I was facing. The solution was simple in the end, but not documented.

You need to add this file res/values/bools.xml, with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="standalone" type="bool" format="boolean">true</item>
</resources>

Whilst I am happy with own implementation, some changes need to be made before I would consider this resolved as the default behaviour crashes on Android 10 devices. It would be great to:

  1. Document the booleans used in bools.xml somewhere. I have checked and there is no mention of standalone boolean anywhere in this repo's README.md, nor awareframework.com
  2. Use better defaults for Android 10, so the default behaviour is not to crash.

I was reading the source (following the stacktraces I provided) and centred on the following method:

/* com.aware.utils.DatabaseHelper.java */
private synchronized SQLiteDatabase getDatabaseFile() {
    try {
        File aware_folder;
        if (mContext.getResources().getBoolean(R.bool.internalstorage)) {
            // Internal storage.  This is not acceassible to any other apps and is removed once
            // app is uninstalled.  Plugins can't use it.  Hard-coded to off, only change if
            // you know what you are doing.  Beware!
            aware_folder = mContext.getFilesDir();
        } else if (!mContext.getResources().getBoolean(R.bool.standalone)) {
            // sdcard/AWARE/ (shareable, does not delete when uninstalling)
            aware_folder = new File(Environment.getExternalStoragePublicDirectory("AWARE").toString());
        } else {
            if (isEmulator()) {
                aware_folder = mContext.getFilesDir();
            } else {
                // sdcard/Android/<app_package_name>/AWARE/ (not shareable, deletes when uninstalling package)
                aware_folder = new File(ContextCompat.getExternalFilesDirs(mContext, null)[0] + "/AWARE");
            }
        }

        if (!aware_folder.exists()) {
            aware_folder.mkdirs();
        }

        database = SQLiteDatabase.openOrCreateDatabase(new File(aware_folder, this.databaseName).getPath(), this.cursorFactory);
        return database;
    } catch (SQLiteException e) {
        return null;
    }
}

It makes reference to where files/folders are to be stored/read. I checked my Android 9 devices' filesystem and found the AWARE folder in Internal storage/AWARE/ (I did not have a bools.xml file, so it used default values, presumably). On Android 10, it was not in any of the suggested locations (and crashes). After setting the booleans in bools.xml (as mentioned above), the app no longer crashes and the files appear in Internal storage/Android/data/<app_package_name>/files/AWARE/.

I have not extensively tested on a matrix of various devices and Android versions, but doing this fixes the problem I was facing.

It is possible it has something to do with Privacy changes in Android 10

@TylerADavis
Copy link

Thanks @ChristopherBull ! I was running into this issue as well, and adding the file you mentioned resolved the errors I was getting related to being unable to open the SQLite db.

I ran into this issue while running the android simulator targeting API 30.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants