sqlcipher / android-database-sqlcipher

Android SQLite API based on SQLCipher
https://www.zetetic.net/sqlcipher/sqlcipher-for-android/
Other
2.76k stars 567 forks source link

attempt to write a readonly database, crashes on android 5.0v devices while using SqlCipher #161

Closed praveenb closed 7 years ago

praveenb commented 9 years ago

Im getting following log on app crash, on android 5.0v devices

Caused by: net.sqlcipher.database.SQLiteException: attempt to write a readonly database at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method) at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096) at net.sqlcipher.database.SQLiteDatabase.(SQLiteDatabase.java:1962) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881) at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:913) at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:132) at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:99) at PackageName.DBHelperCipher.(DBHelperCipher.java:93) at PackageName.ProcessDBCipherInitTask.doInBackground(ProcessDBCipherInitTask.java:20) at PackageName.ProcessDBCipherInitTask.doInBackground(ProcessDBCipherInitTask.java:1) at android.os.AsyncTask$2.call(AsyncTask.java:288) at java.util.concurrent.FutureTask.run(FutureTask.java:237)

I've submitted a question on StackOverflow, http://stackoverflow.com/q/29988933/341443. Can you please help on this.

Thank you.

developernotes commented 9 years ago

Hello @praveenb

Are you able to replicate the crash on your 5.0 device when running the SQLCipher for Android test suite?

praveenb commented 9 years ago

@developernotes Thank you so much for your kind reply, I run the test suite on Android 5.0 device, Though I see a crash at some other test condition, I do not see a crash resulting error log given above. i.e I'm not able to replicate above crash.

Not sure where im doing mistake in my code. I think i need to investigate further in test suite to handle the issue in my project.

But, I just like to ask,.. you have any other suggestions or guidelines for me on this.

Thank you.

developernotes commented 9 years ago

Hello @praveenb

Do you have a specific test case that is failing consistently in the test suite?

With regard to your specific scenario though, does the database file exist right before you initialize the DBHelperCipher instance?

praveenb commented 9 years ago

@developernotes,

there is no database file exist before initialize the class... Just for clarification, I published app to Play Store, I see app crashes, When I do a fresh install from play store, on a android 5.0v device.

I debugged the android-database-sqlcipher project, by giving external path, as shown below public EventDataSQLHelper(Context context, String name, CursorFactory factory, int version) { super(context, DB_PATH+DATABASE_NAME, null, DATABASE_VERSION); } **here DB_PATH constant refers to external path.

And I see the issue is occurring only when created db file on external storage, see the issue occurring at this line setLocale(Locale.getDefault()); in SQLiteDatabase file

Please let me any idea on this.

Thankyou

developernotes commented 9 years ago

Hello @praveenb

I am wondering if there is an issue within the internals of getWritableDatabase(). As an experiment, could you try invoking SQLiteDatabase.openOrCreateDatabase(…); before you initialize your EventDataSQLHelper only when the database file does not exist before hand? Could you let us know your results? Thanks!

praveenb commented 9 years ago

Im getting the same error, invoking SQLiteDatabase.openOrCreateDatabase(…); method

Thanks

developernotes commented 9 years ago

Hello @praveenb

If you can prepare a test within the test suite, I would be glad to take a look at it on a Lollipop device.

praveenb commented 9 years ago

Hi @developernotes ,

Please see this link https://github.com/praveenb/sqlcipher-android-tests, I added test class to test suite. Please see committed code changes.

Hi Nick, You are able to see issue on your side. or You see any issue in committed changes. Please reply on this.

FYI, I see this issue on Lenovo A7000, Lollipop device. Please help on this.

Thank you.

chetan1011 commented 9 years ago

Hi @developernotes ,

I am getting the same error,error code 8: attempt to write a read only database

When I am write(Insert) record in database at this time I am getting this error in my lolipop device.

please help me ...

FYI, I see this issue on Lenovo A7000-a, Lollipop device. Please help on this.

developernotes commented 9 years ago

Hello @chetan1011

Can you verify whether the database file exists before you attempt to write to it?

praveenb commented 9 years ago

Hi @developernotes ,

You are able to look at the test suit changes that i made at this link https://github.com/praveenb/sqlcipher-android-tests.

Please let me know if you need any other details

Thank you.

chetan1011 commented 9 years ago

Hello @developernotes ,

The database file was store in sdcard(External_storage)... and i take permission in android manifest "android.permission.WRITE_EXTERNAL_STORAGE"

developernotes commented 9 years ago

Hello @chetan1011

Can you verify whether the database file exists on the SD card prior to any attempts to interact with it via the SQLCipher API? Thanks!

BenPope commented 9 years ago

I'm having a similar problem on Android 5.0.2 with native (c++) sqlcipher 3.3.0.

ls -al /storage/emulated/0/Android/data/com.app.name/files/data.db
-rw-rw---- u0_a165  sdcard_r    38912 2015-05-28 21:31 data.db

I get an exception "attempt to write a readonly database".

It's weird. The app manages to write the database on startup.

It also fails miserably if I try to put it into EXCLUSIVE locking mode, could it somehow be trying to lock the file more than once?

chetan1011 commented 9 years ago

Hello @developernotes ,

@developernotes Thank you so much for your kind reply,

Yes sir, i check database file is exist or not in sdcard...at that time database is exist in sdcard..

I mean database file is exist in sdcard...

still Im getting the same error, android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.

This error got in only 5.0 (lolipop)version in android.

Please let me know if you need any other details

Thank you.

brodycj commented 9 years ago

FYI the same problem (crash with net.sqlcipher.database.SQLiteException: attempt to write a readonly database) is also discussed in: https://discuss.zetetic.net/t/sqlcipher-on-android-5-0-x64-emulator-crash/286

still Im getting the same error, android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.

@chetan1011 looks like it may be the same problem as #139.

brodycj commented 9 years ago

According to the documentation in http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html, and also in the Javadoc, it is possible that SQLiteDatabase.openDatabase (and SQLiteDatabase.openOrCreateDatabase()) can throw a SQLiteException if it cannot open the database for some reason. It should be the responsibility of the application to catch and handle this error. I wonder if we should add throws SQLException to the declaration of these functions to avoid these crashes?

chetan1011 commented 9 years ago

Hello brodybits, Thank you so much for your kind reply,

I am use following code: database = SQLiteDatabase.openOrCreateDatabase(db_path, "**", null); SQLiteStatement insertStmt = database.compileStatement(insertQuery); recordId = insertStmt.executeInsert();

then i got "attempt to write a read only database"

if you hve any solution then please give me your solution ya any sample...

please help me dude...

brodycj commented 9 years ago

@chetan1011 can you post the log to show where your application is failing?

chetan1011 commented 9 years ago

HI @brodybits , bellow I post my log where i failing application..

05-29 17:55:20.391: W/System.err(4598): net.sqlcipher.database.SQLiteException: error code 8: attempt to write a readonly database 05-29 17:55:20.391: W/System.err(4598): at net.sqlcipher.database.SQLiteStatement.native_execute(Native Method) 05-29 17:55:20.391: W/System.err(4598): at net.sqlcipher.database.SQLiteStatement.executeInsert(SQLiteStatement.java:84) 05-29 17:55:20.391: W/System.err(4598): at com.esense.topscorer.scratchcard.QueryCreator.insertRecords(QueryCreator.java:94) 05-29 17:55:20.391: W/System.err(4598): at com.esense.topscorer.scratchcard.InsertImpl.runQuery(InsertImpl.java:18) 05-29 17:55:20.391: W/System.err(4598): at com.esense.topscorer.scratchcard.BaseAsyncDBOperation.doInBackground(BaseAsyncDBOperation.java:56) 05-29 17:55:20.391: W/System.err(4598): at com.esense.topscorer.scratchcard.BaseAsyncDBOperation.doInBackground(BaseAsyncDBOperation.java:1) 05-29 17:55:20.391: W/System.err(4598): at android.os.AsyncTask$2.call(AsyncTask.java:288) 05-29 17:55:20.391: W/System.err(4598): at java.util.concurrent.FutureTask.run(FutureTask.java:237) 05-29 17:55:20.391: W/System.err(4598): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 05-29 17:55:20.391: W/System.err(4598): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 05-29 17:55:20.391: W/System.err(4598): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 05-29 17:55:20.391: W/System.err(4598): at java.lang.Thread.run(Thread.java:818)

please help me..

brodycj commented 9 years ago

@chetan1011, for some reason your case is different from the OP. In your case, openOrCreateDatabase() succeeds but insertStmt.executeInsert() is failing. Can you log and post the string value of db_path?

chetan1011 commented 9 years ago

@brodybits dbpath is valid...

it's database file and it's exist in sdcard...

this code is working fine in all other version but.... it's just not working in 5.0 android version...

brodycj commented 9 years ago

Just issued PR #174 with fixes to show where SQLiteDatabase.dbopen is actually failing. If you are having problems, please try again with these changes and report your results.

developernotes commented 9 years ago

@chetan1011 you may want to hold off on #174 right now, there is still some work going on there.

brodycj commented 9 years ago

Just reworked the changes in PR #175 to show where SQLiteDatabase.dbopen() is actually failing, waiting for review.

developernotes commented 9 years ago

@brodybits will check it out shortly, just finishing some work on cleaning up ICU loading.

brodycj commented 9 years ago

@brodybits will check it out shortly, just finishing some work on cleaning up ICU loading.

:+1: Testing #175 uncovered an issue that I reported in #176. I will look further tomorrow night or early next week.

Thanks for integrating my fixes so far!

chetan1011 commented 9 years ago

@developernotes ,@brodybits good morning,

HI Sir, still I am getting the same error, android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.

how can solve this error..?

please help me

brodycj commented 9 years ago

Good morning @chetan1011,

This project has been updated to report a more specific error in the native code (built from C++). Please get the latest changes from this project, do make clean, and rebuild. On Jun 4, 2015 7:30 AM, "chetan1011" notifications@github.com wrote:

@developernotes https://github.com/developernotes ,@brodybits https://github.com/brodybits good morning,

HI Sir, still I am getting the same error, android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.

how can solve this error..?

please help me

— Reply to this email directly or view it on GitHub https://github.com/sqlcipher/android-database-sqlcipher/issues/161#issuecomment-108732217 .

developernotes commented 9 years ago

Hello @praveenb @chetan1011

Please post the path your application is using within the SD card to store/access the database. There were some changes introduced around 4.4 to adjust the WRITE_EXTERNAL_STORAGE permission on Android that could be the cause depending on the path you are using.

praveenb commented 9 years ago

Hi Nick @developernotes , I see the changes http://android.stackexchange.com/a/77436, link, that makes sense.

please see this file which i created from forked test suit, https://github.com/praveenb/sqlcipher-android-tests/blob/master/src/main/java/net/zetetic/tests/ExternalPathDatabaseTest.java

as per the code in above test suit link, db path is like this /storage/sdcard0/ZeteticTestDB/test.db

i'm following the same code in my current project to get external path and to store db file.

please let me know your thoughts on it.

Thank you.

praveenb commented 9 years ago

Hi @developernotes , For now, I think the only solution is, to move db file to internal application storage, which works on >5.0 devices too.

I checked installing a different app which uses normal sqlite database storing on External SD card path on 5.0v device, its working fine.

I think its a drawback with the SqlCipher library :(.

Thank you.

mkovalyk commented 8 years ago

Any updates on this issue?

praveenb commented 8 years ago

@developernotes , My Android application got negative reviews :-1: , for using this library in app. As its not supported on few Android devices. I feel bad for choosing this library. I'm thinking to remove my app from Playstore and do a new app using normal Sqlite db classes to support all devices.

I don't recommend this to anybody. Though its a free library version, Once you used in app, you'll end up like me. Hope it helps somebody.

ahfchan commented 8 years ago

Hi,

Thanks for raising and looking into this issue.

I'm experiencing the same problem, too - using sqlcipher 3.3.0 natively on Android 5.0. Is there a solution to this problem, besides putting the Db on internal storage?

Thank you.

developernotes commented 8 years ago

Hello @ahfchan

What is the full path to the database on the SD card that you are unable to write to? What permissions does your application require?

ahfchan commented 8 years ago

Hi @developernotes

Thanks for the reply. I've tried a few tests and still encountered the same 'attempt to write a readonly database' issue on my Redmi Note 2 device running Android 5.0.2

case 1: no physical sd card inserted (i.e. emulated)

The full path is: /storage/emulated/0/Android/data/com.app.name/files/MyApp/chat.db The root dir was retrieved with the Android call Context.getExternalFilesDirs(null) (or getExternalFilesDirs(null)[0] which yields the same result).

case 2: with sd card

The full path is: /storage/sdcard1/Android/data/com.app.name/files/MyApp/chat.db with getExternalFilesDirs(null)[1]

Both cases: the db file was created, the app was also able to write to the log file placed in the same directory. When attempting to insert a record into the db, I get an the error 'attempt to write a readonly database'

Checking the permissions using adb shell on the db file: -rwxrwx--- u0_a129 sdcard_r

, and the directories , 'files', MyApp': drwxrwx--- u0_a129 sdcard_r

The permissions needed by my app are: android.permission.WRITE_EXTERNAL_STORAGE android.permission.VIBRATE android.permission.INTERNET android.permission.ACCESS_NETWORK_STATE android.permission.GET_ACCOUNTS android.permission.WAKE_LOCK android.permission.RECORD_AUDIO android.permission.MODIFY_AUDIO_SETTINGS com.google.android.providers.gsf.permission.READ_GSERVICES android.permission.ACCESS_COARSE_LOCATION android.permission.ACCESS_FINE_LOCATION

Would appreciate any insight you can provide on the issue. Please let me know if I could provide any additional info to assist.

Thanks.

developernotes commented 8 years ago

Hello @ahfchan

Are you able to consistently reproduce the issue? If so, is it always on the Redmi device, or others?

ahfchan commented 8 years ago

Hi @developernotes

Yes I can consistently reproduce what I've reported on my Redmi Note2 which is on Android 5.0.2.

I also had the same issue (consistently reproducable) with an HTC M9 back in May 2015. I believe it was also running Android 5.0.x. The issue no longer appeared after a few months (very likely after upgrading to Android 5.1). The device is now on Android 6 and it's working also.

I have a few more devices at hand: Nexus 7 running 4.4, Samsung galaxy S6 running 5.1, Nexus 5 running 6.1 - all without problems. Unfortunately Redmi is only only 5.0.x device I have at hand now.

From reading what others have commented on this thread, it appears Android 5.0.x may be the only affected version, which seems consistent with my experience.

Thanks again.

linsmalldragon commented 8 years ago

@developernotes I have the same issue on Redmi Device and can reproduce it every time. The sdk is Android 5.0.2. Other versions is all ok. Any other solutions except moving data into internal storage on android 5.0.2?

developernotes commented 8 years ago

Hello @linsmalldragon

Unfortunately I do not have access to that specific device to perform further debugging with it. I am not aware of another solution at this time.

faoiseamh commented 8 years ago

I can confirm this is still an issue. It occurs consistently on the following device / OS (tried on multiple of these devices):

Device: LG G Pad X8.3 (VK815) OS: Android 5.0.2

I don't have access to the devices to do any further testing myself, but the behavior is very consistent.

baskar007 commented 8 years ago

I can consistently reproduce the same issue on Mi 4i Android version 5.0.2.

eyeled commented 8 years ago

The issue can be reproduced in the 5.0 x86_64 emulator. Key point seems to be that the database is located in the external storage. We've started seeing this issue immediately after upgrading from a >2 years old version of sqlcipher to the current release. The problem is that fileHasMoved in https://github.com/sqlcipher/sqlcipher/blob/master/src/os_unix.c#L1324 returns TRUE even though the file is still there. Hardcoding to return 0 fixes the issue in the emulator. We also haven't seen the issue again for more than 1 week on acutal devices.

developernotes commented 8 years ago

Hello @eyeled

Thank you for your feedback, we look forward to hearing your results on device.

atultiwari commented 8 years ago

Hi, As mentioned in discussion forum, my app is crashing (at least in 2 known mobiles - Mi 4i and Lenovo Phab Plus) soon after it tries to access the database. After some research and with the help of @developernotes reply in the discussion forum, I was finally able to get the App Crashing Error from Mi 4i mobile - It said -

net.sqlcipher.database.SQLiteException: attempt to write a readonly database: DELETE failed setting locale

The Mi 4i device runs Android 5.0.2 After learning this.. I tried to reciprocate the same in x86_64 emulators of version 5.0.1 and 5.1.1. Luckily no error is thrown in 5.1.1 and app works absolutely fine for me.

Unfortunately in Android 5.0.1 x86_64 emulator following error is displayed -

05-11 19:36:46.931 2995-2995/? D/QuestionBankDBHelper: Count Query = SELECT COUNT(*) as count FROM qbank 05-11 19:36:46.935 2995-2995/? I/Database: sqlite returned: error code = 28, msg = file renamed while open: /storage/sdcard/Download/mydata.db 05-11 19:36:47.071 2995-2995/? I/Database: sqlite returned: error code = 1032, msg = statement aborts at 3: [PRAGMA user_version = 1] 05-11 19:36:47.071 2995-2995/? E/Database: Failure 8 (attempt to write a readonly database) on 0xecf5f208 when executing 'PRAGMA user_version = 1' 05-11 19:36:47.072 2995-2995/? I/Database: sqlite returned: error code = 28, msg = file renamed while open: /storage/sdcard/Download/mydata.db

The same database is working fine in 4.2.2, 5.1.1, 6.0.1 etc.

This error appears to be slightly different than what is thrown in Mi 4i phone. But, one thing is sure.. there is some bug that is interfering with SQLCipher to work in Android 5.0.x

How I tested - I have sqlcipher encrypted database, which is stored in External Storage. The errors are thrown, when being trying to access this database.

kibergus commented 8 years ago

Hi! We've encountered the same bug too. atultiwari, thank you very much for finding emulator in which the problem can be easily reproduced. That helped a lot. The error is actually in android headers. For android 19 they have:

android-ndk-r10d/platforms/android-19/arch-x86/usr/include/sys/types.h:typedef __kernel_ino_t       ino_t;
android-ndk-r10d/platforms/android-19/arch-x86/usr/include/asm/posix_types_32.h:typedef unsigned long __kernel_ino_t;

but

struct stat {
...
    unsigned long long  st_ino;
};

So ino_t is 4 bytes and stat.st_ino is 8 bytes wide. Sqlite trims inode number to 4 bytes when stores it and then compares with 8 byte wide inode number in fileHasMoved.

It seems, that in android 21 headers have been fixed:

android-ndk-r10d/platforms/android-21/arch-x86/usr/include/sys/types.h:typedef __kernel_ino_t __ino_t;
android-ndk-r10d/platforms/android-21/arch-x86/usr/include/sys/types.h:typedef __ino_t ino_t;
android-ndk-r10d/platforms/android-21/arch-x86/usr/include/asm-generic/posix_types.h:typedef __kernel_ulong_t __kernel_ino_t;
android-ndk-r10d/platforms/android-21/arch-x86/usr/include/asm/posix_types_x32.h:typedef unsigned long long __kernel_ulong_t;

So currently I see two solutions: good one is to use headers for android 21. But if that's inappropriate, then the problem can be solved by a hack in sqlite by explicitly converting stat.st_ino to (ino_t) in sqlite source.

brodycj commented 8 years ago

+1 for using the android-21 headers

atultiwari commented 8 years ago

@kibergus thank you for finding out the root cause of this issue. Being a medico, it is hard to understand it completely, but I did understand some basics about it. I am curious, if somehow, I can make SQLCipher work with Android 5.0 (as suggested by you - using the android 21 headers), or will I have to wait for developers of SQLCipher to release some kind of patch? Thanks.

YuriZheng commented 8 years ago

I get this issue on my phone, Android 5.0, I see @kibergus's answer, but i don't know how to deal with it,For using the android-21 headers ? How to do it?