From 131100ef0043924a9c11eb9886b4f6b0373690d9 Mon Sep 17 00:00:00 2001 From: Itroublve <51215044+Itroublve@users.noreply.github.com> Date: Sun, 10 Jul 2022 12:17:47 +0200 Subject: [PATCH] feat: `--uninstall` switch (#84) This moves the move unmount script to a command --- .../app/revanced/cli/command/MainCommand.kt | 62 ++++++++++++++----- .../app/revanced/cli/patcher/Patcher.kt | 5 +- .../app/revanced/cli/signing/Signing.kt | 2 +- src/main/kotlin/app/revanced/utils/adb/Adb.kt | 29 +++++---- .../app/revanced/utils/adb/Constants.kt | 24 +++---- .../app/revanced/utils/patcher/Patcher.kt | 8 +-- 6 files changed, 80 insertions(+), 50 deletions(-) diff --git a/src/main/kotlin/app/revanced/cli/command/MainCommand.kt b/src/main/kotlin/app/revanced/cli/command/MainCommand.kt index 4b03204..7c84cdf 100644 --- a/src/main/kotlin/app/revanced/cli/command/MainCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/MainCommand.kt @@ -33,6 +33,20 @@ internal object MainCommand : Runnable { lateinit var args: Args class Args { + @Option(names = ["-a", "--apk"], description = ["Input file to be patched"], required = true) + lateinit var inputFile: File + + @Option(names = ["--uninstall"], description = ["Uninstall the mount variant"]) + var uninstall: Boolean = false + + @Option(names = ["-d", "--deploy-on"], description = ["If specified, deploy to adb device with given name"]) + var deploy: String? = null + + @ArgGroup(exclusive = false) + var sArgs: StartPatcherArgs? = null + } + + class StartPatcherArgs { @Option(names = ["-b", "--bundles"], description = ["One or more bundles of patches"], required = true) var patchBundles = arrayOf() @@ -58,9 +72,6 @@ internal object MainCommand : Runnable { } class PatchingArgs { - @Option(names = ["-a", "--apk"], description = ["Input file to be patched"], required = true) - lateinit var inputFile: File - @Option(names = ["-o", "--out"], description = ["Output file path"], required = true) lateinit var outputPath: String @@ -94,9 +105,6 @@ internal object MainCommand : Runnable { @Option(names = ["-p", "--password"], description = ["Overwrite the default password for the signed file"]) var password = "ReVanced" - @Option(names = ["-d", "--deploy-on"], description = ["If specified, deploy to adb device with given name"]) - var deploy: String? = null - @Option(names = ["-t", "--temp-dir"], description = ["Temporal resource cache directory"]) var cacheDirectory = "revanced-cache" @@ -108,16 +116,37 @@ internal object MainCommand : Runnable { } override fun run() { - if (args.lArgs?.listOnly == true) { + if (args.sArgs?.lArgs?.listOnly == true) { printListOfPatches() return } - val args = args.pArgs ?: return + if (args.uninstall) { + // temporarily get package name using Patcher method + // fix: abstract options in patcher + val patcher = app.revanced.patcher.Patcher( + PatcherOptions( + args.inputFile, + "uninstaller-cache", + false + ) + ) + File("uninstaller-cache").deleteRecursively() + + val adb: Adb? = args.deploy?.let { + Adb(File("placeholder_file"), patcher.data.packageMetadata.packageName, args.deploy!!, false) + } + adb?.uninstall() + + return + } + + val _args = args + val args = args.sArgs?.pArgs ?: return val patcher = app.revanced.patcher.Patcher( PatcherOptions( - args.inputFile, + _args.inputFile, args.cacheDirectory, !args.disableResourcePatching, logger = PatcherLogger @@ -126,10 +155,9 @@ internal object MainCommand : Runnable { val outputFile = File(args.outputPath) - val adb: Adb? = args.deploy?.let { - Adb(outputFile, patcher.data.packageMetadata.packageName, args.deploy!!, !args.mount) + val adb: Adb? = _args.deploy?.let { + Adb(outputFile, patcher.data.packageMetadata.packageName, _args.deploy!!, !args.mount) } - val patchedFile = if (args.mount) outputFile else File(args.cacheDirectory).resolve("${outputFile.nameWithoutExtension}_raw.apk") @@ -153,17 +181,17 @@ internal object MainCommand : Runnable { adb?.deploy() - if (args.clean && args.deploy != null) Files.delete(outputFile.toPath()) + if (args.clean && _args.deploy != null) Files.delete(outputFile.toPath()) logger.info("Finished") } private fun printListOfPatches() { - for (patchBundlePath in args.patchBundles) for (patch in JarPatchBundle(patchBundlePath).loadPatches()) { + for (patchBundlePath in args.sArgs?.patchBundles!!) for (patch in JarPatchBundle(patchBundlePath).loadPatches()) { for (compatiblePackage in patch.compatiblePackages!!) { val packageEntryStr = buildString { // Add package if flag is set - if (args.lArgs?.withPackages == true) { + if (args.sArgs?.lArgs?.withPackages == true) { val packageName = compatiblePackage.name.substringAfterLast(".").padStart(10) append(packageName) append("\t") @@ -172,12 +200,12 @@ internal object MainCommand : Runnable { val patchName = patch.patchName.padStart(25) append(patchName) // Add description if flag is set. - if (args.lArgs?.withDescriptions == true) { + if (args.sArgs?.lArgs?.withDescriptions == true) { append("\t") append(patch.description) } // Add compatible versions, if flag is set - if (args.lArgs?.withVersions == true) { + if (args.sArgs?.lArgs?.withVersions == true) { val compatibleVersions = compatiblePackage.versions.joinToString(separator = ", ") append("\t") append(compatibleVersions) diff --git a/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt b/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt index e006025..c1895ca 100644 --- a/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt @@ -11,7 +11,8 @@ import java.nio.file.Files internal object Patcher { internal fun start(patcher: app.revanced.patcher.Patcher, output: File) { - val args = args.pArgs!! + val inputFile = args.inputFile + val args = args.sArgs?.pArgs!! // merge files like necessary integrations patcher.mergeFiles() @@ -22,7 +23,7 @@ internal object Patcher { // write output file if (output.exists()) Files.delete(output.toPath()) - args.inputFile.copyTo(output) + inputFile.copyTo(output) val result = patcher.save() ZipFileSystemUtils(output).use { outputFileSystem -> diff --git a/src/main/kotlin/app/revanced/cli/signing/Signing.kt b/src/main/kotlin/app/revanced/cli/signing/Signing.kt index 5732d71..677316f 100644 --- a/src/main/kotlin/app/revanced/cli/signing/Signing.kt +++ b/src/main/kotlin/app/revanced/cli/signing/Signing.kt @@ -8,7 +8,7 @@ import java.io.File object Signing { fun start(inputFile: File, outputFile: File, signingOptions: SigningOptions) { - val cacheDirectory = File(args.pArgs!!.cacheDirectory) + val cacheDirectory = File(args.sArgs?.pArgs?.cacheDirectory) val alignedOutput = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_aligned.apk") val signedOutput = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_signed.apk") diff --git a/src/main/kotlin/app/revanced/utils/adb/Adb.kt b/src/main/kotlin/app/revanced/utils/adb/Adb.kt index cc2f288..53820de 100644 --- a/src/main/kotlin/app/revanced/utils/adb/Adb.kt +++ b/src/main/kotlin/app/revanced/utils/adb/Adb.kt @@ -21,7 +21,7 @@ internal class Adb( ?: throw IllegalArgumentException("No such device with name $deviceName") if (!modeInstall && device.run("su -h", false) != 0) - throw IllegalArgumentException("Root required on $deviceName. Deploying failed") + throw IllegalArgumentException("Root required on $deviceName. Task failed") } private fun String.replacePlaceholder(with: String? = null): String { @@ -39,7 +39,7 @@ internal class Adb( // push patched file device.copy(Constants.PATH_INIT_PUSH, file) - // create revanced path + // create revanced folder path device.run("${Constants.COMMAND_CREATE_DIR} ${Constants.PATH_REVANCED}") // prepare mounting the apk @@ -53,16 +53,8 @@ internal class Adb( // install mount script device.run(Constants.COMMAND_INSTALL_MOUNT.replacePlaceholder()) - // push umount script - device.createFile( - Constants.PATH_INIT_PUSH, - Constants.CONTENT_UMOUNT_SCRIPT.replacePlaceholder() - ) - // install unmount script - device.run(Constants.COMMAND_INSTALL_UMOUNT.replacePlaceholder()) - // unmount the apk for sanity - device.run(Constants.PATH_UMOUNT.replacePlaceholder()) + device.run(Constants.COMMAND_UMOUNT.replacePlaceholder()) // mount the apk device.run(Constants.PATH_MOUNT.replacePlaceholder()) @@ -74,6 +66,21 @@ internal class Adb( } } + internal fun uninstall() { + logger.info("Uninstalling by unmounting") + + // unmount the apk + device.run(Constants.COMMAND_UMOUNT.replacePlaceholder()) + + // delete revanced app + device.run(Constants.COMMAND_DELETE.replacePlaceholder(Constants.PATH_REVANCED_APP).replacePlaceholder()) + + // delete mount script + device.run(Constants.COMMAND_DELETE.replacePlaceholder(Constants.PATH_MOUNT).replacePlaceholder()) + + logger.info("Finished uninstalling") + } + private fun log() { val executor = Executors.newSingleThreadExecutor() val pipe = if (logging) { diff --git a/src/main/kotlin/app/revanced/utils/adb/Constants.kt b/src/main/kotlin/app/revanced/utils/adb/Constants.kt index 57ef60d..80adb5d 100644 --- a/src/main/kotlin/app/revanced/utils/adb/Constants.kt +++ b/src/main/kotlin/app/revanced/utils/adb/Constants.kt @@ -21,31 +21,25 @@ internal object Constants { internal const val PATH_REVANCED = "/data/adb/revanced/" // revanced apk path - private const val PATH_REVANCED_APP = "$PATH_REVANCED$PLACEHOLDER.apk" + internal const val PATH_REVANCED_APP = "$PATH_REVANCED$PLACEHOLDER.apk" - // (un)mount script paths + // delete command + internal const val COMMAND_DELETE = "rm -rf $PLACEHOLDER" + + // mount script path internal const val PATH_MOUNT = "/data/adb/service.d/$NAME_MOUNT_SCRIPT" - internal const val PATH_UMOUNT = "/data/adb/post-fs-data.d/un$NAME_MOUNT_SCRIPT" // move to revanced apk path & set permissions internal const val COMMAND_PREPARE_MOUNT_APK = "base_path=\"$PATH_REVANCED_APP\" && 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" + // unmount command + internal const val COMMAND_UMOUNT = + "stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' ) && umount -l ${'$'}stock_path" + // install mount script & set permissions internal const val COMMAND_INSTALL_MOUNT = "mv $PATH_INIT_PUSH $PATH_MOUNT && $COMMAND_CHMOD_MOUNT $PATH_MOUNT" - // install umount script & set permissions - internal const val COMMAND_INSTALL_UMOUNT = "mv $PATH_INIT_PUSH $PATH_UMOUNT && $COMMAND_CHMOD_MOUNT $PATH_UMOUNT" - - // unmount script - internal val CONTENT_UMOUNT_SCRIPT = - """ - #!/system/bin/sh - - stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' ) - umount -l ${'$'}stock_path - """.trimIndent() - // mount script internal val CONTENT_MOUNT_SCRIPT = """ diff --git a/src/main/kotlin/app/revanced/utils/patcher/Patcher.kt b/src/main/kotlin/app/revanced/utils/patcher/Patcher.kt index 3eb2e11..476181d 100644 --- a/src/main/kotlin/app/revanced/utils/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/utils/patcher/Patcher.kt @@ -15,7 +15,7 @@ fun Patcher.addPatchesFiltered() { val packageName = this.data.packageMetadata.packageName val packageVersion = this.data.packageMetadata.packageVersion - args.patchBundles.forEach { bundle -> + args.sArgs?.patchBundles!!.forEach { bundle -> val includedPatches = mutableListOf>>() JarPatchBundle(bundle).loadPatches().forEach patch@{ patch -> val compatiblePackages = patch.compatiblePackages @@ -23,7 +23,7 @@ fun Patcher.addPatchesFiltered() { val prefix = "Skipping $patchName" - val args = MainCommand.args.pArgs!! + val args = MainCommand.args.sArgs?.pArgs!! if (excludePatches && args.excludedPatches.contains(patchName)) { logger.info("$prefix: Explicitely excluded") @@ -72,7 +72,7 @@ fun Patcher.applyPatchesVerbose() { } fun Patcher.mergeFiles() { - this.addFiles(args.pArgs!!.mergeFiles) { file -> + this.addFiles(args.sArgs?.pArgs!!.mergeFiles) { file -> logger.info("Merging $file") } -} +} \ No newline at end of file