mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-10 21:26:18 +00:00
feat: Improve root installation
This commit is contained in:
@@ -54,7 +54,11 @@ class RootInstaller(
|
|||||||
await()
|
await()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun execute(vararg commands: String) = getShell().newJob().add(*commands).exec()
|
suspend fun execute(vararg commands: String): Shell.Result {
|
||||||
|
val stdout = mutableListOf<String>()
|
||||||
|
val stderr = mutableListOf<String>()
|
||||||
|
return getShell().newJob().add(*commands).to(stdout, stderr).exec()
|
||||||
|
}
|
||||||
|
|
||||||
fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false
|
fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false
|
||||||
|
|
||||||
@@ -108,20 +112,15 @@ class RootInstaller(
|
|||||||
unmount(packageName)
|
unmount(packageName)
|
||||||
|
|
||||||
stockAPK?.let { stockApp ->
|
stockAPK?.let { stockApp ->
|
||||||
pm.getPackageInfo(packageName)?.let { packageInfo ->
|
// TODO: get user id programmatically
|
||||||
// TODO: get user id programmatically
|
execute("pm uninstall -k --user 0 $packageName")
|
||||||
if (pm.getVersionCode(packageInfo) <= pm.getVersionCode(
|
|
||||||
pm.getPackageInfo(patchedAPK)
|
|
||||||
?: error("Failed to get package info for patched app")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
execute("pm uninstall -k --user 0 $packageName").assertSuccess("Failed to uninstall stock app")
|
|
||||||
}
|
|
||||||
|
|
||||||
execute("pm install \"${stockApp.absolutePath}\"").assertSuccess("Failed to install stock app")
|
execute("pm install -r -d --user 0 \"${stockApp.absolutePath}\"")
|
||||||
|
.assertSuccess("Failed to install stock app")
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteFS.getFile(modulePath).mkdir()
|
remoteFS.getFile(modulePath).mkdirs()
|
||||||
|
.also { if (!it) throw Exception("Failed to create module directory") }
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
"service.sh",
|
"service.sh",
|
||||||
@@ -142,7 +141,6 @@ class RootInstaller(
|
|||||||
}
|
}
|
||||||
|
|
||||||
"$modulePath/$packageName.apk".let { apkPath ->
|
"$modulePath/$packageName.apk".let { apkPath ->
|
||||||
|
|
||||||
remoteFS.getFile(patchedAPK.absolutePath)
|
remoteFS.getFile(patchedAPK.absolutePath)
|
||||||
.also { if (!it.exists()) throw Exception("File doesn't exist") }
|
.also { if (!it.exists()) throw Exception("File doesn't exist") }
|
||||||
.newInputStream().use { inputStream ->
|
.newInputStream().use { inputStream ->
|
||||||
@@ -173,9 +171,43 @@ class RootInstaller(
|
|||||||
const val modulesPath = "/data/adb/modules"
|
const val modulesPath = "/data/adb/modules"
|
||||||
|
|
||||||
private fun Shell.Result.assertSuccess(errorMessage: String) {
|
private fun Shell.Result.assertSuccess(errorMessage: String) {
|
||||||
if (!isSuccess) throw Exception(errorMessage)
|
if (!isSuccess) {
|
||||||
|
throw ShellCommandException(
|
||||||
|
errorMessage,
|
||||||
|
code,
|
||||||
|
out,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShellCommandException(
|
||||||
|
val userMessage: String,
|
||||||
|
val exitCode: Int,
|
||||||
|
val stdout: List<String>,
|
||||||
|
val stderr: List<String>
|
||||||
|
) : Exception(format(userMessage, exitCode, stdout, stderr)) {
|
||||||
|
companion object {
|
||||||
|
private fun format(message: String, exitCode: Int, stdout: List<String>, stderr: List<String>): String =
|
||||||
|
buildString {
|
||||||
|
appendLine(message)
|
||||||
|
appendLine("Exit code: $exitCode")
|
||||||
|
|
||||||
|
val output = stdout.filter { it.isNotBlank() }
|
||||||
|
val errors = stderr.filter { it.isNotBlank() }
|
||||||
|
|
||||||
|
if (output.isNotEmpty()) {
|
||||||
|
appendLine("stdout:")
|
||||||
|
output.forEach(::appendLine)
|
||||||
|
}
|
||||||
|
if (errors.isNotEmpty()) {
|
||||||
|
appendLine("stderr:")
|
||||||
|
errors.forEach(::appendLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RootServiceException : Exception("Root not available")
|
class RootServiceException : Exception("Root not available")
|
||||||
@@ -377,22 +377,22 @@ class PatcherViewModel(
|
|||||||
try {
|
try {
|
||||||
isInstalling = true
|
isInstalling = true
|
||||||
|
|
||||||
val currentPackageInfo = pm.getPackageInfo(outputFile)
|
|
||||||
?: throw Exception("Failed to load application info")
|
|
||||||
|
|
||||||
// If the app is currently installed
|
|
||||||
val existingPackageInfo = pm.getPackageInfo(currentPackageInfo.packageName)
|
|
||||||
if (existingPackageInfo != null) {
|
|
||||||
// Check if the app version is less than the installed version
|
|
||||||
if (pm.getVersionCode(currentPackageInfo) < pm.getVersionCode(existingPackageInfo)) {
|
|
||||||
// Exit if the selected app version is less than the installed version
|
|
||||||
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_CONFLICT
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when (installType) {
|
when (installType) {
|
||||||
InstallType.DEFAULT -> {
|
InstallType.DEFAULT -> {
|
||||||
|
val currentPackageInfo = pm.getPackageInfo(outputFile)
|
||||||
|
?: throw Exception("Failed to load application info")
|
||||||
|
|
||||||
|
// If the app is currently installed
|
||||||
|
val existingPackageInfo = pm.getPackageInfo(currentPackageInfo.packageName)
|
||||||
|
if (existingPackageInfo != null) {
|
||||||
|
// Check if the app version is less than the installed version
|
||||||
|
if (pm.getVersionCode(currentPackageInfo) < pm.getVersionCode(existingPackageInfo)) {
|
||||||
|
// Exit if the selected app version is less than the installed version
|
||||||
|
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_CONFLICT
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the app is mounted as root
|
// Check if the app is mounted as root
|
||||||
// If it is, unmount it first, silently
|
// If it is, unmount it first, silently
|
||||||
if (rootInstaller.hasRootAccess() && rootInstaller.isAppMounted(packageName)) {
|
if (rootInstaller.hasRootAccess() && rootInstaller.isAppMounted(packageName)) {
|
||||||
@@ -412,16 +412,6 @@ class PatcherViewModel(
|
|||||||
packageInfo.label()
|
packageInfo.label()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for base APK, first check if the app is already installed
|
|
||||||
if (existingPackageInfo == null) {
|
|
||||||
// If the app is not installed, check if the output file is a base apk
|
|
||||||
if (currentPackageInfo.splitNames.isNotEmpty()) {
|
|
||||||
// Exit if there is no base APK package
|
|
||||||
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_INVALID
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val inputVersion = input.selectedApp.version
|
val inputVersion = input.selectedApp.version
|
||||||
?: inputFile?.let(pm::getPackageInfo)?.versionName
|
?: inputFile?.let(pm::getPackageInfo)?.versionName
|
||||||
?: throw Exception("Failed to determine input APK version")
|
?: throw Exception("Failed to determine input APK version")
|
||||||
|
|||||||
Reference in New Issue
Block a user