From de2d29c46455c769196261c7a455a859231b62d2 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 5 May 2022 01:43:35 +0200 Subject: [PATCH] add: deploy to `adb` Signed-off-by: oSumAtrIX --- build.gradle.kts | 3 + .../kotlin/app/revanced/cli/MainCommand.kt | 26 +++++- src/main/kotlin/app/revanced/cli/Patcher.kt | 8 +- src/main/kotlin/app/revanced/utils/Scripts.kt | 35 -------- src/main/kotlin/app/revanced/utils/adb/Adb.kt | 85 +++++++++++++++++++ .../kotlin/app/revanced/utils/adb/Commands.kt | 25 ++++++ .../app/revanced/utils/adb/Constants.kt | 34 ++++++++ 7 files changed, 170 insertions(+), 46 deletions(-) delete mode 100644 src/main/kotlin/app/revanced/utils/Scripts.kt create mode 100644 src/main/kotlin/app/revanced/utils/adb/Adb.kt create mode 100644 src/main/kotlin/app/revanced/utils/adb/Commands.kt create mode 100644 src/main/kotlin/app/revanced/utils/adb/Constants.kt diff --git a/build.gradle.kts b/build.gradle.kts index 730003e..b4e3ea6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,6 +27,9 @@ dependencies { implementation("app.revanced:revanced-patcher:+") implementation(patchesDependency) implementation("info.picocli:picocli:+") + + implementation("me.tongfei:progressbar:+") + implementation("com.github.li-wjohnson:jadb:master-SNAPSHOT") // using a fork instead. implementation("org.bouncycastle:bcpkix-jdk15on:+") } diff --git a/src/main/kotlin/app/revanced/cli/MainCommand.kt b/src/main/kotlin/app/revanced/cli/MainCommand.kt index a15b07f..57a4c36 100644 --- a/src/main/kotlin/app/revanced/cli/MainCommand.kt +++ b/src/main/kotlin/app/revanced/cli/MainCommand.kt @@ -2,6 +2,7 @@ package app.revanced.cli import app.revanced.patch.PatchLoader import app.revanced.patch.Patches +import app.revanced.utils.adb.Adb import picocli.CommandLine import picocli.CommandLine.* import java.io.File @@ -10,15 +11,15 @@ import java.io.File name = "ReVanced-CLI", version = ["1.0.0"], mixinStandardHelpOptions = true ) internal object MainCommand : Runnable { - @Option(names = ["-p", "--patches"], description = ["One or more bundles of patches"]) - internal var patchBundles = arrayOf() - @Parameters( paramLabel = "INCLUDE", description = ["Which patches to include. If none is specified, all compatible patches will be included"] ) internal var includedPatches = arrayOf() + @Option(names = ["-p", "--patches"], description = ["One or more bundles of patches"]) + internal var patchBundles = arrayOf() + @Option(names = ["-c", "--cache"], description = ["Output resource cache directory"], required = true) internal lateinit var cacheDirectory: String @@ -41,6 +42,10 @@ internal object MainCommand : Runnable { @Option(names = ["-o", "--out"], description = ["Output file path"], required = true) internal lateinit var outputPath: String + @Option(names = ["-d", "--deploy-on"], description = ["If specified, deploy to adb device with given name"]) + internal var deploy: String? = null + + override fun run() { if (listOnly) { patchBundles.forEach { @@ -52,10 +57,23 @@ internal object MainCommand : Runnable { return } - Patcher.run() + val patcher = app.revanced.patcher.Patcher( + inputFile, + cacheDirectory, + patchResources + ) + Patcher.start(patcher) if (!wipe) return File(cacheDirectory).deleteRecursively() + + deploy?.let { + Adb( + File(outputPath), + patcher.packageName, + deploy!! + ).deploy() + } } } diff --git a/src/main/kotlin/app/revanced/cli/Patcher.kt b/src/main/kotlin/app/revanced/cli/Patcher.kt index 26c78ce..548ef1c 100644 --- a/src/main/kotlin/app/revanced/cli/Patcher.kt +++ b/src/main/kotlin/app/revanced/cli/Patcher.kt @@ -10,13 +10,7 @@ import java.io.File internal class Patcher { internal companion object { - internal fun run() { - val patcher = app.revanced.patcher.Patcher( - MainCommand.inputFile, - MainCommand.cacheDirectory, - MainCommand.patchResources - ) - + internal fun start(patcher: app.revanced.patcher.Patcher) { // merge files like necessary integrations patcher.addFiles(MainCommand.mergeFiles) // add patches, but filter incompatible or excluded patches diff --git a/src/main/kotlin/app/revanced/utils/Scripts.kt b/src/main/kotlin/app/revanced/utils/Scripts.kt deleted file mode 100644 index 31043fb..0000000 --- a/src/main/kotlin/app/revanced/utils/Scripts.kt +++ /dev/null @@ -1,35 +0,0 @@ -package app.revanced.utils - -// TODO: make this a class with PACKAGE_NAME as argument, then use that everywhere. -// make sure to remove the "const" from all the vals, they won't compile obviously. -internal object Scripts { - private const val PACKAGE_NAME = "com.google.android.apps.youtube.music" - private const val DATA_PATH = "/data/adb/ReVanced" - internal const val APK_PATH = "/sdcard/base.apk" - internal const val SCRIPT_PATH = "/sdcard/mount.sh" - - internal val MOUNT_SCRIPT = - """ - base_path="$DATA_PATH/base.apk" - stock_path=${'$'}{ pm path $PACKAGE_NAME | grep base | sed 's/package://g' } - umount -l ${'$'}stock_path - rm ${'$'}base_path - mv "$APK_PATH" ${'$'}base_path - chmod 644 ${'$'}base_path - chown system:system ${'$'}base_path - chcon u:object_r:apk_data_file:s0 ${'$'}base_path - mount -o bind ${'$'}base_path ${'$'}stock_path - """.trimIndent() - - internal const val PIDOF_APP_COMMAND = "pidof -s $PACKAGE_NAME" - private const val PIDOF_APP = "\$($PIDOF_APP_COMMAND)" - internal const val CREATE_DIR_COMMAND = "su -c \"mkdir -p $DATA_PATH/\"" - internal const val MV_MOUNT_COMMAND = "su -c \"mv /sdcard/mount.sh $DATA_PATH/\"" - internal const val CHMOD_MOUNT_COMMAND = "su -c \"chmod +x $DATA_PATH/mount.sh\"" - internal const val START_MOUNT_COMMAND = "su -c $DATA_PATH/mount.sh" - internal const val UNMOUNT_COMMAND = - "su -c \"umount -l $(pm path $PACKAGE_NAME | grep base | sed 's/package://g')\"" - internal const val LOGCAT_COMMAND = "su -c \"logcat -c && logcat --pid=$PIDOF_APP\"" - internal const val STOP_APP_COMMAND = "su -c \"kill $PIDOF_APP\"" - internal const val START_APP_COMMAND = "monkey -p $PACKAGE_NAME 1" -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/utils/adb/Adb.kt b/src/main/kotlin/app/revanced/utils/adb/Adb.kt new file mode 100644 index 0000000..a93a3cc --- /dev/null +++ b/src/main/kotlin/app/revanced/utils/adb/Adb.kt @@ -0,0 +1,85 @@ +package app.revanced.utils.adb + +import se.vidstige.jadb.JadbConnection +import se.vidstige.jadb.JadbDevice +import java.io.File +import java.util.concurrent.Executors + +internal class Adb( + private val apk: File, + private val packageName: String, + deviceName: String, + private val logging: Boolean = true +) { + private val device: JadbDevice + + init { + device = JadbConnection().devices.find { it.serial == deviceName } + ?: throw IllegalArgumentException("No such device with name $deviceName") + + if (device.run("su -h") == 0) + throw IllegalArgumentException("Root required on $deviceName. Deploying failed.") + } + + internal fun deploy() { + // create revanced path + device.run(Constants.COMMAND_CREATE_DIR + Constants.PATH_DATA) + + // create mount script + device.createFile( + Constants.PATH_INIT_PUSH, + Constants.CONTENT_MOUNT_SCRIPT.replace(Constants.PLACEHOLDER, packageName) + ) + + // move the mount script to the revanced path + device.run(Constants.COMMAND_MOVE_MOUNT) + // make the mount script executable + device.run(Constants.COMMAND_CHMOD_MOUNT + Constants.NAME_MOUNT_SCRIPT) + + // push patched file + device.copy(Constants.PATH_INIT_PUSH, apk) + // move patched file to revanced path + device.run(Constants.COMMAND_MOVE_BASE) + + // kill, mount & run app + device.run(Constants.COMMAND_KILL_APP.replace(Constants.PLACEHOLDER, packageName)) + device.run(Constants.COMMAND_MOUNT) + device.run(Constants.COMMAND_RUN_APP.replace(Constants.PLACEHOLDER, packageName)) + + // log the app + log() + + // unmount it, after it closes + device.run(Constants.COMMAND_UNMOUNT.replace(Constants.PLACEHOLDER, packageName)) + } + + private fun log() { + val executor = Executors.newSingleThreadExecutor() + val pipe = if (logging) { + ProcessBuilder.Redirect.INHERIT + } else { + ProcessBuilder.Redirect.PIPE + } + + val process = device.buildCommand(Constants.COMMAND_LOGCAT.replace(Constants.PLACEHOLDER, packageName)) + .redirectOutput(pipe) + .redirectError(pipe) + .useExecutor(executor) + .start() + + Thread.sleep(250) // give the app some time to start up. + while (true) { + try { + while (device.run(Constants.COMMAND_PID_OF + packageName) == 0) { + Thread.sleep(1000) + } + break + } catch (e: Exception) { + throw RuntimeException("An error occurred while monitoring state of app", e) + } + } + println("App closed, continuing.") + process.destroy() + executor.shutdown() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/utils/adb/Commands.kt b/src/main/kotlin/app/revanced/utils/adb/Commands.kt new file mode 100644 index 0000000..af23c27 --- /dev/null +++ b/src/main/kotlin/app/revanced/utils/adb/Commands.kt @@ -0,0 +1,25 @@ +package app.revanced.utils.adb + +import se.vidstige.jadb.JadbDevice +import se.vidstige.jadb.RemoteFile +import se.vidstige.jadb.ShellProcessBuilder +import java.io.File + +internal fun JadbDevice.buildCommand(command: String, su: Boolean = true): ShellProcessBuilder { + val args = command.split(" ") as ArrayList + val cmd = args.removeFirst() + + return shellProcessBuilder(cmd, *args.toTypedArray()) +} + +internal fun JadbDevice.run(command: String, su: Boolean = true): Int { + return this.buildCommand(command).start().waitFor() +} + +internal fun JadbDevice.copy(targetPath: String, file: File) { + push(file, RemoteFile(targetPath)) +} + +internal fun JadbDevice.createFile(targetFile: String, content: String, su: Boolean = true) { + push(content.byteInputStream(), System.currentTimeMillis(), 644, RemoteFile(targetFile)) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/utils/adb/Constants.kt b/src/main/kotlin/app/revanced/utils/adb/Constants.kt new file mode 100644 index 0000000..39b74c8 --- /dev/null +++ b/src/main/kotlin/app/revanced/utils/adb/Constants.kt @@ -0,0 +1,34 @@ +package app.revanced.utils.adb + +internal object Constants { + internal const val PLACEHOLDER = "TEMPLATE_PACKAGE_NAME" + + internal const val NAME_MOUNT_SCRIPT = "mount.sh" + + internal const val PATH_DATA = "/data/adb/revanced/" + internal const val PATH_INIT_PUSH = "/sdcard/revanced" + + internal const val COMMAND_PID_OF = "pidof -s " + internal const val COMMAND_CREATE_DIR = "mkdir -p " + internal const val COMMAND_MOVE_BASE = "mv $PATH_INIT_PUSH $PATH_DATA/base.apk" + internal const val COMMAND_MOVE_MOUNT = "mv $PATH_INIT_PUSH $PATH_DATA/$NAME_MOUNT_SCRIPT" + internal const val COMMAND_CHMOD_MOUNT = "chmod +x $PATH_DATA" + internal const val COMMAND_MOUNT = "./$PATH_DATA/$NAME_MOUNT_SCRIPT" + internal const val COMMAND_UNMOUNT = "umount -l $(pm path $PLACEHOLDER | grep base | sed 's/package://g')" + internal const val COMMAND_LOGCAT = "logcat -c && logcat --pid=$($COMMAND_PID_OF $PLACEHOLDER)" + internal const val COMMAND_RUN_APP = "monkey -p $PLACEHOLDER 1" + internal const val COMMAND_KILL_APP = "kill \$($COMMAND_PID_OF $PLACEHOLDER)" + + internal val CONTENT_MOUNT_SCRIPT = + """ + base_path="$PATH_DATA/base.apk" + stock_path=${'$'}{ pm path $PLACEHOLDER | grep base | sed 's/package://g' } + umount -l ${'$'}stock_path + rm ${'$'}base_path + mv "$PATH_INIT_PUSH" ${'$'}base_path + chmod 644 ${'$'}base_path + chown system:system ${'$'}base_path + chcon u:object_r:apk_data_file:s0 ${'$'}base_path + mount -o bind ${'$'}base_path ${'$'}stock_path + """.trimIndent() +} \ No newline at end of file