将数据库从一个应用程序复制到另一个应用程序
Copy database from one app to another app
我正在尝试将数据库从 Android 应用程序复制到另一个应用程序。换句话说,我想将位于以下路径 /data/data/com.other.package/databases/filename.db
中的文件复制到 /data/data/com.my.app/databases/new_file.db
.
到目前为止,我正在使用 root 命令 执行此过程,然后尝试 修复权限,但我做不到读取复制的文件。这是我得到的 logcat 错误:
type=1400 audit(0.0:6364): avc: denied { open } for name="database.db" dev="mmcblk0p28" ino=171293 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:app_data_file:s0 tclass=file permissive=0
os_unix.c:31278: (13) open(/data/user/0/com.testapp/databases/database.db)
这是我想出的代码:
// Define in and out filepaths
String DB_INPUT = "/data/data/com.package.name/databases/database.db";
String DB_OUTPUT = activity.getDatabasePath("database.db").getPath();
try {
// Request superuser permissions
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream suOutputStream = new DataOutputStream(suProcess.getOutputStream());
// Copy database
suOutputStream.writeBytes("cat " + DB_INPUT + " > " + DB_OUTPUT + "\n");
// Fix permissions
int appUID = getApplication().getApplicationInfo().uid;
suOutputStream.writeBytes("chmod 600 " + DB_OUTPUT + "\n"); // rw- --- ---
suOutputStream.writeBytes("chown " + appUID + "." + appUID + " " + DB_OUTPUT + "\n");
suOutputStream.writeBytes("exit\n");
suProcess.waitFor();
suOutputStream.close();
// Test
SQLiteDatabase.openDatabase(DB_OUTPUT, null, SQLiteDatabase.OPEN_READWRITE);
} catch(Exception e) {
Log.e(LOGTAG, "Something went terrible wrong: " + e.getMessage());
}
最后但并非最不重要的一点是,一些上下文可以帮助您找到答案:
- 我运行这个代码在真正的 root 设备上
- 该数据库是一个有效的 SQLite 文件,已使用 SQLite 编辑器针对 Android
进行了测试
- 正在将文件正确复制到输出路径(校验和匹配)
- 权限、所有者和组正在更改为正确的,使用终端仿真器和命令
ls [path] -l
进行了测试
- 无法更改我要从中复制数据库的应用程序的源代码
我找到了一个非常简单的技巧来避免重写所有者、组和权限,方法是创建一个具有相同名称的空数据库,然后覆盖它。这是最终代码的样子:
// Define in and out filepaths
String DB_INPUT = "/data/data/com.package.name/databases/database.db";
String DB_OUTPUT = activity.getDatabasePath("database.db").getPath();
// Create empty database to grant permissions
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_OUTPUT, null);
db.close();
try {
// Request superuser permissions
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream suOutputStream = new DataOutputStream(suProcess.getOutputStream());
// Copy database
suOutputStream.writeBytes("cat " + DB_INPUT + " > " + DB_OUTPUT + "\n");
// Close terminal
suOutputStream.writeBytes("exit\n");
suProcess.waitFor();
suOutputStream.close();
} catch(Exception e) {
Log.e(LOGTAG, "Something went terrible wrong: " + e.getMessage());
}
您与原始代码非常接近,但您的问题是 avc: denied { open }
中的 SELinux 错误
当您复制数据库文件时,您需要在终端中使用类似 chcon u:object_r:app_data_file:s0:c512,c768 database.db
的 SSH 命令更改 SELinux 上下文。
在您的代码上下文中,它类似于
suOutputStream.writeBytes("chcon u:object_r:app_data_file:s0:c512,c768 " + DB_OUTPUT + "\n");
我正在尝试将数据库从 Android 应用程序复制到另一个应用程序。换句话说,我想将位于以下路径 /data/data/com.other.package/databases/filename.db
中的文件复制到 /data/data/com.my.app/databases/new_file.db
.
到目前为止,我正在使用 root 命令 执行此过程,然后尝试 修复权限,但我做不到读取复制的文件。这是我得到的 logcat 错误:
type=1400 audit(0.0:6364): avc: denied { open } for name="database.db" dev="mmcblk0p28" ino=171293 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:app_data_file:s0 tclass=file permissive=0
os_unix.c:31278: (13) open(/data/user/0/com.testapp/databases/database.db)
这是我想出的代码:
// Define in and out filepaths
String DB_INPUT = "/data/data/com.package.name/databases/database.db";
String DB_OUTPUT = activity.getDatabasePath("database.db").getPath();
try {
// Request superuser permissions
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream suOutputStream = new DataOutputStream(suProcess.getOutputStream());
// Copy database
suOutputStream.writeBytes("cat " + DB_INPUT + " > " + DB_OUTPUT + "\n");
// Fix permissions
int appUID = getApplication().getApplicationInfo().uid;
suOutputStream.writeBytes("chmod 600 " + DB_OUTPUT + "\n"); // rw- --- ---
suOutputStream.writeBytes("chown " + appUID + "." + appUID + " " + DB_OUTPUT + "\n");
suOutputStream.writeBytes("exit\n");
suProcess.waitFor();
suOutputStream.close();
// Test
SQLiteDatabase.openDatabase(DB_OUTPUT, null, SQLiteDatabase.OPEN_READWRITE);
} catch(Exception e) {
Log.e(LOGTAG, "Something went terrible wrong: " + e.getMessage());
}
最后但并非最不重要的一点是,一些上下文可以帮助您找到答案:
- 我运行这个代码在真正的 root 设备上
- 该数据库是一个有效的 SQLite 文件,已使用 SQLite 编辑器针对 Android 进行了测试
- 正在将文件正确复制到输出路径(校验和匹配)
- 权限、所有者和组正在更改为正确的,使用终端仿真器和命令
ls [path] -l
进行了测试
- 无法更改我要从中复制数据库的应用程序的源代码
我找到了一个非常简单的技巧来避免重写所有者、组和权限,方法是创建一个具有相同名称的空数据库,然后覆盖它。这是最终代码的样子:
// Define in and out filepaths
String DB_INPUT = "/data/data/com.package.name/databases/database.db";
String DB_OUTPUT = activity.getDatabasePath("database.db").getPath();
// Create empty database to grant permissions
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_OUTPUT, null);
db.close();
try {
// Request superuser permissions
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream suOutputStream = new DataOutputStream(suProcess.getOutputStream());
// Copy database
suOutputStream.writeBytes("cat " + DB_INPUT + " > " + DB_OUTPUT + "\n");
// Close terminal
suOutputStream.writeBytes("exit\n");
suProcess.waitFor();
suOutputStream.close();
} catch(Exception e) {
Log.e(LOGTAG, "Something went terrible wrong: " + e.getMessage());
}
您与原始代码非常接近,但您的问题是 avc: denied { open }
当您复制数据库文件时,您需要在终端中使用类似 chcon u:object_r:app_data_file:s0:c512,c768 database.db
的 SSH 命令更改 SELinux 上下文。
在您的代码上下文中,它类似于
suOutputStream.writeBytes("chcon u:object_r:app_data_file:s0:c512,c768 " + DB_OUTPUT + "\n");