SQLiteException: not an error (code 0): Could not open the database in read/write mode

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

0x01. 崩溃信息

---android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.
android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:709)
android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:702)
//...
android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
//...
android.app.Activity.performStart(Activity.java:5241)
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2268)
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2344)
android.app.ActivityThread.access$800(ActivityThread.java:141)
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
//...
android.os.Handler.dispatchMessage(Handler.java:98)
android.os.Looper.loop(Looper.java:136)
android.app.ActivityThread.main(ActivityThread.java:5112)
java.lang.reflect.Method.invokeNative(Native Method)
java.lang.reflect.Method.invoke(Method.java:515)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
dalvik.system.NativeStart.main(Native Method)

0x02. native方法nativeOpen

➜  android-7.0.0_r1 find . -name android_database_SQLiteConnection.cpp
./frameworks/base/core/jni/android_database_SQLiteConnection.cpp

static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
        jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
    int sqliteFlags;
    if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
        sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
        sqliteFlags = SQLITE_OPEN_READONLY;
    } else {
        sqliteFlags = SQLITE_OPEN_READWRITE;
    }

    const char* pathChars = env->GetStringUTFChars(pathStr, NULL);
    String8 path(pathChars);
    env->ReleaseStringUTFChars(pathStr, pathChars);

    const char* labelChars = env->GetStringUTFChars(labelStr, NULL);
    String8 label(labelChars);
    env->ReleaseStringUTFChars(labelStr, labelChars);

    sqlite3* db;
    int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
    if (err != SQLITE_OK) {
        throw_sqlite3_exception_errcode(env, err, "Could not open database");
        return 0;
    }

    // Check that the database is really read/write when that is what we asked for.
    if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {//关键在sqlite3_db_readonly方法.
        throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");//错误信息
        sqlite3_close(db);
        return 0;
    }
    //...

sqlite3_db_readonly这个是sqlite3的库接口.

    int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);

The sqlite3_db_readonly(D,N) interface returns 1 if the database N of connection D is read-only, 0 if it is read/write, or -1 if N is not the name of a database on connection D.

搜索这个接口的实现

➜  android-7.0.0_r1 grep -rn 'sqlite3_db_readonly'*
external/sqlite/dist/orig/sqlite3.c:134609:SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
//...
external/sqlite/dist/sqlite3.c:134627:SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
//...

接口实现:

/*
** Return 1 if database is read-only or 0 if read/write.  Return -1 if
** no such database exists.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
  Btree *pBt;
#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) ){
    (void)SQLITE_MISUSE_BKPT;
    return -1;
  }
#endif
  pBt = sqlite3DbNameToBtree(db, zDbName);
  return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
}

0x03. 参考信息

https://stackoverflow.com/questions/21673898/could-not-open-the-database-in-read-write-mode#21674485

从源码和网络上的信息分析来看,这个问题比较诡异:
- 0x01. 数据库属性是只读
这个基本上可以被排除,因为创建数据库的时候已经设置了是读写属性.(系统权限导致?)

  • 0x02. 数据库不存在
    创建文件失败,数据库文件不存在?

0x04. 目前由于线下无法复现该故障

所以根据上面的结论猜测这两种可能性: 用户手机权限导致/创建数据库文件失败导致文件不存在.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值