SQLiteCantOpenDatabaseException =>未知错误(代码14):无法打开数据库(Android 6.0)

时间:2015-10-14 09:07:07

标签: android sqlite android-sqlite root

以下是成千上万的设备,但最近我得到了以下错误,两次,都来自android 6.0,所以它可能与新的Android版本有关:

RootUtils.copyDatabase(path, pathApp);
if (new File(pathApp).exists())
{
    L.d(this, "Database copied!"); // <= this is called, so copying file succeeds!!!

    SQLiteDatabase db = SQLiteDatabase.openDatabase(pathApp, null, SQLiteDatabase.OPEN_READONLY);
    final Cursor cursor = db.rawQuery("select * from contacts", new String[0]); // <= this line throws the exception
    cursor.moveToFirst();
    ....
}

日志/异常

c.m.s.utils.RootUtils   [RootUtils-91]  copyDatabase: true
c.m.s.networks.utils.Util   [FUtil-105] Database copied!
c.m.s.networks.utils.Util   [FUtil-185] unknown error (code 14): Could not open database
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
    at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:207)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:191)
    at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
    at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806)
    at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791)
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
    ...

我的复制功能正在关注

public final static boolean copyDatabase(String pathSource, String pathTarget) throws IOException, InterruptedException, TimeoutException, RootDeniedException
{
    Shell shell = RootTools.getShell(true);
    Command command = new Command(0,
            "su\n",
            "rm " + pathTarget + "\n",
            "cat " + pathSource + " > " + pathTarget + "\n",
            "chown root.root " + pathTarget + "\n",
            "chmod 777 " + pathTarget + "\n");
    command = shell.add(command);
    int exitCode = command.getExitCode();
    while (!command.isFinished()) {
        Thread.sleep(50);
    }
    shell.close();
    boolean success = exitCode == -1 && command.isFinished();
    L.d(RootUtils.class, "copyDatabase: " + success);
    return success;
}

编辑:我的新复制功能甚至将所有者/群组设置为我的应用程序流程 - 只收到一个反馈,但似乎无法解决问题

public final static boolean copyDatabase(String ownAppDatabase, String pathSource, String pathTarget) throws IOException, InterruptedException, TimeoutException, RootDeniedException
{
    Shell shell = RootTools.getShell(true);

    boolean getRealUser = true;
    String owner = null;
    String group = null;
    if (getRealUser)
    {
        final  StringHolder lsResult = new StringHolder("");
        Command lsCommand = new Command(0,
                "su\n",
                "ls -ld " + ownAppDatabase + "\n")
        {
            public void commandOutput(int id, String line) {
                super.commandOutput(id, line);
                lsResult.set(line);
            }

        };
        lsCommand = shell.add(lsCommand);
        int lsExitCode = lsCommand.getExitCode();
        while (!lsCommand.isFinished()) {
            Thread.sleep(50);
        }

        L.d(RootUtils.class, "ls exit code: " + lsExitCode);
        L.d(RootUtils.class, "ls result: " + lsResult.get());

        String[] parts = lsResult.get().split("\\s+");
        if (parts.length > 3)
        {
            owner = parts[1];
            group = parts[2];
        }
    }

    if (owner == null || group == null)
    {
        L.d(RootUtils.class, "owner or group is NULL!");
        getRealUser = false;
    }
    else
        L.d(RootUtils.class, "owner=" + owner + " | group=" + group);

    Command command = new Command(0,
            "su\n",
            "rm " + pathTarget + "\n",
            "cat " + pathSource + " > " + pathTarget + "\n",
            "chown " + (getRealUser ? (owner + "." + group + " ") : "chown root.root ") + pathTarget + "\n",
            "chmod 777 " + pathTarget + "\n");
    command = shell.add(command);
    int exitCode = command.getExitCode();
    while (!command.isFinished()) {
        Thread.sleep(50);
    }
    shell.close();
    boolean success = exitCode == -1 && command.isFinished();
    L.d(RootUtils.class, "copyDatabase: " + success);
    return success;
}

3 个答案:

答案 0 :(得分:0)

在尝试打开存储在内部存储上的SQLite数据库时,在更新到Android 6.0后,我遇到了同样的问题。

这是由Marshmallow的新权限模型引起的。

作为一种解决方法,我必须访问我的应用程序&#34;应用信息&#34;系统设置页面,并授予存储访问权限。

答案 1 :(得分:0)

以下是我发现的唯一解决方案(它应该适用于所有旧设备):

转储数据库!

复制数据库不起作用,也读取数据库。可能是因为数据库是由另一个进程打开的。但是转储数据库是有效的。您也可以转储单个表,这是一个适用于所有设备的示例:

String dump = pathSQLite3 + " " + pathDB + " \".dump '" + tablename + "'\"\n";

唯一的缺点是,您必须将sqlite可执行文件添加到您的应用程序中,您必须找出目标设备具有哪种体系结构,以便您知道可以使用哪个sqlite可执行文件...

但至少这种方法很好。

答案 2 :(得分:0)

你几乎就在那里 - 在chmod之后也需要这样做:&#34; chcon u:object_r:app_data_file:s0:c512,c768&#34;。