-Optimize file permission requests, simplify backup and restore logic, and directly process user-selected files
- This will fix an issue where some devices were unable to back up their app lists
This commit is contained in:
@@ -3,10 +3,9 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
tools:ignore="ScopedStorage" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
|
||||||
tools:ignore="ScopedStorage" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".KernelSUApplication"
|
android:name=".KernelSUApplication"
|
||||||
@@ -19,6 +18,7 @@
|
|||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.KernelSU"
|
android:theme="@style/Theme.KernelSU"
|
||||||
|
android:requestLegacyExternalStorage="true"
|
||||||
tools:targetApi="34">
|
tools:targetApi="34">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.MainActivity"
|
android:name=".ui.MainActivity"
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import shirkneko.zako.sukisu.R
|
import shirkneko.zako.sukisu.R
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@@ -45,30 +44,25 @@ object ModuleModify {
|
|||||||
try {
|
try {
|
||||||
val busyboxPath = "/data/adb/ksu/bin/busybox"
|
val busyboxPath = "/data/adb/ksu/bin/busybox"
|
||||||
val moduleDir = "/data/adb/modules"
|
val moduleDir = "/data/adb/modules"
|
||||||
val tempFile = File(context.cacheDir, "backup_${System.currentTimeMillis()}.tar.gz")
|
|
||||||
val tempPath = tempFile.absolutePath
|
|
||||||
|
|
||||||
|
// 直接将tar输出重定向到用户选择的文件
|
||||||
val command = """
|
val command = """
|
||||||
cd "$moduleDir" &&
|
cd "$moduleDir" &&
|
||||||
$busyboxPath tar -czvf "$tempPath" ./*
|
$busyboxPath tar -cz ./* > /proc/self/fd/1
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", command))
|
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", command))
|
||||||
process.waitFor()
|
|
||||||
|
// 直接将tar输出写入到用户选择的文件
|
||||||
|
context.contentResolver.openOutputStream(uri)?.use { output ->
|
||||||
|
process.inputStream.copyTo(output)
|
||||||
|
}
|
||||||
|
|
||||||
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
||||||
if (process.exitValue() != 0) {
|
if (process.exitValue() != 0) {
|
||||||
throw IOException(context.getString(R.string.command_execution_failed, error))
|
throw IOException(context.getString(R.string.command_execution_failed, error))
|
||||||
}
|
}
|
||||||
|
|
||||||
context.contentResolver.openOutputStream(uri)?.use { output ->
|
|
||||||
tempFile.inputStream().use { input ->
|
|
||||||
input.copyTo(output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tempFile.delete()
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
snackBarHost.showSnackbar(
|
snackBarHost.showSnackbar(
|
||||||
context.getString(R.string.backup_success),
|
context.getString(R.string.backup_success),
|
||||||
@@ -96,23 +90,15 @@ object ModuleModify {
|
|||||||
try {
|
try {
|
||||||
val busyboxPath = "/data/adb/ksu/bin/busybox"
|
val busyboxPath = "/data/adb/ksu/bin/busybox"
|
||||||
val moduleDir = "/data/adb/modules"
|
val moduleDir = "/data/adb/modules"
|
||||||
val tempFile = File(context.cacheDir, "temp_restore.tar.gz").apply {
|
|
||||||
if (exists()) delete()
|
// 直接从用户选择的文件读取并解压
|
||||||
}
|
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", "$busyboxPath tar -xz -C $moduleDir"))
|
||||||
|
|
||||||
context.contentResolver.openInputStream(uri)?.use { input ->
|
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||||
tempFile.outputStream().use { output ->
|
input.copyTo(process.outputStream)
|
||||||
input.copyTo(output)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
process.outputStream.close()
|
||||||
|
|
||||||
val command = """
|
|
||||||
cd "$moduleDir" &&
|
|
||||||
rm -rf * &&
|
|
||||||
$busyboxPath tar -xzvf "${tempFile.absolutePath}"
|
|
||||||
""".trimIndent()
|
|
||||||
|
|
||||||
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", command))
|
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
|
|
||||||
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
||||||
@@ -120,8 +106,6 @@ object ModuleModify {
|
|||||||
throw IOException(context.getString(R.string.command_execution_failed, error))
|
throw IOException(context.getString(R.string.command_execution_failed, error))
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFile.delete()
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val snackbarResult = snackBarHost.showSnackbar(
|
val snackbarResult = snackBarHost.showSnackbar(
|
||||||
message = context.getString(R.string.restore_success),
|
message = context.getString(R.string.restore_success),
|
||||||
@@ -166,25 +150,19 @@ object ModuleModify {
|
|||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val allowlistPath = "/data/adb/ksu/.allowlist"
|
val allowlistPath = "/data/adb/ksu/.allowlist"
|
||||||
val tempFile = File(context.cacheDir, "allowlist_backup_${System.currentTimeMillis()}")
|
|
||||||
|
|
||||||
val command = "cp $allowlistPath ${tempFile.absolutePath}"
|
// 直接复制文件到用户选择的位置
|
||||||
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", command))
|
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", "cat $allowlistPath"))
|
||||||
process.waitFor()
|
|
||||||
|
context.contentResolver.openOutputStream(uri)?.use { output ->
|
||||||
|
process.inputStream.copyTo(output)
|
||||||
|
}
|
||||||
|
|
||||||
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
||||||
if (process.exitValue() != 0) {
|
if (process.exitValue() != 0) {
|
||||||
throw IOException(context.getString(R.string.command_execution_failed, error))
|
throw IOException(context.getString(R.string.command_execution_failed, error))
|
||||||
}
|
}
|
||||||
|
|
||||||
context.contentResolver.openOutputStream(uri)?.use { output ->
|
|
||||||
tempFile.inputStream().use { input ->
|
|
||||||
input.copyTo(output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tempFile.delete()
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
snackBarHost.showSnackbar(
|
snackBarHost.showSnackbar(
|
||||||
context.getString(R.string.allowlist_backup_success),
|
context.getString(R.string.allowlist_backup_success),
|
||||||
@@ -211,18 +189,15 @@ object ModuleModify {
|
|||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val allowlistPath = "/data/adb/ksu/.allowlist"
|
val allowlistPath = "/data/adb/ksu/.allowlist"
|
||||||
val tempFile = File(context.cacheDir, "allowlist_restore_temp").apply {
|
|
||||||
if (exists()) delete()
|
// 直接从用户选择的文件读取并写入到目标位置
|
||||||
}
|
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", "cat > $allowlistPath"))
|
||||||
|
|
||||||
context.contentResolver.openInputStream(uri)?.use { input ->
|
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||||
tempFile.outputStream().use { output ->
|
input.copyTo(process.outputStream)
|
||||||
input.copyTo(output)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
process.outputStream.close()
|
||||||
|
|
||||||
val command = "cp ${tempFile.absolutePath} $allowlistPath"
|
|
||||||
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", command))
|
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
|
|
||||||
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
val error = BufferedReader(InputStreamReader(process.errorStream)).readText()
|
||||||
@@ -230,8 +205,6 @@ object ModuleModify {
|
|||||||
throw IOException(context.getString(R.string.command_execution_failed, error))
|
throw IOException(context.getString(R.string.command_execution_failed, error))
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFile.delete()
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
snackBarHost.showSnackbar(
|
snackBarHost.showSnackbar(
|
||||||
context.getString(R.string.allowlist_restore_success),
|
context.getString(R.string.allowlist_restore_success),
|
||||||
@@ -350,4 +323,8 @@ object ModuleModify {
|
|||||||
type = "application/octet-stream"
|
type = "application/octet-stream"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun reboot() {
|
||||||
|
Runtime.getRuntime().exec(arrayOf("su", "-c", "reboot"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user