You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-09-06 16:38:50 +02:00
Compare commits
124 Commits
v1.0.0-dev
...
v1.0.0-dev
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8b4f3947f8 | ||
![]() |
4d74de4061 | ||
![]() |
4fbee7d255 | ||
![]() |
fd9f639605 | ||
![]() |
9084ccc2a2 | ||
![]() |
83a8a48176 | ||
![]() |
66b08f8b3a | ||
![]() |
e286ba5090 | ||
![]() |
e5c054ac2f | ||
![]() |
cb0741d05f | ||
![]() |
38556d61ab | ||
![]() |
ce8021b482 | ||
![]() |
243dba7751 | ||
![]() |
698f759979 | ||
![]() |
1701da3dde | ||
![]() |
37fa9949ec | ||
![]() |
ac36d19693 | ||
![]() |
c245edb0c5 | ||
![]() |
1f7bf3ac6c | ||
![]() |
bfeeaf4435 | ||
![]() |
748d0abad0 | ||
![]() |
569238ab76 | ||
![]() |
23197879b2 | ||
![]() |
305a81793a | ||
![]() |
33f9211f98 | ||
![]() |
864e38c069 | ||
![]() |
659e1087c9 | ||
![]() |
03700ffa51 | ||
![]() |
ae06d826e8 | ||
![]() |
5ca5188fc2 | ||
![]() |
f88c11820d | ||
![]() |
93e81ff047 | ||
![]() |
d49df10a3c | ||
![]() |
04b49b8b66 | ||
![]() |
5ddc63f979 | ||
![]() |
82b1e66d54 | ||
![]() |
fd630cd429 | ||
![]() |
f4a47d4dc8 | ||
![]() |
3bfc24fc16 | ||
![]() |
25bba2c1d8 | ||
![]() |
4dea27e831 | ||
![]() |
a0d6d46217 | ||
![]() |
643a14e664 | ||
![]() |
355e6d82cc | ||
![]() |
df7503b47b | ||
![]() |
a01dded092 | ||
![]() |
9ae95174e6 | ||
![]() |
e161f7fea4 | ||
![]() |
200e3c9fdb | ||
![]() |
f0f34031dd | ||
![]() |
560c485ab0 | ||
![]() |
cc5a414692 | ||
![]() |
c2a334eb3f | ||
![]() |
1b2fbbca26 | ||
![]() |
4458141d6d | ||
![]() |
8544fc4cbc | ||
![]() |
a492808021 | ||
![]() |
0204eee79e | ||
![]() |
4022b8b847 | ||
![]() |
8daf877fac | ||
![]() |
7d38bb0baa | ||
![]() |
5f71a342ac | ||
![]() |
866b03af21 | ||
![]() |
4c1a42b216 | ||
![]() |
264989f488 | ||
![]() |
4281546f69 | ||
![]() |
af4f2396c7 | ||
![]() |
147195647c | ||
![]() |
433914feda | ||
![]() |
622138736d | ||
![]() |
aed4fd9a3c | ||
![]() |
32e645850d | ||
![]() |
e45fc02aae | ||
![]() |
e0d29cf450 | ||
![]() |
2b888e381c | ||
![]() |
f72dd68ec5 | ||
![]() |
3b68d5c65e | ||
![]() |
eed1cfda7b | ||
![]() |
8b70bb4290 | ||
![]() |
dbda641d0c | ||
![]() |
5ae5e98f1f | ||
![]() |
1ba40ab1cb | ||
![]() |
e9c119ebb1 | ||
![]() |
1bd6d1d5b8 | ||
![]() |
4e7378bd79 | ||
![]() |
28ed4793e3 | ||
![]() |
312235b194 | ||
![]() |
6ab21e5891 | ||
![]() |
db8d1150c3 | ||
![]() |
8f778f38fe | ||
![]() |
88a6a27302 | ||
![]() |
a9e4e8ac32 | ||
![]() |
d5e694c306 | ||
![]() |
dde0a22642 | ||
![]() |
9a67aa3ff4 | ||
![]() |
e69708f21e | ||
![]() |
c49071aff7 | ||
![]() |
d15240d033 | ||
![]() |
6767c8fbc1 | ||
![]() |
4543b36616 | ||
![]() |
ec6d462ade | ||
![]() |
84bc7e0dc7 | ||
![]() |
6ad51aad9a | ||
![]() |
b711b8001e | ||
![]() |
12c10d8c64 | ||
![]() |
05e44007d8 | ||
![]() |
dbafe2ab37 | ||
![]() |
45a885dbde | ||
![]() |
78235d1abe | ||
![]() |
aec5eeb597 | ||
![]() |
d98c9eeb30 | ||
![]() |
f8e978af88 | ||
![]() |
86cb053566 | ||
![]() |
c1ccb70de4 | ||
![]() |
bb42fa3c6f | ||
![]() |
2d3c61113d | ||
![]() |
6bc4e7eab7 | ||
![]() |
be51f42710 | ||
![]() |
fa0412985c | ||
![]() |
0048788dd0 | ||
![]() |
47eb493f54 | ||
![]() |
6b1337e4fc | ||
![]() |
f4589db3a9 | ||
![]() |
1af31b2aa3 |
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Setup JDK
|
- name: Setup JDK
|
||||||
uses: actions/setup-java@v2
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: '8'
|
java-version: '17'
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
cache: gradle
|
cache: gradle
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
@@ -30,6 +30,8 @@ jobs:
|
|||||||
- name: Make gradlew executable
|
- name: Make gradlew executable
|
||||||
run: chmod +x gradlew
|
run: chmod +x gradlew
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
- name: Setup semantic-release
|
- name: Setup semantic-release
|
||||||
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
||||||
|
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -4,7 +4,7 @@
|
|||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
113
CHANGELOG.md
113
CHANGELOG.md
@@ -1,3 +1,116 @@
|
|||||||
|
# [1.0.0-dev.10](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.9...v1.0.0-dev.10) (2022-05-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* qualifying `Element` with wrong package ([4d74de4](https://github.com/revanced/revanced-patcher/commit/4d74de4061f26c0d7c17fabd849051b429d86033))
|
||||||
|
|
||||||
|
# [1.0.0-dev.9](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.8...v1.0.0-dev.9) (2022-05-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* `compareSignatureToMethod` not matching correctly in case opcodes are null ([5ae5e98](https://github.com/revanced/revanced-patcher/commit/5ae5e98f1f8e174d800bcc75723e1ed965d66196))
|
||||||
|
* `ConcurrentModificationException` while iterating through `proxies` and modifying it ([bfeeaf4](https://github.com/revanced/revanced-patcher/commit/bfeeaf443549c9a43279d83a0628c061a382beb9))
|
||||||
|
* `PackageMetadata` ([305a817](https://github.com/revanced/revanced-patcher/commit/305a81793a9a04fe4e8969f2d3b591b0f01e3b63))
|
||||||
|
* `replaceWith` not replacing classes with used class proxies ([f0f3403](https://github.com/revanced/revanced-patcher/commit/f0f34031dd4e618223f016f7c427d7c93ab8456a))
|
||||||
|
* adding existing classes to the patchers cache ([4281546](https://github.com/revanced/revanced-patcher/commit/4281546f69225ee90ec4c003f4313df41edf71a6))
|
||||||
|
* always return PatchResultSuccess on patch success ([866b03a](https://github.com/revanced/revanced-patcher/commit/866b03af217ad97dd2755bfdc0ffe5bcf723c949))
|
||||||
|
* applying no patches throwing error ([f88c118](https://github.com/revanced/revanced-patcher/commit/f88c11820dbdc0d1d52a49c9bcdb4f7caa9eb6eb))
|
||||||
|
* applyPatches not returning successful patches ([8b70bb4](https://github.com/revanced/revanced-patcher/commit/8b70bb42909434a5e59315502f6d54d7c7691f18))
|
||||||
|
* Classes not being written properly because of array shifting ([1471956](https://github.com/revanced/revanced-patcher/commit/147195647c3990ab78ba95e4b3000650e718b713))
|
||||||
|
* failing tests temporarily ([66b08f8](https://github.com/revanced/revanced-patcher/commit/66b08f8b3a8f31844c7e7bab4df4243521d4a431))
|
||||||
|
* fix classes having multiple instances of fields ([b711b80](https://github.com/revanced/revanced-patcher/commit/b711b8001e4845857fa6cc71b107f1c553b31e80))
|
||||||
|
* fix classes having multiple method instances ([12c10d8](https://github.com/revanced/revanced-patcher/commit/12c10d8c64422c4534c23467e367707e3b953f82))
|
||||||
|
* Fixed writer & signature resolver, improved tests & speed, minor refactoring ([bb42fa3](https://github.com/revanced/revanced-patcher/commit/bb42fa3c6f59b78a7223fc70edbe598ec181ee37))
|
||||||
|
* fuzzy resolver warning params were turned around ([d49df10](https://github.com/revanced/revanced-patcher/commit/d49df10a3ca6b472ce4a32d10cfe787ca243d47b))
|
||||||
|
* incorrect pattern offset ([03700ff](https://github.com/revanced/revanced-patcher/commit/03700ffa519e5f20b1a0d0ffe68f3fb504351ee5))
|
||||||
|
* make `methodMetadata` nullable in `MethodSignatureMetadata` ([864e38c](https://github.com/revanced/revanced-patcher/commit/864e38c06906a9e29271fe383d51a8ec6594a46c))
|
||||||
|
* make warnings nullable instead of lateinit ([04b49b8](https://github.com/revanced/revanced-patcher/commit/04b49b8b664e45e64e9561eca3353ffdeda91187))
|
||||||
|
* match to correct signature method parameters ([c49071a](https://github.com/revanced/revanced-patcher/commit/c49071aff78245f27c98a4760b361c30aa6340bc))
|
||||||
|
* MethodSignature#resolved throwing an exception ([82b1e66](https://github.com/revanced/revanced-patcher/commit/82b1e66d54bed1e4c335e0515b7ff3ec901fa6f8))
|
||||||
|
* Move proxy package out of cache package ([6bc4e7e](https://github.com/revanced/revanced-patcher/commit/6bc4e7eab742f5796f3041332c70495e3f993c9b))
|
||||||
|
* null check causing an exception ([560c485](https://github.com/revanced/revanced-patcher/commit/560c485ab08b08a213b58704b11b1e2f5f625080))
|
||||||
|
* Patcher not writing resolved methods ([d15240d](https://github.com/revanced/revanced-patcher/commit/d15240d0330a63c4b568fc5de3de861b8046cba4))
|
||||||
|
* reaching all constructors not possible ([37fa994](https://github.com/revanced/revanced-patcher/commit/37fa9949ec84ffd277f32b1cd554e92be41d35e4))
|
||||||
|
* remove leftover debug code ([4458141](https://github.com/revanced/revanced-patcher/commit/4458141d6d2e1b015c0d70a6e65e6c32a3cf17dc))
|
||||||
|
* return mutable set of classes ([84bc7e0](https://github.com/revanced/revanced-patcher/commit/84bc7e0dc76f0732613383accb803f2c52da98ac))
|
||||||
|
* returning failure on success ([3b68d5c](https://github.com/revanced/revanced-patcher/commit/3b68d5c65ec3082d1aa48525b4ee2a4163895a3b))
|
||||||
|
* Search method map for existing class proxy ([d5e694c](https://github.com/revanced/revanced-patcher/commit/d5e694c306a47f47b8d1078b5c9f8a742445cf7e))
|
||||||
|
* string signature in `SignatureResolver` ([ac36d19](https://github.com/revanced/revanced-patcher/commit/ac36d19693390db8f404ed30963aefb2fb7519e0))
|
||||||
|
* Suppress unused for addFiles ([a0d6d46](https://github.com/revanced/revanced-patcher/commit/a0d6d462170552929039d71eafa813fdfde215cb))
|
||||||
|
* throwing in case the opcode patterns do not match ([f72dd68](https://github.com/revanced/revanced-patcher/commit/f72dd68ec575ee0926ee668911ebb6f85b75f7d1))
|
||||||
|
* use Array instead of Iterable for methodParameters ([312235b](https://github.com/revanced/revanced-patcher/commit/312235b194cac01ddc3f03ecff32c7de4e48c29c))
|
||||||
|
* write all classes ([6ad51aa](https://github.com/revanced/revanced-patcher/commit/6ad51aad9a94d8dd5afb5e270138ef7161ccfb07))
|
||||||
|
|
||||||
|
|
||||||
|
### Code Refactoring
|
||||||
|
|
||||||
|
* bump multidexlib2 to 2.5.2.r2 ([32e6458](https://github.com/revanced/revanced-patcher/commit/32e645850d4cc74aa708984da03ae1606e696d20))
|
||||||
|
* Change all references from Array to Iterable ([264989f](https://github.com/revanced/revanced-patcher/commit/264989f48804ed637469436acf8165ac4b7be383))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add `MethodWalker` ([659e108](https://github.com/revanced/revanced-patcher/commit/659e1087c9e7a33e04cd7eb728c01ed946335810))
|
||||||
|
* add `p` naming scheme to smali compiler ([38556d6](https://github.com/revanced/revanced-patcher/commit/38556d61ab192dfa84083d935ee3e9eee5450d06))
|
||||||
|
* add extensions for cloning methods ([df7503b](https://github.com/revanced/revanced-patcher/commit/df7503b47b1e2162d6ab666f8586c633c314016f))
|
||||||
|
* add findClass method with className ([78235d1](https://github.com/revanced/revanced-patcher/commit/78235d1abe267e6aaa086662ad69af7132b8ff74))
|
||||||
|
* Add first tests ([6767c8f](https://github.com/revanced/revanced-patcher/commit/6767c8fbc15ea18a61db53e1472483632077f62a))
|
||||||
|
* add fuzzy resolver ([a492808](https://github.com/revanced/revanced-patcher/commit/a4928080217451017a99cf158fd5cc9d650a5a9e))
|
||||||
|
* add immutableMethod ([eed1cfd](https://github.com/revanced/revanced-patcher/commit/eed1cfda7b89f03f4c61ac4401707e1a12e6efb3))
|
||||||
|
* add inline smali compiler ([dbafe2a](https://github.com/revanced/revanced-patcher/commit/dbafe2ab37b25480f3e218d94ced5af2e56cba68))
|
||||||
|
* add missing test for fields ([4022b8b](https://github.com/revanced/revanced-patcher/commit/4022b8b847e8767ace0da3f98ad72ab61a4c242b))
|
||||||
|
* add or extension for AccessFlags ([aec5eeb](https://github.com/revanced/revanced-patcher/commit/aec5eeb597f0e9968b43efa228c96e83175e031c))
|
||||||
|
* Add patch metadata ([8544fc4](https://github.com/revanced/revanced-patcher/commit/8544fc4cbcb5d7c1ac0f6fcae52882a00d2bacf5)), closes [ReVancedTeam/revanced-patches#1](https://github.com/ReVancedTeam/revanced-patches/issues/1)
|
||||||
|
* Add warnings for Fuzzy resolver ([643a14e](https://github.com/revanced/revanced-patcher/commit/643a14e664c7ff86580da683eaff9c486884ee2c))
|
||||||
|
* allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called ([5f71a34](https://github.com/revanced/revanced-patcher/commit/5f71a342ac9c6aa64a4983156f595ae0832c30e8))
|
||||||
|
* Allow unknown opcodes using `null` ([f4a47d4](https://github.com/revanced/revanced-patcher/commit/f4a47d4dc893bb511ca2087a1a63bfc35888663f))
|
||||||
|
* Finish first patcher test ([a9e4e8a](https://github.com/revanced/revanced-patcher/commit/a9e4e8ac3203bdd62abcd1e366f08a2269919571))
|
||||||
|
* Improve `SignatureResolver` ([88a6a27](https://github.com/revanced/revanced-patcher/commit/88a6a2730296883e191543c2666f39f24c05d74d))
|
||||||
|
* migrate to dexlib ([be51f42](https://github.com/revanced/revanced-patcher/commit/be51f42710c1489ef4405700e56ffecee5e6552f))
|
||||||
|
* Minor refactor and return proxy, if class has been proxied already ([2d3c611](https://github.com/revanced/revanced-patcher/commit/2d3c61113dc9b76c43e93928ba11026fe0ad444e))
|
||||||
|
* properly manage `ClassProxy` & add `ProxyBackedClassList` ([2319787](https://github.com/revanced/revanced-patcher/commit/23197879b20906aac7563e5f8107305edd7ccb1b))
|
||||||
|
* remaining mutable `EncodedValue` classes ([7d38bb0](https://github.com/revanced/revanced-patcher/commit/7d38bb0baaeabade6a9e64d97e2dd6c20edd153f))
|
||||||
|
* string signature ([#22](https://github.com/revanced/revanced-patcher/issues/22)) ([c245edb](https://github.com/revanced/revanced-patcher/commit/c245edb0c5317c1bb884ea315a1a04b720f20dd5))
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* depend on `androlib` instead of `ApkDecoder` ([e5c054a](https://github.com/revanced/revanced-patcher/commit/e5c054ac2f68b00ac123a45ed56b9f150332a82d))
|
||||||
|
* do not resolve empty signatures list ([1f7bf3a](https://github.com/revanced/revanced-patcher/commit/1f7bf3ac6c77a71abd687f2ff6f7306a40654a1b))
|
||||||
|
* lazy-ify all mutable clones ([05e4400](https://github.com/revanced/revanced-patcher/commit/05e44007d81399791aa1bab1eead66b7ff662043))
|
||||||
|
* optimize indexOf call away ([f8e978a](https://github.com/revanced/revanced-patcher/commit/f8e978af888255d9c104a8275be1d9b091af3f96))
|
||||||
|
* use Set instead of List since there are no dupes ([6221387](https://github.com/revanced/revanced-patcher/commit/622138736dca6c0161171330801b7b5666594ec7))
|
||||||
|
* use String List and compare instead of any lambda ([aed4fd9](https://github.com/revanced/revanced-patcher/commit/aed4fd9a3c9e7f96c1e2c54b831c3fe7d3d720a2))
|
||||||
|
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* AccessFlag extensions not working with IDE ([e161f7f](https://github.com/revanced/revanced-patcher/commit/e161f7fea449883b7ac0fb436ed4f7f2ff78af62))
|
||||||
|
* previous commits check for dupes in dexFile, not cache ([433914f](https://github.com/revanced/revanced-patcher/commit/433914feda3066102a073d6b3bc457d0fae87911))
|
||||||
|
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* arrayOf has to be changed to listOf.
|
||||||
|
* Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
|
||||||
|
* Removed usage of ASM library
|
||||||
|
|
||||||
|
# [1.0.0-dev.8](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.7...v1.0.0-dev.8) (2022-03-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* check type instead of class ([47eb493](https://github.com/ReVancedTeam/revanced-patcher/commit/47eb493f5425dc27a4d6e79e6b02a36ef760e8da))
|
||||||
|
|
||||||
|
# [1.0.0-dev.7](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.6...v1.0.0-dev.7) (2022-03-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **MethodResolver:** fix cd57a8c9a0db7e3ae5ad0bca202e5955930319ab ([1af31b2](https://github.com/ReVancedTeam/revanced-patcher/commit/1af31b2aa3772a7473c04d27bf835c8eae13438d))
|
||||||
|
|
||||||
# [1.0.0-dev.6](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.5...v1.0.0-dev.6) (2022-03-24)
|
# [1.0.0-dev.6](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.5...v1.0.0-dev.6) (2022-03-24)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.6.10"
|
kotlin("jvm") version "1.6.20"
|
||||||
java
|
java
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
@@ -8,23 +8,35 @@ group = "app.revanced"
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
url = uri("https://maven.pkg.github.com/revanced/multidexlib2")
|
||||||
|
credentials {
|
||||||
|
// DO NOT set these variables in the project's gradle.properties.
|
||||||
|
// Instead, you should set them in:
|
||||||
|
// Windows: %homepath%\.gradle\gradle.properties
|
||||||
|
// Linux: ~/.gradle/gradle.properties
|
||||||
|
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR") // DO NOT CHANGE!
|
||||||
|
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN") // DO NOT CHANGE!
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib"))
|
implementation(kotlin("stdlib"))
|
||||||
implementation("org.ow2.asm:asm:9.2")
|
|
||||||
implementation("org.ow2.asm:asm-util:9.2")
|
api("org.apktool:apktool-lib:2.6.1")
|
||||||
implementation("org.ow2.asm:asm-tree:9.2")
|
api("app.revanced:multidexlib2:2.5.2.r2")
|
||||||
implementation("org.ow2.asm:asm-commons:9.2")
|
api("org.smali:smali:2.5.2")
|
||||||
implementation("io.github.microutils:kotlin-logging:2.1.21")
|
|
||||||
testImplementation("ch.qos.logback:logback-classic:1.2.11") // use your own logger!
|
|
||||||
testImplementation(kotlin("test"))
|
testImplementation(kotlin("test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
tasks {
|
||||||
useJUnitPlatform()
|
test {
|
||||||
testLogging {
|
useJUnitPlatform()
|
||||||
events("PASSED", "SKIPPED", "FAILED")
|
testLogging {
|
||||||
|
events("PASSED", "SKIPPED", "FAILED")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,15 +45,21 @@ java {
|
|||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isGitHubCI = System.getenv("GITHUB_ACTOR") != null
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
if (isGitHubCI) {
|
||||||
name = "GitHubPackages"
|
maven {
|
||||||
url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patcher")
|
name = "GitHubPackages"
|
||||||
credentials {
|
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
|
||||||
username = System.getenv("GITHUB_ACTOR")
|
credentials {
|
||||||
password = System.getenv("GITHUB_TOKEN")
|
username = System.getenv("GITHUB_ACTOR")
|
||||||
|
password = System.getenv("GITHUB_TOKEN")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mavenLocal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
publications {
|
publications {
|
||||||
@@ -49,4 +67,4 @@ publishing {
|
|||||||
from(components["java"])
|
from(components["java"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 1.0.0-dev.6
|
version = 1.0.0-dev.10
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
|||||||
package app.revanced.patcher.cache
|
|
||||||
|
|
||||||
import org.objectweb.asm.tree.ClassNode
|
|
||||||
|
|
||||||
class Cache(
|
|
||||||
val classes: List<ClassNode>,
|
|
||||||
val methods: MethodMap
|
|
||||||
)
|
|
||||||
|
|
||||||
class MethodMap : LinkedHashMap<String, PatchData>() {
|
|
||||||
override fun get(key: String): PatchData {
|
|
||||||
return super.get(key) ?: throw MethodNotFoundException("Method $key was not found in the method cache")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MethodNotFoundException(s: String) : Exception(s)
|
|
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.cache
|
|
||||||
|
|
||||||
import app.revanced.patcher.resolver.MethodResolver
|
|
||||||
import app.revanced.patcher.signature.Signature
|
|
||||||
import org.objectweb.asm.tree.ClassNode
|
|
||||||
import org.objectweb.asm.tree.MethodNode
|
|
||||||
|
|
||||||
data class PatchData(
|
|
||||||
val declaringClass: ClassNode,
|
|
||||||
val method: MethodNode,
|
|
||||||
val scanData: PatternScanData
|
|
||||||
) {
|
|
||||||
@Suppress("Unused") // TODO(Sculas): remove this when we have coverage for this method.
|
|
||||||
fun findParentMethod(signature: Signature): PatchData? {
|
|
||||||
return MethodResolver.resolveMethod(declaringClass, signature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class PatternScanData(
|
|
||||||
val startIndex: Int,
|
|
||||||
val endIndex: Int
|
|
||||||
)
|
|
18
src/main/kotlin/app/revanced/patcher/data/PatcherData.kt
Normal file
18
src/main/kotlin/app/revanced/patcher/data/PatcherData.kt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package app.revanced.patcher.data
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.base.Data
|
||||||
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
import app.revanced.patcher.patch.base.Patch
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal data class PatcherData(
|
||||||
|
val internalClasses: MutableList<ClassDef>,
|
||||||
|
val resourceCacheDirectory: String
|
||||||
|
) {
|
||||||
|
internal val patches = mutableListOf<Patch<Data>>()
|
||||||
|
|
||||||
|
internal val bytecodeData = BytecodeData(patches, internalClasses)
|
||||||
|
internal val resourceData = ResourceData(File(resourceCacheDirectory))
|
||||||
|
}
|
9
src/main/kotlin/app/revanced/patcher/data/base/Data.kt
Normal file
9
src/main/kotlin/app/revanced/patcher/data/base/Data.kt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package app.revanced.patcher.data.base
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constraint interface for [BytecodeData] and [ResourceData]
|
||||||
|
*/
|
||||||
|
interface Data
|
@@ -0,0 +1,87 @@
|
|||||||
|
package app.revanced.patcher.data.implementation
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.base.Data
|
||||||
|
import app.revanced.patcher.methodWalker.MethodWalker
|
||||||
|
import app.revanced.patcher.patch.base.Patch
|
||||||
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
|
import app.revanced.patcher.proxy.ClassProxy
|
||||||
|
import app.revanced.patcher.signature.SignatureResolverResult
|
||||||
|
import app.revanced.patcher.util.ProxyBackedClassList
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
|
||||||
|
class BytecodeData(
|
||||||
|
// FIXME: ugly solution due to design.
|
||||||
|
// It does not make sense for a BytecodeData instance to have access to the patches
|
||||||
|
private val patches: List<Patch<Data>>,
|
||||||
|
internalClasses: MutableList<ClassDef>
|
||||||
|
) : Data {
|
||||||
|
val classes = ProxyBackedClassList(internalClasses)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a class by a given class name
|
||||||
|
* @return A proxy for the first class that matches the class name
|
||||||
|
*/
|
||||||
|
fun findClass(className: String) = findClass { it.type.contains(className) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a class by a given predicate
|
||||||
|
* @return A proxy for the first class that matches the predicate
|
||||||
|
*/
|
||||||
|
fun findClass(predicate: (ClassDef) -> Boolean): ClassProxy? {
|
||||||
|
// if we already proxied the class matching the predicate...
|
||||||
|
for (patch in patches) {
|
||||||
|
if (patch !is BytecodePatch) continue
|
||||||
|
for (signature in patch.signatures) {
|
||||||
|
val result = signature.result
|
||||||
|
result ?: continue
|
||||||
|
|
||||||
|
if (predicate(result.definingClassProxy.immutableClass)) return result.definingClassProxy // ...then return that proxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else resolve the class to a proxy and return it, if the predicate is matching a class
|
||||||
|
return classes.find(predicate)?.let {
|
||||||
|
proxy(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MethodMap : LinkedHashMap<String, SignatureResolverResult>() {
|
||||||
|
override fun get(key: String): SignatureResolverResult {
|
||||||
|
return super.get(key) ?: throw MethodNotFoundException("Method $key was not found in the method cache")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MethodNotFoundException(s: String) : Exception(s)
|
||||||
|
|
||||||
|
internal inline fun <reified T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
|
||||||
|
for (element in this) {
|
||||||
|
if (predicate(element)) {
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BytecodeData.toMethodWalker(startMethod: Method): MethodWalker {
|
||||||
|
return MethodWalker(this, startMethod)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <T> Iterable<T>.findIndexed(predicate: (T) -> Boolean): Pair<T, Int>? {
|
||||||
|
for ((index, element) in this.withIndex()) {
|
||||||
|
if (predicate(element)) {
|
||||||
|
return element to index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BytecodeData.proxy(classDef: ClassDef): ClassProxy {
|
||||||
|
var proxy = this.classes.proxies.find { it.immutableClass.type == classDef.type }
|
||||||
|
if (proxy == null) {
|
||||||
|
proxy = ClassProxy(classDef)
|
||||||
|
this.classes.proxies.add(proxy)
|
||||||
|
}
|
||||||
|
return proxy
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
package app.revanced.patcher.data.implementation
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.base.Data
|
||||||
|
import org.w3c.dom.Document
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.io.File
|
||||||
|
import javax.xml.XMLConstants
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
import javax.xml.transform.TransformerFactory
|
||||||
|
import javax.xml.transform.dom.DOMSource
|
||||||
|
import javax.xml.transform.stream.StreamResult
|
||||||
|
|
||||||
|
class ResourceData(private val resourceCacheDirectory: File) : Data {
|
||||||
|
private fun resolve(path: String) = resourceCacheDirectory.resolve(path)
|
||||||
|
|
||||||
|
fun forEach(action: (File) -> Unit) = resourceCacheDirectory.walkTopDown().forEach(action)
|
||||||
|
fun reader(path: String) = resolve(path).reader()
|
||||||
|
fun writer(path: String) = resolve(path).writer()
|
||||||
|
|
||||||
|
fun replace(path: String, oldValue: String, newValue: String, oldValueIsRegex: Boolean = false) {
|
||||||
|
// TODO: buffer this somehow
|
||||||
|
val content = resolve(path).readText()
|
||||||
|
|
||||||
|
if (oldValueIsRegex) {
|
||||||
|
content.replace(Regex(oldValue), newValue)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getXmlEditor(path: String) = DomFileEditor(resolve(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
class DomFileEditor internal constructor(private val domFile: File) : Closeable {
|
||||||
|
val file: Document
|
||||||
|
|
||||||
|
init {
|
||||||
|
val factory = DocumentBuilderFactory.newInstance()
|
||||||
|
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
|
||||||
|
|
||||||
|
val builder = factory.newDocumentBuilder()
|
||||||
|
|
||||||
|
// this will expectedly throw
|
||||||
|
file = builder.parse(domFile)
|
||||||
|
file.normalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() = TransformerFactory.newInstance().newTransformer()
|
||||||
|
.transform(DOMSource(file), StreamResult(domFile.outputStream()))
|
||||||
|
}
|
@@ -0,0 +1,81 @@
|
|||||||
|
package app.revanced.patcher.extensions
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.builder.BuilderInstruction
|
||||||
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||||
|
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.util.MethodUtil
|
||||||
|
|
||||||
|
infix fun AccessFlags.or(other: AccessFlags) = this.value or other.value
|
||||||
|
infix fun Int.or(other: AccessFlags) = this or other.value
|
||||||
|
|
||||||
|
fun MutableMethodImplementation.addInstructions(index: Int, instructions: List<BuilderInstruction>) {
|
||||||
|
for (i in instructions.lastIndex downTo 0) {
|
||||||
|
this.addInstruction(index, instructions[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the method.
|
||||||
|
* @param registerCount This parameter allows you to change the register count of the method.
|
||||||
|
* This may be a positive or negative number.
|
||||||
|
* @return The **immutable** cloned method. Call [toMutable] or [cloneMutable] to get a **mutable** copy.
|
||||||
|
*/
|
||||||
|
internal fun Method.clone(
|
||||||
|
registerCount: Int = 0,
|
||||||
|
): ImmutableMethod {
|
||||||
|
val clonedImplementation = implementation?.let {
|
||||||
|
ImmutableMethodImplementation(
|
||||||
|
it.registerCount + registerCount,
|
||||||
|
it.instructions,
|
||||||
|
it.tryBlocks,
|
||||||
|
it.debugItems,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return ImmutableMethod(
|
||||||
|
returnType,
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
returnType,
|
||||||
|
accessFlags,
|
||||||
|
annotations,
|
||||||
|
hiddenApiRestrictions,
|
||||||
|
clonedImplementation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the method.
|
||||||
|
* @param registerCount This parameter allows you to change the register count of the method.
|
||||||
|
* This may be a positive or negative number.
|
||||||
|
* @return The **mutable** cloned method. Call [clone] to get an **immutable** copy.
|
||||||
|
*/
|
||||||
|
internal fun Method.cloneMutable(
|
||||||
|
registerCount: Int = 0,
|
||||||
|
) = clone(registerCount).toMutable()
|
||||||
|
|
||||||
|
internal fun Method.softCompareTo(
|
||||||
|
otherMethod: MethodReference
|
||||||
|
): Boolean {
|
||||||
|
if (MethodUtil.isConstructor(this) && !parametersEqual(this.parameterTypes, otherMethod.parameterTypes))
|
||||||
|
return false
|
||||||
|
return this.name == otherMethod.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: also check the order of parameters as different order equals different method overload
|
||||||
|
internal fun parametersEqual(
|
||||||
|
parameters1: Iterable<CharSequence>,
|
||||||
|
parameters2: Iterable<CharSequence>
|
||||||
|
): Boolean {
|
||||||
|
return parameters1.count() == parameters2.count() && parameters1.all { parameter ->
|
||||||
|
parameters2.any {
|
||||||
|
it.startsWith(
|
||||||
|
parameter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
package app.revanced.patcher.methodWalker
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.data.implementation.MethodNotFoundException
|
||||||
|
import app.revanced.patcher.extensions.softCompareTo
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableMethod
|
||||||
|
import org.jf.dexlib2.Format
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
import org.jf.dexlib2.util.Preconditions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a method from another method via instruction offsets.
|
||||||
|
* @param bytecodeData The bytecodeData to use when resolving the next method reference.
|
||||||
|
* @param currentMethod The method to start from.
|
||||||
|
*/
|
||||||
|
class MethodWalker internal constructor(
|
||||||
|
private val bytecodeData: BytecodeData,
|
||||||
|
private var currentMethod: Method
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Get the method which was walked last.
|
||||||
|
* It is possible to cast this method to a [MutableMethod], if the method has been walked mutably.
|
||||||
|
*/
|
||||||
|
fun getMethod(): Method {
|
||||||
|
return currentMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walk to a method defined at the offset in the instruction list of the current method.
|
||||||
|
* @param offset The offset of the instruction. This instruction must be of format 35c.
|
||||||
|
* @param walkMutable If this is true, the class of the method will be resolved mutably.
|
||||||
|
* The current method will be mutable.
|
||||||
|
*/
|
||||||
|
fun walk(offset: Int, walkMutable: Boolean = false): MethodWalker {
|
||||||
|
currentMethod.implementation?.instructions?.let { instructions ->
|
||||||
|
val instruction = instructions.elementAt(offset)
|
||||||
|
|
||||||
|
Preconditions.checkFormat(instruction.opcode, Format.Format35c)
|
||||||
|
|
||||||
|
val newMethod = (instruction as Instruction35c).reference as MethodReference
|
||||||
|
val proxy = bytecodeData.findClass(newMethod.definingClass)!!
|
||||||
|
|
||||||
|
val methods = if (walkMutable) proxy.resolve().methods else proxy.immutableClass.methods
|
||||||
|
currentMethod = methods.first { it ->
|
||||||
|
return@first it.softCompareTo(newMethod)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
throw MethodNotFoundException("This method can not be walked at offset $offset inside the method ${currentMethod.name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -1,7 +0,0 @@
|
|||||||
package app.revanced.patcher.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.cache.Cache
|
|
||||||
|
|
||||||
abstract class Patch(val patchName: String) {
|
|
||||||
abstract fun execute(cache: Cache): PatchResult
|
|
||||||
}
|
|
22
src/main/kotlin/app/revanced/patcher/patch/base/Patch.kt
Normal file
22
src/main/kotlin/app/revanced/patcher/patch/base/Patch.kt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package app.revanced.patcher.patch.base
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.base.Data
|
||||||
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.metadata.PatchMetadata
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ReVanced patch.
|
||||||
|
* Can either be a [ResourcePatch] or a [BytecodePatch]
|
||||||
|
*/
|
||||||
|
abstract class Patch<out T : Data>(
|
||||||
|
open val metadata: PatchMetadata
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* The main function of the [Patch] which the patcher will call.
|
||||||
|
*/
|
||||||
|
abstract fun execute(data: @UnsafeVariance T): PatchResult // FIXME: remove the UnsafeVariance annotation
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
package app.revanced.patcher.patch.implementation
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.patch.base.Patch
|
||||||
|
import app.revanced.patcher.patch.implementation.metadata.PatchMetadata
|
||||||
|
import app.revanced.patcher.signature.MethodSignature
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytecode patch for the Patcher.
|
||||||
|
* @param metadata [PatchMetadata] for the patch.
|
||||||
|
* @param signatures A list of [MethodSignature] this patch relies on.
|
||||||
|
*/
|
||||||
|
abstract class BytecodePatch(
|
||||||
|
override val metadata: PatchMetadata,
|
||||||
|
val signatures: Iterable<MethodSignature>
|
||||||
|
) : Patch<BytecodeData>(metadata)
|
@@ -0,0 +1,13 @@
|
|||||||
|
package app.revanced.patcher.patch.implementation
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
import app.revanced.patcher.patch.base.Patch
|
||||||
|
import app.revanced.patcher.patch.implementation.metadata.PatchMetadata
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource patch for the Patcher.
|
||||||
|
* @param metadata [PatchMetadata] for the patch.
|
||||||
|
*/
|
||||||
|
abstract class ResourcePatch(
|
||||||
|
override val metadata: PatchMetadata
|
||||||
|
) : Patch<ResourceData>(metadata)
|
@@ -0,0 +1,29 @@
|
|||||||
|
package app.revanced.patcher.patch.implementation.metadata
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.base.Patch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata about a [Patch].
|
||||||
|
* @param shortName A suggestive short name for the [Patch].
|
||||||
|
* @param name A suggestive name for the [Patch].
|
||||||
|
* @param description A description for the [Patch].
|
||||||
|
* @param compatiblePackages A list of packages this [Patch] is compatible with.
|
||||||
|
* @param version The version of the [Patch].
|
||||||
|
*/
|
||||||
|
data class PatchMetadata(
|
||||||
|
val shortName: String,
|
||||||
|
val name: String,
|
||||||
|
val description: String,
|
||||||
|
val compatiblePackages: Iterable<PackageMetadata>,
|
||||||
|
val version: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata about a package.
|
||||||
|
* @param name The package name.
|
||||||
|
* @param versions Compatible versions of the package.
|
||||||
|
*/
|
||||||
|
data class PackageMetadata(
|
||||||
|
val name: String,
|
||||||
|
val versions: Iterable<String>
|
||||||
|
)
|
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patcher.patch
|
package app.revanced.patcher.patch.implementation.misc
|
||||||
|
|
||||||
interface PatchResult {
|
interface PatchResult {
|
||||||
fun error(): PatchResultError? {
|
fun error(): PatchResultError? {
|
41
src/main/kotlin/app/revanced/patcher/proxy/ClassProxy.kt
Normal file
41
src/main/kotlin/app/revanced/patcher/proxy/ClassProxy.kt
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package app.revanced.patcher.proxy
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableClass
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A proxy class for a [ClassDef].
|
||||||
|
*
|
||||||
|
* A class proxy simply holds a reference to the original class
|
||||||
|
* and allocates a mutable clone for the original class if needed.
|
||||||
|
* @param immutableClass The class to proxy
|
||||||
|
*/
|
||||||
|
class ClassProxy(
|
||||||
|
val immutableClass: ClassDef,
|
||||||
|
) {
|
||||||
|
internal var proxyUsed = false
|
||||||
|
internal lateinit var mutatedClass: MutableClass
|
||||||
|
|
||||||
|
init {
|
||||||
|
// in the instance, that a [MutableClass] is being proxied,
|
||||||
|
// do not create an additional clone and reuse the [MutableClass] instance
|
||||||
|
if (immutableClass is MutableClass) {
|
||||||
|
mutatedClass = immutableClass
|
||||||
|
proxyUsed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates and returns a mutable clone of the original class.
|
||||||
|
* A patch should always use the original immutable class reference
|
||||||
|
* to avoid unnecessary allocations for the mutable class.
|
||||||
|
* @return A mutable clone of the original class.
|
||||||
|
*/
|
||||||
|
fun resolve(): MutableClass {
|
||||||
|
if (!proxyUsed) {
|
||||||
|
proxyUsed = true
|
||||||
|
mutatedClass = MutableClass(immutableClass)
|
||||||
|
}
|
||||||
|
return mutatedClass
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableAnnotationElement.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.base.BaseAnnotation
|
||||||
|
import org.jf.dexlib2.iface.Annotation
|
||||||
|
|
||||||
|
class MutableAnnotation(annotation: Annotation) : BaseAnnotation() {
|
||||||
|
private val visibility = annotation.visibility
|
||||||
|
private val type = annotation.type
|
||||||
|
private val _elements by lazy { annotation.elements.map { element -> element.toMutable() }.toMutableSet() }
|
||||||
|
|
||||||
|
override fun getType(): String {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getElements(): MutableSet<MutableAnnotationElement> {
|
||||||
|
return _elements
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVisibility(): Int {
|
||||||
|
return visibility
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun Annotation.toMutable(): MutableAnnotation {
|
||||||
|
return MutableAnnotation(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.encodedValue.MutableEncodedValue
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.base.BaseAnnotationElement
|
||||||
|
import org.jf.dexlib2.iface.AnnotationElement
|
||||||
|
import org.jf.dexlib2.iface.value.EncodedValue
|
||||||
|
|
||||||
|
class MutableAnnotationElement(annotationElement: AnnotationElement) : BaseAnnotationElement() {
|
||||||
|
private var name = annotationElement.name
|
||||||
|
private var value = annotationElement.value.toMutable()
|
||||||
|
|
||||||
|
fun setName(name: String) {
|
||||||
|
this.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setValue(value: MutableEncodedValue) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValue(): EncodedValue {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun AnnotationElement.toMutable(): MutableAnnotationElement {
|
||||||
|
return MutableAnnotationElement(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,103 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
|
import com.google.common.collect.Iterables
|
||||||
|
import org.jf.dexlib2.base.reference.BaseTypeReference
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.util.FieldUtil
|
||||||
|
import org.jf.dexlib2.util.MethodUtil
|
||||||
|
|
||||||
|
class MutableClass(classDef: ClassDef) : ClassDef, BaseTypeReference() {
|
||||||
|
// Class
|
||||||
|
private var type = classDef.type
|
||||||
|
private var sourceFile = classDef.sourceFile
|
||||||
|
private var accessFlags = classDef.accessFlags
|
||||||
|
private var superclass = classDef.superclass
|
||||||
|
|
||||||
|
private val _interfaces by lazy { classDef.interfaces.toMutableList() }
|
||||||
|
private val _annotations by lazy {
|
||||||
|
classDef.annotations.map { annotation -> annotation.toMutable() }.toMutableSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
private val _methods by lazy { classDef.methods.map { method -> method.toMutable() }.toMutableSet() }
|
||||||
|
private val _directMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_DIRECT).toMutableSet() }
|
||||||
|
private val _virtualMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_VIRTUAL).toMutableSet() }
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
private val _fields by lazy { classDef.fields.map { field -> field.toMutable() }.toMutableSet() }
|
||||||
|
private val _staticFields by lazy { Iterables.filter(_fields, FieldUtil.FIELD_IS_STATIC).toMutableSet() }
|
||||||
|
private val _instanceFields by lazy { Iterables.filter(_fields, FieldUtil.FIELD_IS_INSTANCE).toMutableSet() }
|
||||||
|
|
||||||
|
fun setType(type: String) {
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSourceFile(sourceFile: String?) {
|
||||||
|
this.sourceFile = sourceFile
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAccessFlags(accessFlags: Int) {
|
||||||
|
this.accessFlags = accessFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSuperClass(superclass: String?) {
|
||||||
|
this.superclass = superclass
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(): String {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAccessFlags(): Int {
|
||||||
|
return accessFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSourceFile(): String? {
|
||||||
|
return sourceFile
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSuperclass(): String? {
|
||||||
|
return superclass
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInterfaces(): MutableList<String> {
|
||||||
|
return _interfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||||
|
return _annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStaticFields(): MutableSet<MutableField> {
|
||||||
|
return _staticFields
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInstanceFields(): MutableSet<MutableField> {
|
||||||
|
return _instanceFields
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFields(): MutableSet<MutableField> {
|
||||||
|
return _fields
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDirectMethods(): MutableSet<MutableMethod> {
|
||||||
|
return _directMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVirtualMethods(): MutableSet<MutableMethod> {
|
||||||
|
return _virtualMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMethods(): MutableSet<MutableMethod> {
|
||||||
|
return _methods
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun ClassDef.toMutable(): MutableClass {
|
||||||
|
return MutableClass(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,73 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.encodedValue.MutableEncodedValue
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.HiddenApiRestriction
|
||||||
|
import org.jf.dexlib2.base.reference.BaseFieldReference
|
||||||
|
import org.jf.dexlib2.iface.Field
|
||||||
|
|
||||||
|
class MutableField(field: Field) : Field, BaseFieldReference() {
|
||||||
|
private var definingClass = field.definingClass
|
||||||
|
private var name = field.name
|
||||||
|
private var type = field.type
|
||||||
|
private var accessFlags = field.accessFlags
|
||||||
|
|
||||||
|
private var initialValue = field.initialValue?.toMutable()
|
||||||
|
private val _annotations by lazy { field.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() }
|
||||||
|
private val _hiddenApiRestrictions by lazy { field.hiddenApiRestrictions }
|
||||||
|
|
||||||
|
fun setDefiningClass(definingClass: String) {
|
||||||
|
this.definingClass = definingClass
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setName(name: String) {
|
||||||
|
this.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setType(type: String) {
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAccessFlags(accessFlags: Int) {
|
||||||
|
this.accessFlags = accessFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setInitialValue(initialValue: MutableEncodedValue?) {
|
||||||
|
this.initialValue = initialValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDefiningClass(): String {
|
||||||
|
return this.definingClass
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String {
|
||||||
|
return this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(): String {
|
||||||
|
return this.type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||||
|
return this._annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAccessFlags(): Int {
|
||||||
|
return this.accessFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getHiddenApiRestrictions(): MutableSet<HiddenApiRestriction> {
|
||||||
|
return this._hiddenApiRestrictions
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInitialValue(): MutableEncodedValue? {
|
||||||
|
return this.initialValue
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun Field.toMutable(): MutableField {
|
||||||
|
return MutableField(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableMethodParameter.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.HiddenApiRestriction
|
||||||
|
import org.jf.dexlib2.base.reference.BaseMethodReference
|
||||||
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
|
||||||
|
class MutableMethod(method: Method) : Method, BaseMethodReference() {
|
||||||
|
private var definingClass = method.definingClass
|
||||||
|
private var name = method.name
|
||||||
|
private var accessFlags = method.accessFlags
|
||||||
|
private var returnType = method.returnType
|
||||||
|
|
||||||
|
// Create own mutable MethodImplementation (due to not being able to change members like register count)
|
||||||
|
private val _implementation by lazy { method.implementation?.let { MutableMethodImplementation(it) } }
|
||||||
|
private val _annotations by lazy { method.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() }
|
||||||
|
private val _parameters by lazy { method.parameters.map { parameter -> parameter.toMutable() }.toMutableList() }
|
||||||
|
private val _parameterTypes by lazy { method.parameterTypes.toMutableList() }
|
||||||
|
private val _hiddenApiRestrictions by lazy { method.hiddenApiRestrictions }
|
||||||
|
|
||||||
|
override fun getDefiningClass(): String {
|
||||||
|
return definingClass
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParameterTypes(): MutableList<CharSequence> {
|
||||||
|
return _parameterTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getReturnType(): String {
|
||||||
|
return returnType
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||||
|
return _annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAccessFlags(): Int {
|
||||||
|
return accessFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getHiddenApiRestrictions(): MutableSet<HiddenApiRestriction> {
|
||||||
|
return _hiddenApiRestrictions
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParameters(): MutableList<MutableMethodParameter> {
|
||||||
|
return _parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getImplementation(): MutableMethodImplementation? {
|
||||||
|
return _implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun Method.toMutable(): MutableMethod {
|
||||||
|
return MutableMethod(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,37 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.base.BaseMethodParameter
|
||||||
|
import org.jf.dexlib2.iface.MethodParameter
|
||||||
|
|
||||||
|
// TODO: finish overriding all members if necessary
|
||||||
|
class MutableMethodParameter(parameter: MethodParameter) : MethodParameter, BaseMethodParameter() {
|
||||||
|
private var type = parameter.type
|
||||||
|
private var name = parameter.name
|
||||||
|
private var signature = parameter.signature
|
||||||
|
private val _annotations by lazy {
|
||||||
|
parameter.annotations.map { annotation -> annotation.toMutable() }.toMutableSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(): String {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String? {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSignature(): String? {
|
||||||
|
return signature
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||||
|
return _annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun MethodParameter.toMutable(): MutableMethodParameter {
|
||||||
|
return MutableMethodParameter(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes.encodedValue
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.MutableAnnotationElement.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.base.value.BaseAnnotationEncodedValue
|
||||||
|
import org.jf.dexlib2.iface.AnnotationElement
|
||||||
|
import org.jf.dexlib2.iface.value.AnnotationEncodedValue
|
||||||
|
|
||||||
|
class MutableAnnotationEncodedValue(annotationEncodedValue: AnnotationEncodedValue) : BaseAnnotationEncodedValue(),
|
||||||
|
MutableEncodedValue {
|
||||||
|
private var type = annotationEncodedValue.type
|
||||||
|
|
||||||
|
private val _elements by lazy {
|
||||||
|
annotationEncodedValue.elements.map { annotationElement -> annotationElement.toMutable() }.toMutableSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(): String {
|
||||||
|
return this.type
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setType(type: String) {
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getElements(): MutableSet<out AnnotationElement> {
|
||||||
|
return _elements
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun AnnotationEncodedValue.toMutable(): MutableAnnotationEncodedValue {
|
||||||
|
return MutableAnnotationEncodedValue(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes.encodedValue
|
||||||
|
|
||||||
|
import app.revanced.patcher.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
||||||
|
import org.jf.dexlib2.base.value.BaseArrayEncodedValue
|
||||||
|
import org.jf.dexlib2.iface.value.ArrayEncodedValue
|
||||||
|
import org.jf.dexlib2.iface.value.EncodedValue
|
||||||
|
|
||||||
|
class MutableArrayEncodedValue(arrayEncodedValue: ArrayEncodedValue) : BaseArrayEncodedValue(), MutableEncodedValue {
|
||||||
|
private val _value by lazy {
|
||||||
|
arrayEncodedValue.value.map { encodedValue -> encodedValue.toMutable() }.toMutableList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValue(): MutableList<out EncodedValue> {
|
||||||
|
return _value
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun ArrayEncodedValue.toMutable(): MutableArrayEncodedValue {
|
||||||
|
return MutableArrayEncodedValue(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,23 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes.encodedValue
|
||||||
|
|
||||||
|
import org.jf.dexlib2.base.value.BaseBooleanEncodedValue
|
||||||
|
import org.jf.dexlib2.iface.value.BooleanEncodedValue
|
||||||
|
|
||||||
|
class MutableBooleanEncodedValue(booleanEncodedValue: BooleanEncodedValue) : BaseBooleanEncodedValue(),
|
||||||
|
MutableEncodedValue {
|
||||||
|
private var value = booleanEncodedValue.value
|
||||||
|
|
||||||
|
override fun getValue(): Boolean {
|
||||||
|
return this.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setValue(value: Boolean) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun BooleanEncodedValue.toMutable(): MutableBooleanEncodedValue {
|
||||||
|
return MutableBooleanEncodedValue(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
package app.revanced.patcher.proxy.mutableTypes.encodedValue
|
||||||
|
|
||||||
|
import org.jf.dexlib2.base.value.BaseByteEncodedValue
|
||||||
|
import org.jf.dexlib2.iface.value.ByteEncodedValue
|
||||||
|
|
||||||
|
class MutableByteEncodedValue(byteEncodedValue: ByteEncodedValue) : BaseByteEncodedValue(), MutableEncodedValue {
|
||||||
|
private var value = byteEncodedValue.value
|
||||||
|
|
||||||
|
override fun getValue(): Byte {
|
||||||
|
return this.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setValue(value: Byte) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun ByteEncodedValue.toMutable(): MutableByteEncodedValue {
|
||||||
|
return MutableByteEncodedValue(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user