mirror of
https://github.com/ReVanced/revanced-library.git
synced 2026-01-18 08:53:57 +00:00
Compare commits
17 Commits
v1.4.0-dev
...
v1.5.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b637e0d7d7 | ||
|
|
9fda407441 | ||
|
|
44f7c13a77 | ||
|
|
ecff6fe0d3 | ||
|
|
3515e331ac | ||
|
|
a921c40306 | ||
|
|
b6e1de5eaf | ||
|
|
bf5780e2f7 | ||
|
|
99e90c02ed | ||
|
|
ac3917fecc | ||
|
|
98b7b347cb | ||
|
|
cdf94ffeca | ||
|
|
37434cf4a4 | ||
|
|
73c97abedd | ||
|
|
762b7e3bc0 | ||
|
|
e4be6dbccd | ||
|
|
96845ba265 |
41
CHANGELOG.md
41
CHANGELOG.md
@@ -1,3 +1,44 @@
|
|||||||
|
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2023-12-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Improve mount reliability by unmounting existing mounts and killing running apps ([9fda407](https://github.com/ReVanced/revanced-library/commit/9fda40744173669c84b0c2599ae5ac5d39591798))
|
||||||
|
|
||||||
|
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.4.0...v1.5.0-dev.1) (2023-12-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add JSON de- and serialization of patches ([ecff6fe](https://github.com/ReVanced/revanced-library/commit/ecff6fe0d3889d729a0badcfa28b89610bd27d48))
|
||||||
|
|
||||||
|
# [1.4.0](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0) (2023-11-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Differentiate no package compatibility to any version compatibility ([762b7e3](https://github.com/ReVanced/revanced-library/commit/762b7e3bc01e2ca33dfcdbb1b5028d60ef6e0a48))
|
||||||
|
* Sort the version maps by the most common version ([e4be6db](https://github.com/ReVanced/revanced-library/commit/e4be6dbccd86700ffafe7cd8395e845bbd3d5138))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add `PatchUtils#getMostCommonCompatibleVersions` utility function ([c5f3536](https://github.com/ReVanced/revanced-library/commit/c5f3536cbb6997766076595dc0b2b5d2e861ca73))
|
||||||
|
* Allow getting most common compatible versions for all packages ([96845ba](https://github.com/ReVanced/revanced-library/commit/96845ba265e6dc208c7ac96f5e58734209cd1720))
|
||||||
|
|
||||||
|
# [1.4.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.4.0-dev.1...v1.4.0-dev.2) (2023-11-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Differentiate no package compatibility to any version compatibility ([762b7e3](https://github.com/ReVanced/revanced-library/commit/762b7e3bc01e2ca33dfcdbb1b5028d60ef6e0a48))
|
||||||
|
* Sort the version maps by the most common version ([e4be6db](https://github.com/ReVanced/revanced-library/commit/e4be6dbccd86700ffafe7cd8395e845bbd3d5138))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Allow getting most common compatible versions for all packages ([96845ba](https://github.com/ReVanced/revanced-library/commit/96845ba265e6dc208c7ac96f5e58734209cd1720))
|
||||||
|
|
||||||
# [1.4.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0-dev.1) (2023-11-27)
|
# [1.4.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0-dev.1) (2023-11-27)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,47 @@ public final class app/revanced/library/PatchUtils {
|
|||||||
public static synthetic fun getMostCommonCompatibleVersions$default (Lapp/revanced/library/PatchUtils;Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
|
public static synthetic fun getMostCommonCompatibleVersions$default (Lapp/revanced/library/PatchUtils;Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/PatchUtils$Json {
|
||||||
|
public static final field INSTANCE Lapp/revanced/library/PatchUtils$Json;
|
||||||
|
public final fun deserialize (Ljava/io/InputStream;Ljava/lang/Class;)Ljava/util/Set;
|
||||||
|
public final fun serialize (Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;)V
|
||||||
|
public static synthetic fun serialize$default (Lapp/revanced/library/PatchUtils$Json;Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;ILjava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch : app/revanced/library/PatchUtils$Json$JsonPatch {
|
||||||
|
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$Companion;
|
||||||
|
public final fun getCompatiblePackages ()Ljava/util/Set;
|
||||||
|
public final fun getDependencies ()Ljava/util/Set;
|
||||||
|
public final fun getDescription ()Ljava/lang/String;
|
||||||
|
public final fun getName ()Ljava/lang/String;
|
||||||
|
public final fun getOptions ()Ljava/util/Map;
|
||||||
|
public final fun getRequiresIntegrations ()Z
|
||||||
|
public final fun getUse ()Z
|
||||||
|
public final fun setRequiresIntegrations (Z)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$Companion {
|
||||||
|
public final fun fromPatch (Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption {
|
||||||
|
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion;
|
||||||
|
public final fun getDefault ()Ljava/lang/Object;
|
||||||
|
public final fun getDescription ()Ljava/lang/String;
|
||||||
|
public final fun getKey ()Ljava/lang/String;
|
||||||
|
public final fun getRequired ()Z
|
||||||
|
public final fun getTitle ()Ljava/lang/String;
|
||||||
|
public final fun getValueType ()Ljava/lang/String;
|
||||||
|
public final fun getValues ()Ljava/util/Map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion {
|
||||||
|
public final fun fromPatchOption (Lapp/revanced/patcher/patch/options/PatchOption;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class app/revanced/library/PatchUtils$Json$JsonPatch {
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class app/revanced/library/adb/AdbManager {
|
public abstract class app/revanced/library/adb/AdbManager {
|
||||||
public static final field Companion Lapp/revanced/library/adb/AdbManager$Companion;
|
public static final field Companion Lapp/revanced/library/adb/AdbManager$Companion;
|
||||||
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 1.4.0-dev.1
|
version = 1.5.0-dev.2
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ apksig = "8.1.4"
|
|||||||
bcpkix-jdk18on = "1.76"
|
bcpkix-jdk18on = "1.76"
|
||||||
jackson-module-kotlin = "2.14.3"
|
jackson-module-kotlin = "2.14.3"
|
||||||
jadb = "1.2.1"
|
jadb = "1.2.1"
|
||||||
kotlin-reflect = "1.9.10"
|
kotlin-reflect = "1.9.20"
|
||||||
kotlin-test = "1.9.10"
|
kotlin-test = "1.9.20"
|
||||||
revanced-patcher = "19.0.0"
|
revanced-patcher = "19.1.0"
|
||||||
binary-compatibility-validator = "0.13.2"
|
binary-compatibility-validator = "0.13.2"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|||||||
@@ -3,24 +3,22 @@
|
|||||||
package app.revanced.library
|
package app.revanced.library
|
||||||
|
|
||||||
import app.revanced.library.Options.Patch.Option
|
import app.revanced.library.Options.Patch.Option
|
||||||
import app.revanced.patcher.PatchClass
|
|
||||||
import app.revanced.patcher.PatchSet
|
import app.revanced.patcher.PatchSet
|
||||||
import app.revanced.patcher.patch.options.PatchOptionException
|
import app.revanced.patcher.patch.options.PatchOptionException
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
private typealias PatchList = List<PatchClass>
|
@Suppress("unused")
|
||||||
|
|
||||||
object Options {
|
object Options {
|
||||||
private val logger = Logger.getLogger(Options::class.java.name)
|
private val logger = Logger.getLogger(Options::class.java.name)
|
||||||
|
|
||||||
private var mapper = jacksonObjectMapper()
|
private val mapper = jacksonObjectMapper()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes the options for the patches in the list.
|
* Serializes the options for a set of patches.
|
||||||
*
|
*
|
||||||
* @param patches The list of patches to serialize.
|
* @param patches The set of patches to serialize.
|
||||||
* @param prettyPrint Whether to pretty print the JSON.
|
* @param prettyPrint Whether to pretty print the JSON.
|
||||||
* @return The JSON string containing the options.
|
* @return The JSON string containing the options.
|
||||||
*/
|
*/
|
||||||
@@ -57,17 +55,16 @@ object Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes the options for the patches in the list.
|
* Deserializes the options to a set of patches.
|
||||||
*
|
*
|
||||||
* @param json The JSON string containing the options.
|
* @param json The JSON string containing the options.
|
||||||
* @return The list of [Patch]s.
|
* @return A set of [Patch]s.
|
||||||
* @see Patch
|
* @see Patch
|
||||||
* @see PatchList
|
|
||||||
*/
|
*/
|
||||||
fun deserialize(json: String): Array<Patch> = mapper.readValue(json, Array<Patch>::class.java)
|
fun deserialize(json: String): Array<Patch> = mapper.readValue(json, Array<Patch>::class.java)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the options for the patches in the list.
|
* Sets the options for a set of patches.
|
||||||
*
|
*
|
||||||
* @param json The JSON string containing the options.
|
* @param json The JSON string containing the options.
|
||||||
*/
|
*/
|
||||||
@@ -95,7 +92,7 @@ object Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the options for the patches in the list.
|
* Sets the options for a set of patches.
|
||||||
*
|
*
|
||||||
* @param file The file containing the JSON string containing the options.
|
* @param file The file containing the JSON string containing the options.
|
||||||
* @see setOptions
|
* @see setOptions
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
package app.revanced.library
|
package app.revanced.library
|
||||||
|
|
||||||
|
import app.revanced.patcher.PatchClass
|
||||||
import app.revanced.patcher.PatchSet
|
import app.revanced.patcher.PatchSet
|
||||||
import java.util.*
|
import app.revanced.patcher.patch.Patch
|
||||||
|
import app.revanced.patcher.patch.options.PatchOption
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
private typealias PackageName = String
|
typealias PackageName = String
|
||||||
private typealias Version = String
|
typealias Version = String
|
||||||
private typealias Count = Int
|
typealias Count = Int
|
||||||
|
|
||||||
private typealias VersionMap = SortedMap<Version, Count>
|
typealias VersionMap = LinkedHashMap<Version, Count>
|
||||||
internal typealias PackageNameMap = Map<PackageName, VersionMap>
|
typealias PackageNameMap = Map<PackageName, VersionMap>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions for working with patches.
|
* Utility functions for working with patches.
|
||||||
@@ -48,30 +53,146 @@ object PatchUtils {
|
|||||||
* Get the count of versions for each compatible package from a supplied set of [patches] ordered by the most common version.
|
* Get the count of versions for each compatible package from a supplied set of [patches] ordered by the most common version.
|
||||||
*
|
*
|
||||||
* @param patches The set of patches to check.
|
* @param patches The set of patches to check.
|
||||||
* @param packageNames The names of the compatible packages.
|
* @param packageNames The names of the compatible packages to include. If null, all packages will be included.
|
||||||
* @param countUnusedPatches Whether to count patches that are not used.
|
* @param countUnusedPatches Whether to count patches that are not used.
|
||||||
* @return A map of package names to a map of versions to their count.
|
* @return A map of package names to a map of versions to their count.
|
||||||
*/
|
*/
|
||||||
fun getMostCommonCompatibleVersions(
|
fun getMostCommonCompatibleVersions(
|
||||||
patches: PatchSet,
|
patches: PatchSet,
|
||||||
packageNames: Set<String>,
|
packageNames: Set<String>? = null,
|
||||||
countUnusedPatches: Boolean = false,
|
countUnusedPatches: Boolean = false,
|
||||||
): PackageNameMap {
|
): PackageNameMap =
|
||||||
val wantedPackages = packageNames.toHashSet()
|
buildMap {
|
||||||
return buildMap {
|
fun filterWantedPackages(compatiblePackages: Iterable<Patch.CompatiblePackage>): Iterable<Patch.CompatiblePackage> {
|
||||||
|
val wantedPackages = packageNames?.toHashSet() ?: return compatiblePackages
|
||||||
|
return compatiblePackages.filter { it.name in wantedPackages }
|
||||||
|
}
|
||||||
|
|
||||||
patches
|
patches
|
||||||
.filter { it.use || countUnusedPatches }
|
.filter { it.use || countUnusedPatches }
|
||||||
.flatMap { it.compatiblePackages ?: emptyList() }
|
.flatMap { it.compatiblePackages ?: emptyList() }
|
||||||
.filter { it.name in wantedPackages }
|
.let(::filterWantedPackages)
|
||||||
.forEach { compatiblePackage ->
|
.forEach { compatiblePackage ->
|
||||||
compatiblePackage.versions?.let { versions ->
|
if (compatiblePackage.versions?.isEmpty() == true) {
|
||||||
val versionMap = getOrPut(compatiblePackage.name) { sortedMapOf() }
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
val versionMap = getOrPut(compatiblePackage.name) { linkedMapOf() }
|
||||||
|
|
||||||
|
compatiblePackage.versions?.let { versions ->
|
||||||
versions.forEach { version ->
|
versions.forEach { version ->
|
||||||
versionMap[version] = versionMap.getOrDefault(version, 0) + 1
|
versionMap[version] = versionMap.getOrDefault(version, 0) + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort the version maps by the most common version.
|
||||||
|
forEach { (packageName, versionMap) ->
|
||||||
|
this[packageName] =
|
||||||
|
versionMap
|
||||||
|
.asIterable()
|
||||||
|
.sortedWith(compareByDescending { it.value })
|
||||||
|
.associate { it.key to it.value } as VersionMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Json {
|
||||||
|
private val mapper = jacksonObjectMapper()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes a set of [Patch]es to a JSON string and writes it to an output stream.
|
||||||
|
*
|
||||||
|
* @param patches The set of [Patch]es to serialize.
|
||||||
|
* @param transform A function to transform the [Patch]es to [JsonPatch]es.
|
||||||
|
* @param prettyPrint Whether to pretty print the JSON.
|
||||||
|
* @param outputStream The output stream to write the JSON to.
|
||||||
|
*/
|
||||||
|
fun serialize(
|
||||||
|
patches: PatchSet,
|
||||||
|
transform: (Patch<*>) -> JsonPatch = { patch -> FullJsonPatch.fromPatch(patch) },
|
||||||
|
prettyPrint: Boolean = false,
|
||||||
|
outputStream: OutputStream,
|
||||||
|
) {
|
||||||
|
patches.map(transform).let { transformed ->
|
||||||
|
if (prettyPrint) {
|
||||||
|
mapper.writerWithDefaultPrettyPrinter().writeValue(outputStream, transformed)
|
||||||
|
} else {
|
||||||
|
mapper.writeValue(outputStream, transformed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes a JSON string to a set of [FullJsonPatch]es from an input stream.
|
||||||
|
*
|
||||||
|
* @param inputStream The input stream to read the JSON from.
|
||||||
|
* @param jsonPatchElementClass The class of the [JsonPatch]es to deserialize.
|
||||||
|
* @return A set of [JsonPatch]es.
|
||||||
|
* @see FullJsonPatch
|
||||||
|
*/
|
||||||
|
fun <T : JsonPatch> deserialize(
|
||||||
|
inputStream: InputStream,
|
||||||
|
jsonPatchElementClass: Class<T>,
|
||||||
|
): Set<T> =
|
||||||
|
mapper.readValue(
|
||||||
|
inputStream,
|
||||||
|
mapper.typeFactory.constructCollectionType(Set::class.java, jsonPatchElementClass),
|
||||||
|
)
|
||||||
|
|
||||||
|
interface JsonPatch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JSON representation of a [Patch].
|
||||||
|
* @see Patch
|
||||||
|
*/
|
||||||
|
class FullJsonPatch internal constructor(
|
||||||
|
val name: String?,
|
||||||
|
val description: String?,
|
||||||
|
val compatiblePackages: Set<Patch.CompatiblePackage>?,
|
||||||
|
val dependencies: Set<PatchClass>?,
|
||||||
|
val use: Boolean,
|
||||||
|
var requiresIntegrations: Boolean,
|
||||||
|
val options: Map<String, FullJsonPatchOption<*>>,
|
||||||
|
) : JsonPatch {
|
||||||
|
companion object {
|
||||||
|
fun fromPatch(patch: Patch<*>) =
|
||||||
|
FullJsonPatch(
|
||||||
|
patch.name,
|
||||||
|
patch.description,
|
||||||
|
patch.compatiblePackages,
|
||||||
|
patch.dependencies,
|
||||||
|
patch.use,
|
||||||
|
patch.requiresIntegrations,
|
||||||
|
patch.options.mapValues { FullJsonPatchOption.fromPatchOption(it.value) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JSON representation of a [PatchOption].
|
||||||
|
* @see PatchOption
|
||||||
|
*/
|
||||||
|
class FullJsonPatchOption<T> internal constructor(
|
||||||
|
val key: String,
|
||||||
|
val default: T?,
|
||||||
|
val values: Map<String, T?>?,
|
||||||
|
val title: String?,
|
||||||
|
val description: String?,
|
||||||
|
val required: Boolean,
|
||||||
|
val valueType: String,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun fromPatchOption(option: PatchOption<*>) =
|
||||||
|
FullJsonPatchOption(
|
||||||
|
option.key,
|
||||||
|
option.default,
|
||||||
|
option.values,
|
||||||
|
option.title,
|
||||||
|
option.description,
|
||||||
|
option.required,
|
||||||
|
option.valueType,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import app.revanced.library.adb.Constants.CREATE_DIR
|
|||||||
import app.revanced.library.adb.Constants.DELETE
|
import app.revanced.library.adb.Constants.DELETE
|
||||||
import app.revanced.library.adb.Constants.GET_INSTALLED_PATH
|
import app.revanced.library.adb.Constants.GET_INSTALLED_PATH
|
||||||
import app.revanced.library.adb.Constants.INSTALLATION_PATH
|
import app.revanced.library.adb.Constants.INSTALLATION_PATH
|
||||||
import app.revanced.library.adb.Constants.INSTALL_MOUNT
|
import app.revanced.library.adb.Constants.INSTALL_MOUNT_SCRIPT
|
||||||
import app.revanced.library.adb.Constants.INSTALL_PATCHED_APK
|
import app.revanced.library.adb.Constants.INSTALL_PATCHED_APK
|
||||||
import app.revanced.library.adb.Constants.MOUNT_PATH
|
import app.revanced.library.adb.Constants.KILL
|
||||||
import app.revanced.library.adb.Constants.MOUNT_SCRIPT
|
import app.revanced.library.adb.Constants.MOUNT_SCRIPT
|
||||||
|
import app.revanced.library.adb.Constants.MOUNT_SCRIPT_PATH
|
||||||
import app.revanced.library.adb.Constants.PATCHED_APK_PATH
|
import app.revanced.library.adb.Constants.PATCHED_APK_PATH
|
||||||
import app.revanced.library.adb.Constants.PLACEHOLDER
|
import app.revanced.library.adb.Constants.PLACEHOLDER
|
||||||
import app.revanced.library.adb.Constants.RESTART
|
import app.revanced.library.adb.Constants.RESTART
|
||||||
@@ -104,9 +105,8 @@ sealed class AdbManager private constructor(deviceSerial: String?) {
|
|||||||
|
|
||||||
device.createFile(TMP_PATH, MOUNT_SCRIPT.applyReplacement(packageName))
|
device.createFile(TMP_PATH, MOUNT_SCRIPT.applyReplacement(packageName))
|
||||||
|
|
||||||
device.run(INSTALL_MOUNT, packageName).waitFor()
|
device.run(INSTALL_MOUNT_SCRIPT, packageName).waitFor()
|
||||||
device.run(UMOUNT, packageName).waitFor() // Sanity check.
|
device.run(MOUNT_SCRIPT_PATH, packageName).waitFor()
|
||||||
device.run(MOUNT_PATH, packageName).waitFor()
|
|
||||||
device.run(RESTART, packageName)
|
device.run(RESTART, packageName)
|
||||||
device.run(DELETE, TMP_PATH)
|
device.run(DELETE, TMP_PATH)
|
||||||
|
|
||||||
@@ -118,9 +118,9 @@ sealed class AdbManager private constructor(deviceSerial: String?) {
|
|||||||
|
|
||||||
device.run(UMOUNT, packageName)
|
device.run(UMOUNT, packageName)
|
||||||
device.run(DELETE.applyReplacement(PATCHED_APK_PATH), packageName)
|
device.run(DELETE.applyReplacement(PATCHED_APK_PATH), packageName)
|
||||||
device.run(DELETE, MOUNT_PATH.applyReplacement(packageName))
|
device.run(DELETE, MOUNT_SCRIPT_PATH.applyReplacement(packageName))
|
||||||
device.run(DELETE, TMP_PATH)
|
device.run(DELETE, TMP_PATH)
|
||||||
device.run(RESTART, packageName)
|
device.run(KILL, packageName)
|
||||||
|
|
||||||
super.uninstall(packageName)
|
super.uninstall(packageName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ internal object Constants {
|
|||||||
internal const val TMP_PATH = "/data/local/tmp/revanced.tmp"
|
internal const val TMP_PATH = "/data/local/tmp/revanced.tmp"
|
||||||
internal const val INSTALLATION_PATH = "/data/adb/revanced/"
|
internal const val INSTALLATION_PATH = "/data/adb/revanced/"
|
||||||
internal const val PATCHED_APK_PATH = "$INSTALLATION_PATH$PLACEHOLDER.apk"
|
internal const val PATCHED_APK_PATH = "$INSTALLATION_PATH$PLACEHOLDER.apk"
|
||||||
internal const val MOUNT_PATH = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
|
internal const val MOUNT_SCRIPT_PATH = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
|
||||||
|
|
||||||
internal const val DELETE = "rm -rf $PLACEHOLDER"
|
internal const val DELETE = "rm -rf $PLACEHOLDER"
|
||||||
internal const val CREATE_DIR = "mkdir -p"
|
internal const val CREATE_DIR = "mkdir -p"
|
||||||
internal const val RESTART = "am start -S $PLACEHOLDER"
|
internal const val RESTART = "am start -S $PLACEHOLDER"
|
||||||
|
internal const val KILL = "am force-stop $PLACEHOLDER"
|
||||||
internal const val GET_INSTALLED_PATH = "pm path $PLACEHOLDER"
|
internal const val GET_INSTALLED_PATH = "pm path $PLACEHOLDER"
|
||||||
|
|
||||||
internal const val INSTALL_PATCHED_APK =
|
internal const val INSTALL_PATCHED_APK =
|
||||||
@@ -23,7 +24,7 @@ internal object Constants {
|
|||||||
internal const val UMOUNT =
|
internal const val UMOUNT =
|
||||||
"grep $PLACEHOLDER /proc/mounts | while read -r line; do echo ${'$'}line | cut -d ' ' -f 2 | sed 's/apk.*/apk/' | xargs -r umount -l; done"
|
"grep $PLACEHOLDER /proc/mounts | while read -r line; do echo ${'$'}line | cut -d ' ' -f 2 | sed 's/apk.*/apk/' | xargs -r umount -l; done"
|
||||||
|
|
||||||
internal const val INSTALL_MOUNT = "mv $TMP_PATH $MOUNT_PATH && chmod +x $MOUNT_PATH"
|
internal const val INSTALL_MOUNT_SCRIPT = "mv $TMP_PATH $MOUNT_SCRIPT_PATH && chmod +x $MOUNT_SCRIPT_PATH"
|
||||||
|
|
||||||
internal val MOUNT_SCRIPT =
|
internal val MOUNT_SCRIPT =
|
||||||
"""
|
"""
|
||||||
@@ -33,11 +34,17 @@ internal object Constants {
|
|||||||
|
|
||||||
until [ "$( getprop sys.boot_completed )" = 1 ]; do sleep 3; done
|
until [ "$( getprop sys.boot_completed )" = 1 ]; do sleep 3; done
|
||||||
until [ -d "/sdcard/Android" ]; do sleep 1; done
|
until [ -d "/sdcard/Android" ]; do sleep 1; done
|
||||||
|
|
||||||
|
# Unmount any existing mount as a safety measure
|
||||||
|
$UMOUNT
|
||||||
|
|
||||||
base_path="$PATCHED_APK_PATH"
|
base_path="$PATCHED_APK_PATH"
|
||||||
stock_path=$( pm path $PLACEHOLDER | grep base | sed 's/package://g' )
|
stock_path=$( pm path $PLACEHOLDER | grep base | sed 's/package://g' )
|
||||||
|
|
||||||
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
|
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
|
||||||
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path
|
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path
|
||||||
|
|
||||||
|
# Kill the app to force it to restart the mounted APK in case it's already running
|
||||||
|
$KILL
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,36 +4,75 @@ import app.revanced.patcher.PatchSet
|
|||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.Patch
|
import app.revanced.patcher.patch.Patch
|
||||||
|
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption
|
||||||
|
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.intArrayPatchOption
|
||||||
|
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal object PatchUtilsTest {
|
internal object PatchUtilsTest {
|
||||||
private val patches =
|
private val patches =
|
||||||
arrayOf(
|
arrayOf(
|
||||||
newPatch("some.package", "a"),
|
newPatch("some.package", setOf("a")) { stringPatchOption("string", "value") },
|
||||||
newPatch("some.package", "a", "b", use = false),
|
newPatch("some.package", setOf("a", "b"), use = false),
|
||||||
newPatch("some.package", "a", "b", "c", use = false),
|
newPatch("some.package", setOf("a", "b", "c"), use = false),
|
||||||
newPatch("some.other.package", "b", use = false),
|
newPatch("some.other.package", setOf("b"), use = false),
|
||||||
newPatch("some.other.package", "b", "c"),
|
newPatch("some.other.package", setOf("b", "c")) { booleanPatchOption("bool", true) },
|
||||||
newPatch("some.other.package", "b", "c", "d"),
|
newPatch("some.other.package", setOf("b", "c", "d")),
|
||||||
newPatch("some.other.other.package"),
|
newPatch("some.other.other.package") { intArrayPatchOption("intArray", arrayOf(1, 2, 3)) },
|
||||||
newPatch("some.other.other.package", "a"),
|
newPatch("some.other.other.package", setOf("a")),
|
||||||
newPatch("some.other.other.package", "b"),
|
newPatch("some.other.other.package", setOf("b")),
|
||||||
newPatch("some.other.other.other.package", use = false),
|
newPatch("some.other.other.other.package", use = false),
|
||||||
newPatch("some.other.other.other.package", use = false),
|
newPatch("some.other.other.other.package", use = false),
|
||||||
).toSet()
|
).toSet()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `return common versions correctly ordered for each package`() {
|
fun `empty because package is incompatible with any version`() {
|
||||||
assertEqualsVersions(
|
assertEqualsVersions(
|
||||||
expected =
|
expected = emptyMap(),
|
||||||
mapOf(
|
patches = setOf(newPatch("some.package", emptySet(), use = true)),
|
||||||
"some.package" to sortedMapOf("a" to 3, "b" to 2, "c" to 1),
|
compatiblePackageNames = setOf("some.package"),
|
||||||
"some.other.package" to sortedMapOf("b" to 3, "c" to 2, "d" to 1),
|
)
|
||||||
"some.other.other.package" to sortedMapOf("a" to 1, "b" to 1),
|
}
|
||||||
"some.other.other.other.package" to sortedMapOf(),
|
|
||||||
),
|
@Test
|
||||||
|
fun `empty list of versions because package is unconstrained to any version`() {
|
||||||
|
assertEqualsVersions(
|
||||||
|
expected = mapOf("some.package" to linkedMapOf()),
|
||||||
|
patches = setOf(newPatch("some.package")),
|
||||||
|
compatiblePackageNames = setOf("some.package"),
|
||||||
|
countUnusedPatches = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `empty because no known package was supplied`() {
|
||||||
|
assertEqualsVersions(
|
||||||
|
expected = emptyMap(),
|
||||||
patches,
|
patches,
|
||||||
|
compatiblePackageNames = setOf("unknown.package"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `common versions correctly ordered for each package`() {
|
||||||
|
fun assertEqualsExpected(compatiblePackageNames: Set<String>?) =
|
||||||
|
assertEqualsVersions(
|
||||||
|
expected =
|
||||||
|
mapOf(
|
||||||
|
"some.package" to linkedMapOf("a" to 3, "b" to 2, "c" to 1),
|
||||||
|
"some.other.package" to linkedMapOf("b" to 3, "c" to 2, "d" to 1),
|
||||||
|
"some.other.other.package" to linkedMapOf("a" to 1, "b" to 1),
|
||||||
|
"some.other.other.other.package" to linkedMapOf(),
|
||||||
|
),
|
||||||
|
patches,
|
||||||
|
compatiblePackageNames,
|
||||||
|
countUnusedPatches = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEqualsExpected(
|
||||||
compatiblePackageNames =
|
compatiblePackageNames =
|
||||||
setOf(
|
setOf(
|
||||||
"some.package",
|
"some.package",
|
||||||
@@ -41,18 +80,21 @@ internal object PatchUtilsTest {
|
|||||||
"some.other.other.package",
|
"some.other.other.package",
|
||||||
"some.other.other.other.package",
|
"some.other.other.other.package",
|
||||||
),
|
),
|
||||||
countUnusedPatches = true,
|
)
|
||||||
|
|
||||||
|
assertEqualsExpected(
|
||||||
|
compatiblePackageNames = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `return common versions correctly ordered for each package without counting unused patches`() {
|
fun `common versions correctly ordered for each package without counting unused patches`() {
|
||||||
assertEqualsVersions(
|
assertEqualsVersions(
|
||||||
expected =
|
expected =
|
||||||
mapOf(
|
mapOf(
|
||||||
"some.package" to sortedMapOf("a" to 1),
|
"some.package" to linkedMapOf("a" to 1),
|
||||||
"some.other.package" to sortedMapOf("b" to 2, "c" to 2, "d" to 1),
|
"some.other.package" to linkedMapOf("b" to 2, "c" to 2, "d" to 1),
|
||||||
"some.other.other.package" to sortedMapOf("a" to 1, "b" to 1),
|
"some.other.other.package" to linkedMapOf("a" to 1, "b" to 1),
|
||||||
),
|
),
|
||||||
patches,
|
patches,
|
||||||
compatiblePackageNames =
|
compatiblePackageNames =
|
||||||
@@ -66,30 +108,11 @@ internal object PatchUtilsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `return an empty map because no known package was supplied`() {
|
|
||||||
assertEqualsVersions(
|
|
||||||
expected = emptyMap(),
|
|
||||||
patches,
|
|
||||||
compatiblePackageNames = setOf("unknown.package"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `return empty set of versions because no compatible package is constrained to a version`() {
|
|
||||||
assertEqualsVersions(
|
|
||||||
expected = mapOf("some.package" to sortedMapOf()),
|
|
||||||
patches = setOf(newPatch("some.package")),
|
|
||||||
compatiblePackageNames = setOf("some.package"),
|
|
||||||
countUnusedPatches = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `return 'a' because it is the most common version`() {
|
fun `return 'a' because it is the most common version`() {
|
||||||
val patches =
|
val patches =
|
||||||
arrayOf("a", "a", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d")
|
arrayOf("a", "a", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d")
|
||||||
.map { version -> newPatch("some.package", version) }
|
.map { version -> newPatch("some.package", setOf(version)) }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
assertEqualsVersion("a", patches, "some.package")
|
assertEqualsVersion("a", patches, "some.package")
|
||||||
@@ -102,7 +125,7 @@ internal object PatchUtilsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `return null because no patch is compatible with the supplied package name`() {
|
fun `return null because no patch is compatible with the supplied package name`() {
|
||||||
val patches = setOf(newPatch("some.package", "a"))
|
val patches = setOf(newPatch("some.package", setOf("a")))
|
||||||
|
|
||||||
assertEqualsVersion(null, patches, "other.package")
|
assertEqualsVersion(null, patches, "other.package")
|
||||||
}
|
}
|
||||||
@@ -118,10 +141,24 @@ internal object PatchUtilsTest {
|
|||||||
assertEqualsVersion(null, patches, "other.package")
|
assertEqualsVersion(null, patches, "other.package")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `serializes to and deserializes from JSON string correctly`() {
|
||||||
|
val out = ByteArrayOutputStream()
|
||||||
|
PatchUtils.Json.serialize(patches, outputStream = out)
|
||||||
|
|
||||||
|
val deserialized =
|
||||||
|
PatchUtils.Json.deserialize(
|
||||||
|
ByteArrayInputStream(out.toByteArray()),
|
||||||
|
PatchUtils.Json.FullJsonPatch::class.java,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(patches.size == deserialized.size)
|
||||||
|
}
|
||||||
|
|
||||||
private fun assertEqualsVersions(
|
private fun assertEqualsVersions(
|
||||||
expected: PackageNameMap,
|
expected: PackageNameMap,
|
||||||
patches: PatchSet,
|
patches: PatchSet,
|
||||||
compatiblePackageNames: Set<String>,
|
compatiblePackageNames: Set<String>?,
|
||||||
countUnusedPatches: Boolean = false,
|
countUnusedPatches: Boolean = false,
|
||||||
) = assertEquals(
|
) = assertEquals(
|
||||||
expected,
|
expected,
|
||||||
@@ -135,6 +172,7 @@ internal object PatchUtilsTest {
|
|||||||
) {
|
) {
|
||||||
// Test both the deprecated and the new method.
|
// Test both the deprecated and the new method.
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
assertEquals(
|
assertEquals(
|
||||||
expected,
|
expected,
|
||||||
PatchUtils.getMostCommonCompatibleVersion(patches, compatiblePackageName),
|
PatchUtils.getMostCommonCompatibleVersion(patches, compatiblePackageName),
|
||||||
@@ -149,21 +187,16 @@ internal object PatchUtilsTest {
|
|||||||
|
|
||||||
private fun newPatch(
|
private fun newPatch(
|
||||||
packageName: String,
|
packageName: String,
|
||||||
vararg versions: String,
|
versions: Set<String>? = null,
|
||||||
use: Boolean = true,
|
use: Boolean = true,
|
||||||
) = object : BytecodePatch() {
|
options: Patch<*>.() -> Unit = {},
|
||||||
|
) = object : BytecodePatch(
|
||||||
|
name = "test",
|
||||||
|
compatiblePackages = setOf(CompatiblePackage(packageName, versions?.toSet())),
|
||||||
|
use = use,
|
||||||
|
) {
|
||||||
init {
|
init {
|
||||||
// Set the compatible packages field to the supplied package name and versions reflectively,
|
options()
|
||||||
// because the setter is private but needed for testing.
|
|
||||||
val compatiblePackagesField = Patch::class.java.getDeclaredField("compatiblePackages")
|
|
||||||
|
|
||||||
compatiblePackagesField.isAccessible = true
|
|
||||||
compatiblePackagesField.set(this, setOf(CompatiblePackage(packageName, versions.toSet())))
|
|
||||||
|
|
||||||
val useField = Patch::class.java.getDeclaredField("use")
|
|
||||||
|
|
||||||
useField.isAccessible = true
|
|
||||||
useField.set(this, use)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {}
|
override fun execute(context: BytecodeContext) {}
|
||||||
|
|||||||
Reference in New Issue
Block a user