Sqlite3 result error 14 SQLITE_CANTOPEN on Android

I’ve seen a few threads on this but could not find my exact issue.

I use SQLite3 for the savegame of my games. My code works on 99.9% of the devices (Millions of them) but I receive logs from time to time where a user get a SQLITE_CANTOPEN. So, the user is never able to save its progress. I use this basic code to create the DB:

std::string dbPath = cocos2d::FileUtils::getInstance()->getWritablePath() + "save.db";

result = sqlite3_open(dbPath.c_str(), &pdb);

And I get a result SQLITE_CANTOPEN. I do have the write permission in the AndroidManifest “android.permission.WRITE_EXTERNAL_STORAGE” and this never happen on iOS, only small percentage of user on Android.

I’ve read that on API 23+ you need to ask runtime permission or something, but it seems only related to external permission outside your sandbox which is not the case here and if it was the case I would get a huge more amount of errors and complains.

Any idea why this would happen? Anyone else has the same issue?

Thanks

Is there any chance that the error is coming from devices that may be out of space? Do you do a check for the free space before attempting to create the DB?

Also, have you checked if the errors are coming from users running your app in an emulator instead of a real device?

It is not out of space because I do valid it. When the user is out of space, it is the error 13 SQLITE_FULL that I receive. And no they are not on emulator It happens on different devices, but a lot of them are Samsung Galaxy series.

Doing a net search reveals many reports of SQLite issues that appear only on the Samsung Galaxy devices, and they seem to be for several different reasons, such as the DB being locked when you attempt to open it. I didn’t see a reference to which error it throws in that case, but it could be something to look into.

Are you using your own version of SQLite, or the one that is included with cocos2d-x?

I did not know cocos2d-x came with SQLite. I downloaded the sqlite3.c and .h from the net which seems to be a reference in term of stability and reliability. But I guess if you do not have access to the storage there is not much it can do about it…

Oh I was only going to suggest you try your own version of SQLite in case you were using the bundled version. I personally do the same, using a newer and slightly customized version of sqlite.c and sqlite.h than the one included with cocos2d-x.

Do you use any threads for the sqlite connections, and would there ever be more than one connection at once to the DB? Other than that, I’m out of ideas.

Does it eventually succeed when it re-tries the DB open?

There is only 1 connection at a time and it is on the main thread. When I do get the error 14, the user will get it forever… or at least for quite a while until he quits and do something regarding permission if this is possible… but most of the time, they just stop playing and I have no way of figuring out how to fix it :frowning:

Do you know if the DB works at any point prior to the error occurring?

Assuming this isn’t a permission issue, let’s say this happens:

  1. User opens app, saves state (it works here)
  2. User opens app another time, saves, but something goes wrong during the save, so file is still locked
  3. User opens app, tries to save, but file is still locked. This will go on forever until either the lock is removed or the existing DB is deleted (along with any other files related to the lock)

If that is the case, then given you’re saving a DB, check if any files related to the DB already exist, and if so, try to delete them before attempting a new save (if you don’t need the data in the DB). You can limit the delete action to when an error occurs, and retry the DB open after that.

Again, this is all assuming it is not a permission issue, because if it is, then you’ll need to take care of that with a popup requesting the permission (on Android API 23+).

Thanks. I currently do not have a way to know if it worked at some point prior to the issue. But I could take a look. I have a feeling that this is not the case though. I had the exact same behavior before when I was only using standard file with fread, fwrite and fopen. This is why I decided to move to DB thinking it would be better, but I get the same kind of problem.

As for the permission, why would it be required for only a small percentage or people? Is there a settings somewhere on these device to “always prevent save unless I get a pop up to allow it” and most people this setting is off by default and so it is fine for them?

I read that this was required only if you want to access stuff outside of your sandbox which should not be the case for the “getWritablePath” I believe.

Thanks for your help

The first issue is figuring out precisely why this is happening. The assumption is that the app is writing to the internal storage, but is that always the case? Is there any setting on those Galaxy devices that allows users to store your app data on external storage?

How about this, on an error, perhaps you can do a check for where the app is installed (internal or external storage), and if it has the required permission to access that location, and report those to whichever app analytics service you’re using. Any other things you can think of that you would want to know should be added to the analytics (Android OS version, space available on internal and external storage etc etc). At least then you would have more info about what is going on. No need to add a request permissions popup just yet until you know for sure if it’s the cause of the problem.

EDIT: Are you able to get your hands on at least one of the device models that is reporting the problem? It may be worthwhile investing in one.

Thanks for your suggestions. I will dig out a little bit more. I just got a Samsung Galaxy A21. It is hard to know for sure if this one had a problem, but I could not reproduce it on it yet.