Android5.0上运行SQLCipher库出现readonly database的解决方案

这是第一次在上写文章,没想到写的就是纯技术类的文章,最近被这个小清新风格的网站吸引住了,也想换换风格,平时一般都是逛逛技术类的博客,但是发现这个网站,特别是被灌了一些鸡汤后,决定以后迁移到这个网站了,估计写的话也是一些关于技术类的文章把,谁让咱是一名不折不扣的攻城狮呢。

好的,闲话不多说,下面进入主题。

公司的一些产品中采用了 SQLCipher 这个库来来对数据库中的数据进行加密,但是在Android5.0版本上SQLCipher会出现readonly database错误:

net.sqlcipher.database.SQLiteException: attempt to write a readonly database

一直以为这是SQLCipher的问题,在Github上也有人提出过这个问题,但是这些方案没能解决我遇到的问题。

https://github.com/sqlcipher/android-database-sqlcipher/issues/161

这个问题只有在Android5.0上才会出现,但是目前采用5.0版本的机型应该不会很多(很多机型要么4.4要么就直接 >5.0)而且采用SQLCipher加密库的App也不是很多,所以这个问题出现的几率并不高,但是谁让我们的用户偏偏就用了Android5.0的机型呢,所以不得不去啃这块硬骨头(攻城狮嘛,攻不下城怎么能叫攻城狮呢)。

经过不懈的努力后,终于找到了解决方案:

Workaround for Nexus 9 SQLite file write operations on external dirs?

其实这并不是SQLCipher的问题,而是Android5.0的一个BUG,Google在Android的下一个版本中进行了修复,所以这个问题只有在Android5.0上才会出现。

国外大神也给出了非官方的解决方案:

https://android-review.googlesource.com/#/c/115351/

Store inodes in unsigned long long

In 32 bit ABIs, ino_t is a 32 bit type, while the st_ino field

in struct stat is 64 bits wide in both 32 and 64 bit processes.

This means that struct stat can expose inode numbers that are

truncated when stored in an ino_t.

The SDCard fuse daemon (/system/bin/sdcard) uses raw pointer

values as inode numbers, so on 64 bit devices, we're very likely

to observe inodes that need > 32 bits to represent.

The fileHasMoved function in sqlite compares the stored

inode value with a new one from stat, and when the stored

value is truncated, this check will falsely indicate that

the file has been moved. When the fileHasMoved function

triggers, other functions start returning errors indicating

that the database is in read-only mode.

NOTE: Bionic differs from glibc in that struct stat's st_ino

is *always* 64 bits wide, and not the same width as ino_t.

如果要修复该BUG的话,肯定得自己下载SQLCipher源码自己进行编译了,源码是C编写的,所以需要下载NDK才能进行编译。

NDK环境的搭建这里就不再叙述了,网上有很多的教程。

NDK环境搭建好之后,可以根据官方的教程进行编译:

https://www.zetetic.net/sqlcipher/sqlcipher-for-android/

当然在编译之前需要对源码进行修改,打开

https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c

可以看到 sqlite.c 文件需要修改的地方:

25322    ino_t ino; /* Inode number */

修改为:

25322    #ifdef ANDROID

25323    // Bionic's struct stat has a 64 bit st_ino on both 32 and

25324    // 64 bit architectures. ino_t remains 32 bits wide on 32 bit

25325    // architectures and can lead to inode truncation.

25326    unsigned long long ino; /* Inode number */

25327    #else

25328    ino_t ino; /* Inode number */

25329    #endif

修改完成后保存文件,然后按照官方教程进行编译,编译完成后得到的so文件和jar文件即可用在Android5.0版本上。

----

给需要的朋友分享一个我自己编译的sqlcipher库http://pan.baidu.com/s/1i47SQSd

你可能感兴趣的:(Android5.0上运行SQLCipher库出现readonly database的解决方案)