Skip to content

Commit

Permalink
refactor!: restructure code
Browse files Browse the repository at this point in the history
This commit focuses on improving code quality in a couple of places and bumping the dependency to ReVanced Patcher.

BREAKING CHANGE: This introduces major changes to how ReVanced CLI is used from the command line.
  • Loading branch information
oSumAtrIX committed Aug 22, 2023
1 parent ef5fa9b commit 07da528
Show file tree
Hide file tree
Showing 9 changed files with 416 additions and 408 deletions.
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ repositories {
}

dependencies {
implementation("app.revanced:revanced-patcher:14.0.0")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.22")

implementation("app.revanced:revanced-patcher:13.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
implementation("info.picocli:picocli:4.7.3")
implementation("com.github.revanced:jadb:2531a28109") // Updated fork
implementation("com.android.tools.build:apksig:8.1.0")
Expand Down
387 changes: 245 additions & 142 deletions src/main/kotlin/app/revanced/cli/command/MainCommand.kt

Large diffs are not rendered by default.

23 changes: 0 additions & 23 deletions src/main/kotlin/app/revanced/cli/patcher/Patcher.kt

This file was deleted.

113 changes: 0 additions & 113 deletions src/main/kotlin/app/revanced/utils/adb/Adb.kt

This file was deleted.

130 changes: 130 additions & 0 deletions src/main/kotlin/app/revanced/utils/adb/AdbManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package app.revanced.utils.adb

import app.revanced.cli.logging.CliLogger
import app.revanced.utils.adb.AdbManager.Apk
import app.revanced.utils.adb.Constants.COMMAND_CREATE_DIR
import app.revanced.utils.adb.Constants.COMMAND_DELETE
import app.revanced.utils.adb.Constants.COMMAND_INSTALL_MOUNT
import app.revanced.utils.adb.Constants.COMMAND_PREPARE_MOUNT_APK
import app.revanced.utils.adb.Constants.COMMAND_RESTART
import app.revanced.utils.adb.Constants.COMMAND_UMOUNT
import app.revanced.utils.adb.Constants.CONTENT_MOUNT_SCRIPT
import app.revanced.utils.adb.Constants.PATH_INIT_PUSH
import app.revanced.utils.adb.Constants.PATH_INSTALLATION
import app.revanced.utils.adb.Constants.PATH_MOUNT
import app.revanced.utils.adb.Constants.PATH_PATCHED_APK
import app.revanced.utils.adb.Constants.PLACEHOLDER
import se.vidstige.jadb.JadbConnection
import se.vidstige.jadb.managers.Package
import se.vidstige.jadb.managers.PackageManager
import java.io.Closeable
import java.io.File

/**
* Adb manager. Used to install and uninstall [Apk] files.
*
* @param deviceSerial The serial of the device.
*/
internal sealed class AdbManager(deviceSerial: String? = null, protected val logger: CliLogger? = null) : Closeable {
protected val device = JadbConnection().devices.find { device -> device.serial == deviceSerial }
?: throw IllegalArgumentException("The device with the serial $deviceSerial can not be found.")

init {
logger?.trace("Established connection to $deviceSerial")
}

/**
* Installs the [Apk] file.
*
* @param apk The [Apk] file.
*/
open fun install(apk: Apk) {
logger?.info("Finished installing ${apk.file.name}")
}

/**
* Uninstalls the package.
*
* @param packageName The package name.
*/
open fun uninstall(packageName: String) {
logger?.info("Finished uninstalling $packageName")
}

/**
* Closes the [AdbManager] instance.
*/
override fun close() {
logger?.trace("Closed")
}

class RootAdbManager(deviceSerial: String, logger: CliLogger? = null) : AdbManager(deviceSerial, logger) {
init {
if (!device.hasSu()) throw IllegalArgumentException("Root required on $deviceSerial. Task failed")
}

override fun install(apk: Apk) {
logger?.info("Installing by mounting")

val applyReplacement = getPlaceholderReplacement(
apk.packageName ?: throw IllegalArgumentException("Package name is required")
)

device.copyFile(apk.file, PATH_INIT_PUSH)

device.run("$COMMAND_CREATE_DIR $PATH_INSTALLATION")
device.run(COMMAND_PREPARE_MOUNT_APK.applyReplacement())

device.createFile(PATH_INIT_PUSH, CONTENT_MOUNT_SCRIPT.applyReplacement())

device.run(COMMAND_INSTALL_MOUNT.applyReplacement())
device.run(COMMAND_UMOUNT.applyReplacement()) // Sanity check.
device.run(PATH_MOUNT.applyReplacement())
device.run(COMMAND_RESTART.applyReplacement())

super.install(apk)
}

override fun uninstall(packageName: String) {
logger?.info("Uninstalling $packageName by unmounting and deleting the package")

val applyReplacement = getPlaceholderReplacement(packageName)

device.run(COMMAND_UMOUNT.applyReplacement(packageName))
device.run(COMMAND_DELETE.applyReplacement(PATH_PATCHED_APK).applyReplacement())
device.run(COMMAND_DELETE.applyReplacement(PATH_MOUNT).applyReplacement())

super.uninstall(packageName)
}

companion object Utils {
private fun getPlaceholderReplacement(with: String): String.() -> String = { replace(PLACEHOLDER, with) }
private fun String.applyReplacement(with: String) = replace(PLACEHOLDER, with)
}
}

class UserAdbManager(deviceSerial: String, logger: CliLogger? = null) : AdbManager(deviceSerial, logger) {
private val packageManager = PackageManager(device)

override fun install(apk: Apk) {
PackageManager(device).install(apk.file)

super.install(apk)
}

override fun uninstall(packageName: String) {
logger?.info("Uninstalling $packageName")

packageManager.uninstall(Package(packageName))

super.uninstall(packageName)
}
}

/**
* Apk file for [AdbManager].
*
* @param file The [Apk] file.
*/
internal class Apk(val file: File, val packageName: String? = null)
}
34 changes: 17 additions & 17 deletions src/main/kotlin/app/revanced/utils/adb/Commands.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ package app.revanced.utils.adb

import se.vidstige.jadb.JadbDevice
import se.vidstige.jadb.RemoteFile
import se.vidstige.jadb.ShellProcessBuilder
import java.io.File
import java.util.concurrent.Callable
import java.util.concurrent.Executors

internal fun JadbDevice.buildCommand(command: String, su: Boolean = true): ShellProcessBuilder {
if (su) {
return shellProcessBuilder("su -c \'$command\'")
// return the input or output stream, depending on which first returns a value
internal fun JadbDevice.run(command: String, su: Boolean = false) = with(this.startCommand(command, su)) {
Executors.newFixedThreadPool(2).let { service ->
arrayOf(inputStream, errorStream).map { stream ->
Callable { stream.bufferedReader().use { it.readLine() } }
}.let { tasks -> service.invokeAny(tasks).also { service.shutdown() } }
}

val args = command.split(" ") as ArrayList<String>
val cmd = args.removeFirst()

return shellProcessBuilder(cmd, *args.toTypedArray())
}

internal fun JadbDevice.run(command: String, su: Boolean = true): Int {
return this.buildCommand(command, su).start().waitFor()
}
internal fun JadbDevice.hasSu() =
this.startCommand("su -h", false).waitFor() == 0

internal fun JadbDevice.copy(targetPath: String, file: File) {
push(file, RemoteFile(targetPath))
}
internal fun JadbDevice.copyFile(file: File, targetFile: String) =
push(file, RemoteFile(targetFile))

internal fun JadbDevice.createFile(targetFile: String, content: String) {
internal fun JadbDevice.createFile(targetFile: String, content: String) =
push(content.byteInputStream(), System.currentTimeMillis(), 644, RemoteFile(targetFile))
}


private fun JadbDevice.startCommand(command: String, su: Boolean) =
shellProcessBuilder(if (su) "su -c '$command'" else command).start()
Loading

0 comments on commit 07da528

Please sign in to comment.