mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2026-01-19 09:23:56 +00:00
Compare commits
20 Commits
v14.2.2-de
...
v1.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cdb6887d4 | ||
|
|
ab6453ca8a | ||
|
|
e8182c17ad | ||
|
|
49beec9fc6 | ||
|
|
3ab42a932c | ||
|
|
4d98cbc9e8 | ||
|
|
87bbde5e06 | ||
|
|
8db8893ab1 | ||
|
|
00c6ab7faf | ||
|
|
460d62a24c | ||
|
|
89e4b9f762 | ||
|
|
a8fd7c00c3 | ||
|
|
1769132a9e | ||
|
|
6c0f0823c9 | ||
|
|
23e897a7a9 | ||
|
|
7e67daf878 | ||
|
|
593c83f29f | ||
|
|
72e123dd01 | ||
|
|
599a401ed9 | ||
|
|
3f8500b059 |
9
.gitattributes
vendored
9
.gitattributes
vendored
@@ -1,9 +0,0 @@
|
|||||||
#
|
|
||||||
# https://help.github.com/articles/dealing-with-line-endings/
|
|
||||||
#
|
|
||||||
# Linux start script should use lf
|
|
||||||
/gradlew text eol=lf
|
|
||||||
|
|
||||||
# These are Windows script files and should use crlf
|
|
||||||
*.bat text eol=crlf
|
|
||||||
|
|
||||||
72
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
72
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
@@ -1,72 +0,0 @@
|
|||||||
name: 🐞 Bug report
|
|
||||||
description: Report a very clearly broken issue.
|
|
||||||
title: 'bug: <title>'
|
|
||||||
labels: [bug]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
# ReVanced bug report
|
|
||||||
|
|
||||||
Important to note that your issue may have already been reported before. Please check for existing issues [here](https://github.com/revanced/revanced-patcher/labels/bug).
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: Type
|
|
||||||
options:
|
|
||||||
- Crash
|
|
||||||
- Cosmetic
|
|
||||||
- Other
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Bug description
|
|
||||||
description: How did you find the bug? Any additional details that might help?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Steps to reproduce
|
|
||||||
description: Add the steps to reproduce this bug including your environment.
|
|
||||||
placeholder: Step 1. Download some files. Step 2. ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Relevant log output
|
|
||||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
|
||||||
render: shell
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Screenshots or videos
|
|
||||||
description: Add screenshots or videos that show the bug here.
|
|
||||||
placeholder: Drag and drop the screenshots/videos into this box.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Solution
|
|
||||||
description: If applicable, add a possible solution.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add additional context here.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: checkboxes
|
|
||||||
id: acknowledgements
|
|
||||||
attributes:
|
|
||||||
label: Acknowledgements
|
|
||||||
description: Your issue will be closed if you haven't done these steps.
|
|
||||||
options:
|
|
||||||
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
|
|
||||||
required: true
|
|
||||||
- label: I have written a short but informative title.
|
|
||||||
required: true
|
|
||||||
- label: I filled out all of the requested information in this issue properly.
|
|
||||||
required: true
|
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +0,0 @@
|
|||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: 📃 Documentation
|
|
||||||
url: https://github.com/revanced/revanced-documentation/
|
|
||||||
about: Don't know how or where to start? Check out our documentation!
|
|
||||||
- name: 🗨 Discussions
|
|
||||||
url: https://github.com/revanced/revanced-suggestions/discussions
|
|
||||||
about: Got something you think should change or be added? Search for or start a new discussion!
|
|
||||||
58
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
58
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
@@ -1,58 +0,0 @@
|
|||||||
name: ⭐ Feature request
|
|
||||||
description: Create a detailed feature request.
|
|
||||||
title: 'feat: <title>'
|
|
||||||
labels: [feature-request]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
# ReVanced feature request
|
|
||||||
|
|
||||||
Do not submit requests for patches here. Please submit them [here](https://github.com/orgs/revanced/discussions/categories/patches) instead.
|
|
||||||
Important to note that your feature request may have already been made before. Please check for existing feature requests [here](https://github.com/revanced/revanced-patcher/labels/feature-request).
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: Type
|
|
||||||
options:
|
|
||||||
- Functionality
|
|
||||||
- Cosmetic
|
|
||||||
- Other
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Issue
|
|
||||||
description: What is the current problem. Why does it require a feature request?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Feature
|
|
||||||
description: Describe your feature in detail. How does it solve the issue?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Motivation
|
|
||||||
description: Why should your feature should be considered?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add additional context here.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: checkboxes
|
|
||||||
id: acknowledgements
|
|
||||||
attributes:
|
|
||||||
label: Acknowledgements
|
|
||||||
description: Your issue will be closed if you haven't done these steps.
|
|
||||||
options:
|
|
||||||
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
|
|
||||||
required: true
|
|
||||||
- label: I have written a short but informative title.
|
|
||||||
required: true
|
|
||||||
- label: I filled out all of the requested information in this issue properly.
|
|
||||||
required: true
|
|
||||||
2
.github/config.yml
vendored
2
.github/config.yml
vendored
@@ -1,2 +0,0 @@
|
|||||||
firstPRMergeComment: >
|
|
||||||
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.
|
|
||||||
25
.github/workflows/pull_request.yml
vendored
25
.github/workflows/pull_request.yml
vendored
@@ -1,25 +0,0 @@
|
|||||||
name: PR to main
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
MESSAGE: merge branch `${{ github.head_ref || github.ref_name }}` to `main`
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
pull-request:
|
|
||||||
name: Open pull request
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Open pull request
|
|
||||||
uses: repo-sync/pull-request@v2
|
|
||||||
with:
|
|
||||||
destination_branch: 'main'
|
|
||||||
pr_title: 'chore: ${{ env.MESSAGE }}'
|
|
||||||
pr_body: 'This pull request will ${{ env.MESSAGE }}.'
|
|
||||||
pr_draft: true
|
|
||||||
38
.github/workflows/release.yml
vendored
38
.github/workflows/release.yml
vendored
@@ -1,7 +1,5 @@
|
|||||||
name: Release
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
@@ -10,36 +8,32 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev
|
- dev
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
# Make sure the release step uses its own credentials:
|
|
||||||
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
|
||||||
persist-credentials: false
|
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Cache
|
- name: Setup JDK
|
||||||
uses: actions/cache@v3
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
java-version: '8'
|
||||||
${{ runner.home }}/.gradle/caches
|
distribution: 'adopt'
|
||||||
${{ runner.home }}/.gradle/wrapper
|
cache: gradle
|
||||||
.gradle
|
- name: Setup Node.js
|
||||||
build
|
uses: actions/setup-node@v2
|
||||||
node_modules
|
with:
|
||||||
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
|
node-version: "lts/*"
|
||||||
|
- name: Make gradlew executable
|
||||||
|
run: chmod +x gradlew
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
env:
|
run: ./gradlew build
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: ./gradlew build clean --no-daemon
|
|
||||||
- name: Setup semantic-release
|
- name: Setup semantic-release
|
||||||
run: npm install
|
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
||||||
- name: Release
|
- name: Release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: npm exec semantic-release
|
run: npx semantic-release
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -74,7 +74,6 @@ cmake-build-*/
|
|||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
out/
|
out/
|
||||||
.idea/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
# mpeltonen/sbt-idea plugin
|
||||||
.idea_modules/
|
.idea_modules/
|
||||||
@@ -116,9 +115,3 @@ gradle-app.setting
|
|||||||
|
|
||||||
# Avoid ignoring test resources
|
# Avoid ignoring test resources
|
||||||
!src/test/resources/*
|
!src/test/resources/*
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Gradle props, to avoid sharing the gpr key
|
|
||||||
gradle.properties
|
|
||||||
|
|||||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
10
.idea/codeStyles/Project.xml
generated
Normal file
10
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</JetCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
7
.idea/discord.xml
generated
Normal file
7
.idea/discord.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="PROJECT_FILES" />
|
||||||
|
<option name="description" value="" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
15
.idea/git_toolbox_prj.xml
generated
Normal file
15
.idea/git_toolbox_prj.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GitToolBoxProjectSettings">
|
||||||
|
<option name="commitMessageIssueKeyValidationOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
<option name="commitMessageValidationEnabledOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
12
.idea/vcs.xml
generated
Normal file
12
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CommitMessageInspectionProfile">
|
||||||
|
<profile version="1.0">
|
||||||
|
<inspection_tool class="CommitFormat" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
22
.releaserc
22
.releaserc
@@ -7,13 +7,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
[
|
"@semantic-release/commit-analyzer",
|
||||||
"@semantic-release/commit-analyzer", {
|
|
||||||
"releaseRules": [
|
|
||||||
{ "type": "build", "scope": "Needs bump", "release": "patch" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@semantic-release/release-notes-generator",
|
"@semantic-release/release-notes-generator",
|
||||||
"@semantic-release/changelog",
|
"@semantic-release/changelog",
|
||||||
"gradle-semantic-release-plugin",
|
"gradle-semantic-release-plugin",
|
||||||
@@ -26,18 +20,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
"@semantic-release/github"
|
||||||
"@saithodev/semantic-release-backmerge",
|
|
||||||
{
|
|
||||||
backmergeBranches: [{"from": "main", "to": "dev"}],
|
|
||||||
clearWorkspace: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@semantic-release/github",
|
|
||||||
{
|
|
||||||
successComment: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1681
CHANGELOG.md
1681
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1 @@
|
|||||||
# 💉 ReVanced Patcher
|
# Patcher
|
||||||
|
|
||||||
ReVanced Patcher used to patch Android applications.
|
|
||||||
|
|||||||
@@ -1,843 +0,0 @@
|
|||||||
public abstract interface class app/revanced/patcher/IntegrationsConsumer {
|
|
||||||
public abstract fun acceptIntegrations (Ljava/util/List;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/PackageMetadata {
|
|
||||||
public final fun getPackageName ()Ljava/lang/String;
|
|
||||||
public final fun getPackageVersion ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/PatchBundleLoader : java/util/List, kotlin/jvm/internal/markers/KMutableList {
|
|
||||||
public synthetic fun <init> (Ljava/lang/Iterable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public fun add (ILjava/lang/Class;)V
|
|
||||||
public synthetic fun add (ILjava/lang/Object;)V
|
|
||||||
public fun add (Ljava/lang/Class;)Z
|
|
||||||
public synthetic fun add (Ljava/lang/Object;)Z
|
|
||||||
public fun addAll (ILjava/util/Collection;)Z
|
|
||||||
public fun addAll (Ljava/util/Collection;)Z
|
|
||||||
public fun clear ()V
|
|
||||||
public fun contains (Ljava/lang/Class;)Z
|
|
||||||
public final fun contains (Ljava/lang/Object;)Z
|
|
||||||
public fun containsAll (Ljava/util/Collection;)Z
|
|
||||||
public fun get (I)Ljava/lang/Class;
|
|
||||||
public synthetic fun get (I)Ljava/lang/Object;
|
|
||||||
public fun getSize ()I
|
|
||||||
public fun indexOf (Ljava/lang/Class;)I
|
|
||||||
public final fun indexOf (Ljava/lang/Object;)I
|
|
||||||
public fun isEmpty ()Z
|
|
||||||
public fun iterator ()Ljava/util/Iterator;
|
|
||||||
public fun lastIndexOf (Ljava/lang/Class;)I
|
|
||||||
public final fun lastIndexOf (Ljava/lang/Object;)I
|
|
||||||
public fun listIterator ()Ljava/util/ListIterator;
|
|
||||||
public fun listIterator (I)Ljava/util/ListIterator;
|
|
||||||
public final fun remove (I)Ljava/lang/Class;
|
|
||||||
public synthetic fun remove (I)Ljava/lang/Object;
|
|
||||||
public fun remove (Ljava/lang/Class;)Z
|
|
||||||
public final fun remove (Ljava/lang/Object;)Z
|
|
||||||
public fun removeAll (Ljava/util/Collection;)Z
|
|
||||||
public fun removeAt (I)Ljava/lang/Class;
|
|
||||||
public fun retainAll (Ljava/util/Collection;)Z
|
|
||||||
public fun set (ILjava/lang/Class;)Ljava/lang/Class;
|
|
||||||
public synthetic fun set (ILjava/lang/Object;)Ljava/lang/Object;
|
|
||||||
public final fun size ()I
|
|
||||||
public fun subList (II)Ljava/util/List;
|
|
||||||
public fun toArray ()[Ljava/lang/Object;
|
|
||||||
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/PatchBundleLoader$Dex : app/revanced/patcher/PatchBundleLoader {
|
|
||||||
public fun <init> ([Ljava/io/File;)V
|
|
||||||
public fun <init> ([Ljava/io/File;Ljava/io/File;)V
|
|
||||||
public synthetic fun <init> ([Ljava/io/File;Ljava/io/File;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public synthetic fun remove (I)Ljava/lang/Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/PatchBundleLoader$Jar : app/revanced/patcher/PatchBundleLoader {
|
|
||||||
public fun <init> ([Ljava/io/File;)V
|
|
||||||
public synthetic fun remove (I)Ljava/lang/Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/PatchExecutorFunction : java/util/function/Function {
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/Patcher : app/revanced/patcher/IntegrationsConsumer, app/revanced/patcher/PatchExecutorFunction, app/revanced/patcher/PatchesConsumer, java/io/Closeable, java/util/function/Supplier {
|
|
||||||
public fun <init> (Lapp/revanced/patcher/PatcherOptions;)V
|
|
||||||
public fun acceptIntegrations (Ljava/util/List;)V
|
|
||||||
public fun acceptPatches (Ljava/util/List;)V
|
|
||||||
public synthetic fun apply (Ljava/lang/Object;)Ljava/lang/Object;
|
|
||||||
public fun apply (Z)Lkotlinx/coroutines/flow/Flow;
|
|
||||||
public fun close ()V
|
|
||||||
public fun get ()Lapp/revanced/patcher/PatcherResult;
|
|
||||||
public synthetic fun get ()Ljava/lang/Object;
|
|
||||||
public final fun getContext ()Lapp/revanced/patcher/PatcherContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/PatcherContext {
|
|
||||||
public final fun getPackageMetadata ()Lapp/revanced/patcher/PackageMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/PatcherOptions {
|
|
||||||
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;)V
|
|
||||||
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/logging/Logger;)V
|
|
||||||
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/logging/Logger;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public final fun copy (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/logging/Logger;)Lapp/revanced/patcher/PatcherOptions;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/PatcherOptions;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/logging/Logger;ILjava/lang/Object;)Lapp/revanced/patcher/PatcherOptions;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public fun hashCode ()I
|
|
||||||
public final fun recreateResourceCacheDirectory ()Ljava/io/File;
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/PatcherResult {
|
|
||||||
public fun <init> (Ljava/util/List;Ljava/io/File;Ljava/util/List;)V
|
|
||||||
public synthetic fun <init> (Ljava/util/List;Ljava/io/File;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public final fun component1 ()Ljava/util/List;
|
|
||||||
public final fun component2 ()Ljava/io/File;
|
|
||||||
public final fun component3 ()Ljava/util/List;
|
|
||||||
public final fun copy (Ljava/util/List;Ljava/io/File;Ljava/util/List;)Lapp/revanced/patcher/PatcherResult;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/PatcherResult;Ljava/util/List;Ljava/io/File;Ljava/util/List;ILjava/lang/Object;)Lapp/revanced/patcher/PatcherResult;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getDexFiles ()Ljava/util/List;
|
|
||||||
public final fun getDoNotCompress ()Ljava/util/List;
|
|
||||||
public final fun getResourceFile ()Ljava/io/File;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/PatcherResult$PatchedDexFile {
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/io/InputStream;)V
|
|
||||||
public final fun getName ()Ljava/lang/String;
|
|
||||||
public final fun getStream ()Ljava/io/InputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/PatchesConsumer {
|
|
||||||
public abstract fun acceptPatches (Ljava/util/List;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/annotation/Compatibility : java/lang/annotation/Annotation {
|
|
||||||
public abstract fun compatiblePackages ()[Lapp/revanced/patcher/annotation/Package;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/annotation/Description : java/lang/annotation/Annotation {
|
|
||||||
public abstract fun description ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/annotation/Name : java/lang/annotation/Annotation {
|
|
||||||
public abstract fun name ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/annotation/Package : java/lang/annotation/Annotation {
|
|
||||||
public abstract fun name ()Ljava/lang/String;
|
|
||||||
public abstract fun versions ()[Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/data/BytecodeContext : app/revanced/patcher/data/Context {
|
|
||||||
public final fun findClass (Ljava/lang/String;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
|
||||||
public final fun findClass (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
|
||||||
public synthetic fun get ()Ljava/lang/Object;
|
|
||||||
public fun get ()Ljava/util/List;
|
|
||||||
public final fun getClasses ()Lapp/revanced/patcher/util/ProxyClassList;
|
|
||||||
public final fun proxy (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
|
||||||
public final fun toMethodWalker (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/method/MethodWalker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/data/Context : java/util/function/Supplier {
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/data/ResourceContext : app/revanced/patcher/data/Context, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
|
|
||||||
public fun get ()Ljava/io/File;
|
|
||||||
public synthetic fun get ()Ljava/lang/Object;
|
|
||||||
public final fun get (Ljava/lang/String;)Ljava/io/File;
|
|
||||||
public final fun getXmlEditor ()Lapp/revanced/patcher/data/ResourceContext$XmlFileHolder;
|
|
||||||
public fun iterator ()Ljava/util/Iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/data/ResourceContext$XmlFileHolder {
|
|
||||||
public fun <init> (Lapp/revanced/patcher/data/ResourceContext;)V
|
|
||||||
public final fun get (Ljava/io/InputStream;)Lapp/revanced/patcher/util/DomFileEditor;
|
|
||||||
public final fun get (Ljava/lang/String;)Lapp/revanced/patcher/util/DomFileEditor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/extensions/ExtensionsKt {
|
|
||||||
public static final fun newLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/Label;
|
|
||||||
public static final fun or (ILcom/android/tools/smali/dexlib2/AccessFlags;)I
|
|
||||||
public static final fun or (Lcom/android/tools/smali/dexlib2/AccessFlags;I)I
|
|
||||||
public static final fun or (Lcom/android/tools/smali/dexlib2/AccessFlags;Lcom/android/tools/smali/dexlib2/AccessFlags;)I
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/extensions/InstructionExtensions {
|
|
||||||
public static final field INSTANCE Lapp/revanced/patcher/extensions/InstructionExtensions;
|
|
||||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V
|
|
||||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
|
||||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V
|
|
||||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V
|
|
||||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
|
||||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/util/List;)V
|
|
||||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V
|
|
||||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/util/List;)V
|
|
||||||
public final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V
|
|
||||||
public final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;Ljava/util/List;)V
|
|
||||||
public final fun addInstructionsWithLabels (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;[Lapp/revanced/patcher/util/smali/ExternalLabel;)V
|
|
||||||
public final fun getInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
|
||||||
public final fun getInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Ljava/lang/Object;
|
|
||||||
public final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
|
||||||
public final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Ljava/lang/Object;
|
|
||||||
public final fun getInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Ljava/util/List;
|
|
||||||
public final fun removeInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V
|
|
||||||
public final fun removeInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V
|
|
||||||
public final fun removeInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;II)V
|
|
||||||
public final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)V
|
|
||||||
public final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;II)V
|
|
||||||
public final fun replaceInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V
|
|
||||||
public final fun replaceInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
|
||||||
public final fun replaceInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
|
||||||
public final fun replaceInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/util/List;)V
|
|
||||||
public final fun replaceInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/extensions/MethodFingerprintExtensions {
|
|
||||||
public static final field INSTANCE Lapp/revanced/patcher/extensions/MethodFingerprintExtensions;
|
|
||||||
public final fun getFuzzyPatternScanMethod (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/method/annotation/FuzzyPatternScanMethod;
|
|
||||||
public final fun getName (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/extensions/PatchExtensions {
|
|
||||||
public static final field INSTANCE Lapp/revanced/patcher/extensions/PatchExtensions;
|
|
||||||
public final fun getCompatiblePackages (Ljava/lang/Class;)[Lapp/revanced/patcher/annotation/Package;
|
|
||||||
public final fun getDependencies (Ljava/lang/Class;)[Lkotlin/reflect/KClass;
|
|
||||||
public final fun getDescription (Ljava/lang/Class;)Ljava/lang/String;
|
|
||||||
public final fun getInclude (Ljava/lang/Class;)Z
|
|
||||||
public final fun getOptions (Ljava/lang/Class;)Lapp/revanced/patcher/patch/PatchOptions;
|
|
||||||
public final fun getPatchName (Ljava/lang/Class;)Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/fingerprint/Fingerprint {
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/fingerprint/method/annotation/FuzzyPatternScanMethod : java/lang/annotation/Annotation {
|
|
||||||
public abstract fun threshold ()I
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/fingerprint/method/impl/MethodFingerprint : app/revanced/patcher/fingerprint/Fingerprint {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint$Companion;
|
|
||||||
public fun <init> ()V
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)V
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public final fun getResult ()Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult;
|
|
||||||
public final fun setResult (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/fingerprint/method/impl/MethodFingerprint$Companion {
|
|
||||||
public final fun resolve (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;Lapp/revanced/patcher/data/BytecodeContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
|
||||||
public final fun resolve (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;Lapp/revanced/patcher/data/BytecodeContext;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
|
||||||
public final fun resolve (Ljava/lang/Iterable;Lapp/revanced/patcher/data/BytecodeContext;Ljava/lang/Iterable;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult {
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;Lapp/revanced/patcher/data/BytecodeContext;)V
|
|
||||||
public final fun component1 ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
|
||||||
public final fun component2 ()Lcom/android/tools/smali/dexlib2/iface/ClassDef;
|
|
||||||
public final fun component3 ()Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;
|
|
||||||
public final fun copy (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;Lapp/revanced/patcher/data/BytecodeContext;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;Lapp/revanced/patcher/data/BytecodeContext;ILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getClassDef ()Lcom/android/tools/smali/dexlib2/iface/ClassDef;
|
|
||||||
public final fun getMethod ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
|
||||||
public final fun getMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
|
|
||||||
public final fun getMutableMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
|
||||||
public final fun getScanResult ()Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult {
|
|
||||||
public fun <init> (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;)V
|
|
||||||
public final fun component1 ()Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;
|
|
||||||
public final fun component2 ()Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;
|
|
||||||
public final fun copy (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;ILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getPatternScanResult ()Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;
|
|
||||||
public final fun getStringsScanResult ()Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult {
|
|
||||||
public fun <init> (IILjava/util/List;)V
|
|
||||||
public synthetic fun <init> (IILjava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public final fun component1 ()I
|
|
||||||
public final fun component2 ()I
|
|
||||||
public final fun component3 ()Ljava/util/List;
|
|
||||||
public final fun copy (IILjava/util/List;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;IILjava/util/List;ILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getEndIndex ()I
|
|
||||||
public final fun getStartIndex ()I
|
|
||||||
public final fun getWarnings ()Ljava/util/List;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public final fun setWarnings (Ljava/util/List;)V
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult$Warning {
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/Opcode;Lcom/android/tools/smali/dexlib2/Opcode;II)V
|
|
||||||
public final fun component1 ()Lcom/android/tools/smali/dexlib2/Opcode;
|
|
||||||
public final fun component2 ()Lcom/android/tools/smali/dexlib2/Opcode;
|
|
||||||
public final fun component3 ()I
|
|
||||||
public final fun component4 ()I
|
|
||||||
public final fun copy (Lcom/android/tools/smali/dexlib2/Opcode;Lcom/android/tools/smali/dexlib2/Opcode;II)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult$Warning;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult$Warning;Lcom/android/tools/smali/dexlib2/Opcode;Lcom/android/tools/smali/dexlib2/Opcode;IIILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult$Warning;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getCorrectOpcode ()Lcom/android/tools/smali/dexlib2/Opcode;
|
|
||||||
public final fun getInstructionIndex ()I
|
|
||||||
public final fun getPatternIndex ()I
|
|
||||||
public final fun getWrongOpcode ()Lcom/android/tools/smali/dexlib2/Opcode;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult {
|
|
||||||
public fun <init> (Ljava/util/List;)V
|
|
||||||
public final fun component1 ()Ljava/util/List;
|
|
||||||
public final fun copy (Ljava/util/List;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;Ljava/util/List;ILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getMatches ()Ljava/util/List;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult$StringMatch {
|
|
||||||
public fun <init> (Ljava/lang/String;I)V
|
|
||||||
public final fun component1 ()Ljava/lang/String;
|
|
||||||
public final fun component2 ()I
|
|
||||||
public final fun copy (Ljava/lang/String;I)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult$StringMatch;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult$StringMatch;Ljava/lang/String;IILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult$StringMatch;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getIndex ()I
|
|
||||||
public final fun getString ()Ljava/lang/String;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/logging/Logger {
|
|
||||||
public abstract fun error (Ljava/lang/String;)V
|
|
||||||
public abstract fun info (Ljava/lang/String;)V
|
|
||||||
public abstract fun trace (Ljava/lang/String;)V
|
|
||||||
public abstract fun warn (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/logging/Logger$DefaultImpls {
|
|
||||||
public static fun error (Lapp/revanced/patcher/logging/Logger;Ljava/lang/String;)V
|
|
||||||
public static fun info (Lapp/revanced/patcher/logging/Logger;Ljava/lang/String;)V
|
|
||||||
public static fun trace (Lapp/revanced/patcher/logging/Logger;Ljava/lang/String;)V
|
|
||||||
public static fun warn (Lapp/revanced/patcher/logging/Logger;Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/logging/impl/NopLogger : app/revanced/patcher/logging/Logger {
|
|
||||||
public static final field INSTANCE Lapp/revanced/patcher/logging/impl/NopLogger;
|
|
||||||
public fun error (Ljava/lang/String;)V
|
|
||||||
public fun info (Ljava/lang/String;)V
|
|
||||||
public fun trace (Ljava/lang/String;)V
|
|
||||||
public fun warn (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
|
|
||||||
public fun <init> ()V
|
|
||||||
public fun <init> (Ljava/lang/Iterable;)V
|
|
||||||
public synthetic fun <init> (Ljava/lang/Iterable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/IllegalValueException : java/lang/Exception {
|
|
||||||
public fun <init> (Ljava/lang/Object;)V
|
|
||||||
public final fun getValue ()Ljava/lang/Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/InvalidTypeException : java/lang/Exception {
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
|
|
||||||
public final fun getExpected ()Ljava/lang/String;
|
|
||||||
public final fun getGot ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/NoSuchOptionException : java/lang/Exception {
|
|
||||||
public fun <init> (Ljava/lang/String;)V
|
|
||||||
public final fun getOption ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/patch/OptionsContainer {
|
|
||||||
public fun <init> ()V
|
|
||||||
public final fun getOptions ()Lapp/revanced/patcher/patch/PatchOptions;
|
|
||||||
protected final fun option (Lapp/revanced/patcher/patch/PatchOption;)Lapp/revanced/patcher/patch/PatchOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/patch/Patch {
|
|
||||||
public abstract fun execute (Lapp/revanced/patcher/data/Context;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/PatchException : java/lang/Exception {
|
|
||||||
public fun <init> (Ljava/lang/String;)V
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
|
|
||||||
public fun <init> (Ljava/lang/Throwable;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/patch/PatchOption {
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
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 getValidator ()Lkotlin/jvm/functions/Function1;
|
|
||||||
public final fun getValue ()Ljava/lang/Object;
|
|
||||||
public final fun getValue (Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object;
|
|
||||||
public final fun setValue (Ljava/lang/Object;)V
|
|
||||||
public final fun setValue (Ljava/lang/Object;Lkotlin/reflect/KProperty;Ljava/lang/Object;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/PatchOption$BooleanOption : app/revanced/patcher/patch/PatchOption {
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)V
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/PatchOption$IntListOption : app/revanced/patcher/patch/PatchOption$ListOption {
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)V
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/patch/PatchOption$ListOption : app/revanced/patcher/patch/PatchOption {
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Iterable;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Iterable;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public final fun getOptions ()Ljava/lang/Iterable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/PatchOption$StringListOption : app/revanced/patcher/patch/PatchOption$ListOption {
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Iterable;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)V
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Iterable;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/PatchOption$StringOption : app/revanced/patcher/patch/PatchOption {
|
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)V
|
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/PatchOptions : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
|
|
||||||
public fun <init> ([Lapp/revanced/patcher/patch/PatchOption;)V
|
|
||||||
public final fun getUntyped (Ljava/lang/String;)Lapp/revanced/patcher/patch/PatchOption;
|
|
||||||
public fun iterator ()Ljava/util/Iterator;
|
|
||||||
public final fun nullify (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/PatchResult {
|
|
||||||
public final fun getException ()Lapp/revanced/patcher/patch/PatchException;
|
|
||||||
public final fun getPatchName ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/patch/RequirementNotMetException : java/lang/Exception {
|
|
||||||
public static final field INSTANCE Lapp/revanced/patcher/patch/RequirementNotMetException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/patch/annotations/DependsOn : java/lang/annotation/Annotation {
|
|
||||||
public abstract fun dependencies ()[Ljava/lang/Class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/patch/annotations/Patch : java/lang/annotation/Annotation {
|
|
||||||
public abstract fun include ()Z
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/patch/annotations/RequiresIntegrations : java/lang/annotation/Annotation {
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/DomFileEditor : java/io/Closeable {
|
|
||||||
public fun <init> (Ljava/io/File;)V
|
|
||||||
public fun close ()V
|
|
||||||
public final fun getFile ()Lorg/w3c/dom/Document;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/ProxyClassList : java/util/Set, kotlin/jvm/internal/markers/KMutableSet {
|
|
||||||
public final fun add (Lapp/revanced/patcher/util/proxy/ClassProxy;)Z
|
|
||||||
public fun add (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
|
||||||
public synthetic fun add (Ljava/lang/Object;)Z
|
|
||||||
public fun addAll (Ljava/util/Collection;)Z
|
|
||||||
public fun clear ()V
|
|
||||||
public fun contains (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
|
||||||
public final fun contains (Ljava/lang/Object;)Z
|
|
||||||
public fun containsAll (Ljava/util/Collection;)Z
|
|
||||||
public fun getSize ()I
|
|
||||||
public fun isEmpty ()Z
|
|
||||||
public fun iterator ()Ljava/util/Iterator;
|
|
||||||
public fun remove (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
|
||||||
public final fun remove (Ljava/lang/Object;)Z
|
|
||||||
public fun removeAll (Ljava/util/Collection;)Z
|
|
||||||
public fun retainAll (Ljava/util/Collection;)Z
|
|
||||||
public final fun size ()I
|
|
||||||
public fun toArray ()[Ljava/lang/Object;
|
|
||||||
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/method/MethodWalker {
|
|
||||||
public final fun getMethod ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
|
||||||
public final fun nextMethod (IZ)Lapp/revanced/patcher/util/method/MethodWalker;
|
|
||||||
public static synthetic fun nextMethod$default (Lapp/revanced/patcher/util/method/MethodWalker;IZILjava/lang/Object;)Lapp/revanced/patcher/util/method/MethodWalker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/ClassProxy {
|
|
||||||
public final fun getImmutableClass ()Lcom/android/tools/smali/dexlib2/iface/ClassDef;
|
|
||||||
public final fun getMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation : com/android/tools/smali/dexlib2/base/BaseAnnotation {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Annotation;)V
|
|
||||||
public fun getElements ()Ljava/util/Set;
|
|
||||||
public fun getType ()Ljava/lang/String;
|
|
||||||
public fun getVisibility ()I
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Annotation;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement : com/android/tools/smali/dexlib2/base/BaseAnnotationElement {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)V
|
|
||||||
public fun getName ()Ljava/lang/String;
|
|
||||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;
|
|
||||||
public final fun setName (Ljava/lang/String;)V
|
|
||||||
public final fun setValue (Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableClass : com/android/tools/smali/dexlib2/base/reference/BaseTypeReference, com/android/tools/smali/dexlib2/iface/ClassDef {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)V
|
|
||||||
public final fun charAt (I)C
|
|
||||||
public fun get (I)C
|
|
||||||
public fun getAccessFlags ()I
|
|
||||||
public fun getAnnotations ()Ljava/util/Set;
|
|
||||||
public synthetic fun getDirectMethods ()Ljava/lang/Iterable;
|
|
||||||
public fun getDirectMethods ()Ljava/util/Set;
|
|
||||||
public synthetic fun getFields ()Ljava/lang/Iterable;
|
|
||||||
public fun getFields ()Ljava/util/Set;
|
|
||||||
public synthetic fun getInstanceFields ()Ljava/lang/Iterable;
|
|
||||||
public fun getInstanceFields ()Ljava/util/Set;
|
|
||||||
public fun getInterfaces ()Ljava/util/List;
|
|
||||||
public fun getLength ()I
|
|
||||||
public synthetic fun getMethods ()Ljava/lang/Iterable;
|
|
||||||
public fun getMethods ()Ljava/util/Set;
|
|
||||||
public fun getSourceFile ()Ljava/lang/String;
|
|
||||||
public synthetic fun getStaticFields ()Ljava/lang/Iterable;
|
|
||||||
public fun getStaticFields ()Ljava/util/Set;
|
|
||||||
public fun getSuperclass ()Ljava/lang/String;
|
|
||||||
public fun getType ()Ljava/lang/String;
|
|
||||||
public synthetic fun getVirtualMethods ()Ljava/lang/Iterable;
|
|
||||||
public fun getVirtualMethods ()Ljava/util/Set;
|
|
||||||
public final fun length ()I
|
|
||||||
public final fun setAccessFlags (I)V
|
|
||||||
public final fun setSourceFile (Ljava/lang/String;)V
|
|
||||||
public final fun setSuperClass (Ljava/lang/String;)V
|
|
||||||
public final fun setType (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableClass$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableField : com/android/tools/smali/dexlib2/base/reference/BaseFieldReference, com/android/tools/smali/dexlib2/iface/Field {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableField$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Field;)V
|
|
||||||
public fun getAccessFlags ()I
|
|
||||||
public fun getAnnotations ()Ljava/util/Set;
|
|
||||||
public fun getDefiningClass ()Ljava/lang/String;
|
|
||||||
public fun getHiddenApiRestrictions ()Ljava/util/Set;
|
|
||||||
public fun getInitialValue ()Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;
|
|
||||||
public synthetic fun getInitialValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;
|
|
||||||
public fun getName ()Ljava/lang/String;
|
|
||||||
public fun getType ()Ljava/lang/String;
|
|
||||||
public final fun setAccessFlags (I)V
|
|
||||||
public final fun setDefiningClass (Ljava/lang/String;)V
|
|
||||||
public final fun setInitialValue (Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;)V
|
|
||||||
public final fun setName (Ljava/lang/String;)V
|
|
||||||
public final fun setType (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableField$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Field;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableField;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethod : com/android/tools/smali/dexlib2/base/reference/BaseMethodReference, com/android/tools/smali/dexlib2/iface/Method {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Method;)V
|
|
||||||
public fun getAccessFlags ()I
|
|
||||||
public fun getAnnotations ()Ljava/util/Set;
|
|
||||||
public fun getDefiningClass ()Ljava/lang/String;
|
|
||||||
public fun getHiddenApiRestrictions ()Ljava/util/Set;
|
|
||||||
public fun getImplementation ()Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;
|
|
||||||
public synthetic fun getImplementation ()Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;
|
|
||||||
public fun getName ()Ljava/lang/String;
|
|
||||||
public fun getParameterTypes ()Ljava/util/List;
|
|
||||||
public fun getParameters ()Ljava/util/List;
|
|
||||||
public fun getReturnType ()Ljava/lang/String;
|
|
||||||
public final fun setAccessFlags (I)V
|
|
||||||
public final fun setDefiningClass (Ljava/lang/String;)V
|
|
||||||
public final fun setName (Ljava/lang/String;)V
|
|
||||||
public final fun setReturnType (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethod$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter : com/android/tools/smali/dexlib2/base/BaseMethodParameter, com/android/tools/smali/dexlib2/iface/MethodParameter {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)V
|
|
||||||
public final fun charAt (I)C
|
|
||||||
public fun get (I)C
|
|
||||||
public fun getAnnotations ()Ljava/util/Set;
|
|
||||||
public fun getLength ()I
|
|
||||||
public fun getName ()Ljava/lang/String;
|
|
||||||
public fun getSignature ()Ljava/lang/String;
|
|
||||||
public fun getType ()Ljava/lang/String;
|
|
||||||
public final fun length ()I
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)V
|
|
||||||
public fun getElements ()Ljava/util/Set;
|
|
||||||
public fun getType ()Ljava/lang/String;
|
|
||||||
public final fun setType (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)V
|
|
||||||
public fun getValue ()Ljava/util/List;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)V
|
|
||||||
public fun getValue ()Z
|
|
||||||
public final fun setValue (Z)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)V
|
|
||||||
public fun getValue ()B
|
|
||||||
public final fun setValue (B)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)V
|
|
||||||
public fun getValue ()C
|
|
||||||
public final fun setValue (C)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)V
|
|
||||||
public fun getValue ()D
|
|
||||||
public final fun setValue (D)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue : com/android/tools/smali/dexlib2/iface/value/EncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue$Companion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)V
|
|
||||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;
|
|
||||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)V
|
|
||||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;
|
|
||||||
public fun getValueType ()I
|
|
||||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)V
|
|
||||||
public fun getValue ()F
|
|
||||||
public final fun setValue (F)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)V
|
|
||||||
public fun getValue ()I
|
|
||||||
public final fun setValue (I)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)V
|
|
||||||
public fun getValue ()J
|
|
||||||
public final fun setValue (J)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)V
|
|
||||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;
|
|
||||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)V
|
|
||||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference;
|
|
||||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)V
|
|
||||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference;
|
|
||||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue$Companion;
|
|
||||||
public fun <init> ()V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)V
|
|
||||||
public fun getValue ()S
|
|
||||||
public final fun setValue (S)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/StringEncodedValue;)V
|
|
||||||
public fun getValue ()Ljava/lang/String;
|
|
||||||
public final fun setValue (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue$Companion;
|
|
||||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)V
|
|
||||||
public fun getValue ()Ljava/lang/String;
|
|
||||||
public final fun setValue (Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue$Companion {
|
|
||||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/smali/ExternalLabel {
|
|
||||||
public fun <init> (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)V
|
|
||||||
public final fun copy (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lapp/revanced/patcher/util/smali/ExternalLabel;
|
|
||||||
public static synthetic fun copy$default (Lapp/revanced/patcher/util/smali/ExternalLabel;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;ILjava/lang/Object;)Lapp/revanced/patcher/util/smali/ExternalLabel;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/smali/InlineSmaliCompiler {
|
|
||||||
public static final field Companion Lapp/revanced/patcher/util/smali/InlineSmaliCompiler$Companion;
|
|
||||||
public fun <init> ()V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/smali/InlineSmaliCompiler$Companion {
|
|
||||||
public final fun compile (Ljava/lang/String;Ljava/lang/String;IZ)Ljava/util/List;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patcher/util/smali/InlineSmaliCompilerKt {
|
|
||||||
public static final fun toInstruction (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
|
||||||
public static synthetic fun toInstruction$default (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/Object;)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
|
||||||
public static final fun toInstructions (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Ljava/util/List;
|
|
||||||
public static synthetic fun toInstructions$default (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/Object;)Ljava/util/List;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,49 +1,43 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.8.20"
|
kotlin("jvm") version "1.6.10"
|
||||||
|
java
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
alias(libs.plugins.binary.compatibility.validator)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "app.revanced"
|
group = "app.revanced"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.kotlinx.coroutines.core)
|
implementation(kotlin("stdlib"))
|
||||||
implementation(libs.xpp3)
|
implementation("org.ow2.asm:asm:9.2")
|
||||||
implementation(libs.smali)
|
implementation("org.ow2.asm:asm-util:9.2")
|
||||||
implementation(libs.multidexlib2)
|
implementation("org.ow2.asm:asm-tree:9.2")
|
||||||
implementation(libs.apktool.lib)
|
implementation("org.ow2.asm:asm-commons:9.2")
|
||||||
implementation(libs.kotlin.reflect)
|
implementation("io.github.microutils:kotlin-logging:2.1.21")
|
||||||
|
testImplementation("ch.qos.logback:logback-classic:1.2.11") // use your own logger!
|
||||||
compileOnly(libs.android)
|
testImplementation(kotlin("test"))
|
||||||
|
|
||||||
testImplementation(libs.kotlin.test)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks.test {
|
||||||
test {
|
useJUnitPlatform()
|
||||||
useJUnitPlatform()
|
testLogging {
|
||||||
testLogging {
|
events("PASSED", "SKIPPED", "FAILED")
|
||||||
events("PASSED", "SKIPPED", "FAILED")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processResources {
|
|
||||||
expand("projectVersion" to project.version)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin { jvmToolchain(11) }
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
|
||||||
maven {
|
maven {
|
||||||
name = "GitHubPackages"
|
name = "GitHubPackages"
|
||||||
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
|
url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patcher")
|
||||||
credentials {
|
credentials {
|
||||||
username = System.getenv("GITHUB_ACTOR")
|
username = System.getenv("GITHUB_ACTOR")
|
||||||
password = System.getenv("GITHUB_TOKEN")
|
password = System.getenv("GITHUB_TOKEN")
|
||||||
@@ -51,7 +45,7 @@ publishing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("gpr") {
|
register<MavenPublication>("gpr") {
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
org.gradle.parallel = true
|
|
||||||
org.gradle.caching = true
|
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 14.2.2-dev.1
|
version = 1.0.0-dev.2
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
[versions]
|
|
||||||
android = "4.1.1.4"
|
|
||||||
kotlin-reflect = "1.9.0"
|
|
||||||
apktool-lib = "2.8.2-6"
|
|
||||||
kotlin-test = "1.8.20-RC"
|
|
||||||
kotlinx-coroutines-core = "1.7.1"
|
|
||||||
multidexlib2 = "3.0.3.r2"
|
|
||||||
smali = "3.0.3"
|
|
||||||
xpp3 = "1.1.4c"
|
|
||||||
binary-compatibility-validator = "0.13.2"
|
|
||||||
|
|
||||||
[libraries]
|
|
||||||
android = { module = "com.google.android:android", version.ref = "android" }
|
|
||||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin-reflect" }
|
|
||||||
apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" }
|
|
||||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
|
|
||||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
|
|
||||||
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }
|
|
||||||
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
|
||||||
xpp3 = { module = "xpp3:xpp3", version.ref = "xpp3" }
|
|
||||||
|
|
||||||
[plugins]
|
|
||||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||||
networkTimeout=10000
|
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
281
gradlew
vendored
Executable file → Normal file
281
gradlew
vendored
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015-2021 the original authors.
|
# Copyright 2015 the original author or authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -17,98 +17,67 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
##
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
## Gradle start up script for UN*X
|
||||||
#
|
##
|
||||||
# Important for running:
|
|
||||||
#
|
|
||||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
|
||||||
# noncompliant, but you have some other compliant shell such as ksh or
|
|
||||||
# bash, then to run this script, type that shell name before the whole
|
|
||||||
# command line, like:
|
|
||||||
#
|
|
||||||
# ksh Gradle
|
|
||||||
#
|
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
|
||||||
# requires all of these POSIX shell features:
|
|
||||||
# * functions;
|
|
||||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
|
||||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
|
||||||
# * compound commands having a testable exit status, especially «case»;
|
|
||||||
# * various built-in commands including «command», «set», and «ulimit».
|
|
||||||
#
|
|
||||||
# Important for patching:
|
|
||||||
#
|
|
||||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
|
||||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
|
||||||
#
|
|
||||||
# The "traditional" practice of packing multiple parameters into a
|
|
||||||
# space-separated string is a well documented source of bugs and security
|
|
||||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
|
||||||
# options in "$@", and eventually passing that to Java.
|
|
||||||
#
|
|
||||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
|
||||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
|
||||||
# see the in-line comments for details.
|
|
||||||
#
|
|
||||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
|
||||||
# Darwin, MinGW, and NonStop.
|
|
||||||
#
|
|
||||||
# (3) This script is generated from the Groovy template
|
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
|
||||||
# within the Gradle project.
|
|
||||||
#
|
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
|
||||||
#
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
app_path=$0
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
# Need this for daisy-chained symlinks.
|
while [ -h "$PRG" ] ; do
|
||||||
while
|
ls=`ls -ld "$PRG"`
|
||||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
[ -h "$app_path" ]
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
do
|
PRG="$link"
|
||||||
ls=$( ls -ld "$app_path" )
|
else
|
||||||
link=${ls#*' -> '}
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
case $link in #(
|
fi
|
||||||
/*) app_path=$link ;; #(
|
|
||||||
*) app_path=$APP_HOME$link ;;
|
|
||||||
esac
|
|
||||||
done
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
# This is normally unused
|
APP_NAME="Gradle"
|
||||||
# shellcheck disable=SC2034
|
APP_BASE_NAME=`basename "$0"`
|
||||||
APP_BASE_NAME=${0##*/}
|
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD="maximum"
|
||||||
|
|
||||||
warn () {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
} >&2
|
}
|
||||||
|
|
||||||
die () {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
} >&2
|
}
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
nonstop=false
|
nonstop=false
|
||||||
case "$( uname )" in #(
|
case "`uname`" in
|
||||||
CYGWIN* ) cygwin=true ;; #(
|
CYGWIN* )
|
||||||
Darwin* ) darwin=true ;; #(
|
cygwin=true
|
||||||
MSYS* | MINGW* ) msys=true ;; #(
|
;;
|
||||||
NONSTOP* ) nonstop=true ;;
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MSYS* | MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
@@ -118,9 +87,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
else
|
else
|
||||||
JAVACMD=$JAVA_HOME/bin/java
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
@@ -129,120 +98,88 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD="java"
|
||||||
if ! command -v java >/dev/null 2>&1
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
then
|
|
||||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
case $MAX_FD in #(
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
max*)
|
if [ $? -eq 0 ] ; then
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
# shellcheck disable=SC3045
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
fi
|
||||||
warn "Could not query maximum file descriptor limit"
|
ulimit -n $MAX_FD
|
||||||
esac
|
if [ $? -ne 0 ] ; then
|
||||||
case $MAX_FD in #(
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
'' | soft) :;; #(
|
fi
|
||||||
*)
|
else
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
# shellcheck disable=SC3045
|
fi
|
||||||
ulimit -n "$MAX_FD" ||
|
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Collect all arguments for the java command, stacking in reverse order:
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
# * args from the command line
|
if $darwin; then
|
||||||
# * the main class name
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
# * -classpath
|
fi
|
||||||
# * -D...appname settings
|
|
||||||
# * --module-path (only if needed)
|
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
for arg do
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
if
|
SEP=""
|
||||||
case $arg in #(
|
for dir in $ROOTDIRSRAW ; do
|
||||||
-*) false ;; # don't mess with options #(
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
SEP="|"
|
||||||
[ -e "$t" ] ;; #(
|
|
||||||
*) false ;;
|
|
||||||
esac
|
|
||||||
then
|
|
||||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
|
||||||
fi
|
|
||||||
# Roll the args list around exactly as many times as the number of
|
|
||||||
# args, so each arg winds up back in the position where it started, but
|
|
||||||
# possibly modified.
|
|
||||||
#
|
|
||||||
# NB: a `for` loop captures its iteration list before it begins, so
|
|
||||||
# changing the positional parameters here affects neither the number of
|
|
||||||
# iterations, nor the values presented in `arg`.
|
|
||||||
shift # remove old arg
|
|
||||||
set -- "$@" "$arg" # push replacement arg
|
|
||||||
done
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
0) set -- ;;
|
||||||
|
1) set -- "$args0" ;;
|
||||||
|
2) set -- "$args0" "$args1" ;;
|
||||||
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
|
||||||
# double quotes to make sure that they get re-expanded; and
|
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
|
||||||
|
|
||||||
set -- \
|
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
|
||||||
-classpath "$CLASSPATH" \
|
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
|
||||||
if ! command -v xargs >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
die "xargs is not available"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use "xargs" to parse quoted args.
|
|
||||||
#
|
|
||||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
|
||||||
#
|
|
||||||
# In Bash we could simply go:
|
|
||||||
#
|
|
||||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
|
||||||
# set -- "${ARGS[@]}" "$@"
|
|
||||||
#
|
|
||||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
|
||||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
|
||||||
# character that might be a shell metacharacter, then use eval to reverse
|
|
||||||
# that process (while maintaining the separation between arguments), and wrap
|
|
||||||
# the whole thing up as a single "set" statement.
|
|
||||||
#
|
|
||||||
# This will of course break if any of these variables contains a newline or
|
|
||||||
# an unmatched quote.
|
|
||||||
#
|
|
||||||
|
|
||||||
eval "set -- $(
|
|
||||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
|
||||||
xargs -n1 |
|
|
||||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
|
||||||
tr '\n' ' '
|
|
||||||
)" '"$@"'
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|||||||
15
gradlew.bat
vendored
15
gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
|||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%" == "" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem Gradle startup script for Windows
|
||||||
@@ -25,8 +25,7 @@
|
|||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
@rem This is normally unused
|
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
@@ -76,15 +75,13 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
set EXIT_CODE=%ERRORLEVEL%
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
exit /b 1
|
||||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
|
||||||
exit /b %EXIT_CODE%
|
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|||||||
6580
package-lock.json
generated
6580
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"devDependencies": {
|
|
||||||
"@saithodev/semantic-release-backmerge": "^3.1.0",
|
|
||||||
"@semantic-release/changelog": "^6.0.2",
|
|
||||||
"@semantic-release/git": "^10.0.1",
|
|
||||||
"gradle-semantic-release-plugin": "^1.7.6",
|
|
||||||
"semantic-release": "^20.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +1 @@
|
|||||||
val githubUsername: String = providers.gradleProperty("gpr.user").orNull ?: System.getenv("GITHUB_ACTOR")
|
|
||||||
val githubPassword: String = providers.gradleProperty("gpr.key").orNull ?: System.getenv("GITHUB_TOKEN")
|
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
|
||||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
google()
|
|
||||||
mavenLocal()
|
|
||||||
listOf("multidexlib2", "apktool").forEach { repo ->
|
|
||||||
maven {
|
|
||||||
url = uri("https://maven.pkg.github.com/revanced/$repo")
|
|
||||||
credentials {
|
|
||||||
username = githubUsername
|
|
||||||
password = githubPassword
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProject.name = "revanced-patcher"
|
rootProject.name = "revanced-patcher"
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
interface IntegrationsConsumer {
|
|
||||||
fun acceptIntegrations(integrations: List<File>)
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import brut.androlib.apk.ApkInfo
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Metadata about a package.
|
|
||||||
*/
|
|
||||||
class PackageMetadata internal constructor(internal val apkInfo: ApkInfo) {
|
|
||||||
lateinit var packageName: String
|
|
||||||
internal set
|
|
||||||
|
|
||||||
lateinit var packageVersion: String
|
|
||||||
internal set
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
@file:Suppress("unused")
|
|
||||||
|
|
||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.PatchClass
|
|
||||||
import dalvik.system.DexClassLoader
|
|
||||||
import lanchon.multidexlib2.BasicDexFileNamer
|
|
||||||
import lanchon.multidexlib2.MultiDexIO
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URLClassLoader
|
|
||||||
import java.util.jar.JarFile
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A patch bundle.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param fromClasses The classes to get [Patch]es from.
|
|
||||||
*/
|
|
||||||
sealed class PatchBundleLoader private constructor(
|
|
||||||
fromClasses: Iterable<Class<*>>
|
|
||||||
) : MutableList<PatchClass> by mutableListOf() {
|
|
||||||
init {
|
|
||||||
fromClasses.filter {
|
|
||||||
if (it.isAnnotation) return@filter false
|
|
||||||
|
|
||||||
it.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class) != null
|
|
||||||
}.map {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
it as PatchClass
|
|
||||||
}.sortedBy {
|
|
||||||
it.patchName
|
|
||||||
}.let { addAll(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [PatchBundleLoader] for JAR files.
|
|
||||||
*
|
|
||||||
* @param patchBundles The path to patch bundles of JAR format.
|
|
||||||
*/
|
|
||||||
class Jar(vararg patchBundles: File) : PatchBundleLoader(
|
|
||||||
with(
|
|
||||||
URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray())
|
|
||||||
) {
|
|
||||||
patchBundles.flatMap { patchBundle ->
|
|
||||||
// Get the names of all classes in the DEX file.
|
|
||||||
|
|
||||||
JarFile(patchBundle).entries().asSequence()
|
|
||||||
.filter { it.name.endsWith(".class") }
|
|
||||||
.map { it.name.replace('/', '.').replace(".class", "") }
|
|
||||||
.map { loadClass(it) }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [PatchBundleLoader] for [Dex] files.
|
|
||||||
*
|
|
||||||
* @param patchBundles The path to patch bundles of DEX format.
|
|
||||||
* @param optimizedDexDirectory The directory to store optimized DEX files in.
|
|
||||||
* This parameter is deprecated and has no effect since API level 26.
|
|
||||||
*/
|
|
||||||
class Dex(vararg patchBundles: File, optimizedDexDirectory: File? = null) : PatchBundleLoader(
|
|
||||||
with(
|
|
||||||
DexClassLoader(
|
|
||||||
patchBundles.joinToString(File.pathSeparator) { it.absolutePath }, optimizedDexDirectory?.absolutePath,
|
|
||||||
null,
|
|
||||||
PatchBundleLoader::class.java.classLoader
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
patchBundles
|
|
||||||
.flatMap {
|
|
||||||
MultiDexIO.readDexFile(true, it, BasicDexFileNamer(), null, null).classes
|
|
||||||
}
|
|
||||||
.map { classDef -> classDef.type.substring(1, classDef.length - 1) }
|
|
||||||
.map { loadClass(it) }
|
|
||||||
}) {
|
|
||||||
@Deprecated("This constructor is deprecated. Use the constructor with the second parameter instead.")
|
|
||||||
constructor(vararg patchBundles: File) : this(*patchBundles, optimizedDexDirectory = null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import java.util.function.Function
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
interface PatchExecutorFunction : Function<Boolean, Flow<PatchResult>>
|
|
||||||
@@ -1,236 +1,70 @@
|
|||||||
package app.revanced.patcher
|
package app.revanced.patcher
|
||||||
|
|
||||||
import app.revanced.patcher.data.Context
|
import app.revanced.patcher.cache.Cache
|
||||||
import app.revanced.patcher.data.ResourceContext
|
import app.revanced.patcher.patch.Patch
|
||||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
import app.revanced.patcher.resolver.MethodResolver
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.dependencies
|
import app.revanced.patcher.signature.Signature
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
import app.revanced.patcher.util.Io
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.requiresIntegrations
|
import org.objectweb.asm.tree.ClassNode
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import java.io.IOException
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolveUsingLookupMap
|
import java.io.InputStream
|
||||||
import app.revanced.patcher.patch.*
|
import java.io.OutputStream
|
||||||
import kotlinx.coroutines.flow.flow
|
|
||||||
import java.io.Closeable
|
|
||||||
import java.io.File
|
|
||||||
import java.util.function.Supplier
|
|
||||||
import java.util.logging.Level
|
|
||||||
import java.util.logging.LogManager
|
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ReVanced Patcher.
|
* The Patcher class.
|
||||||
|
* ***It is of utmost importance that the input and output streams are NEVER closed.***
|
||||||
*
|
*
|
||||||
* @param options The options for the patcher.
|
* @param input the input stream to read from, must be a JAR
|
||||||
|
* @param output the output stream to write to
|
||||||
|
* @param signatures the signatures
|
||||||
|
* @sample app.revanced.patcher.PatcherTest
|
||||||
|
* @throws IOException if one of the streams are closed
|
||||||
*/
|
*/
|
||||||
class Patcher(
|
class Patcher(
|
||||||
private val options: PatcherOptions
|
private val input: InputStream,
|
||||||
) : PatchExecutorFunction, PatchesConsumer, IntegrationsConsumer, Supplier<PatcherResult>, Closeable {
|
private val output: OutputStream,
|
||||||
private val logger = Logger.getLogger(Patcher::class.java.name)
|
signatures: Array<Signature>,
|
||||||
|
) {
|
||||||
|
var cache: Cache
|
||||||
|
|
||||||
/**
|
private var io: Io
|
||||||
* The context of ReVanced [Patcher].
|
private val patches = mutableListOf<Patch>()
|
||||||
* This holds the current state of the patcher.
|
|
||||||
*/
|
|
||||||
val context = PatcherContext(options)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
LogManager.getLogManager().let { manager ->
|
val classes = mutableListOf<ClassNode>()
|
||||||
// Disable root logger.
|
io = Io(input, output, classes)
|
||||||
manager.getLogger("").level = Level.OFF
|
io.readFromJar()
|
||||||
|
cache = Cache(classes, MethodResolver(classes, signatures).resolve())
|
||||||
// Enable ReVanced logging only.
|
|
||||||
manager.loggerNames
|
|
||||||
.toList()
|
|
||||||
.filter { it.startsWith("app.revanced") }
|
|
||||||
.map { manager.getLogger(it) }
|
|
||||||
.forEach { it.level = Level.INFO }
|
|
||||||
}
|
|
||||||
|
|
||||||
context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.MANIFEST_ONLY)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun acceptPatches(patches: List<PatchClass>) {
|
|
||||||
/**
|
|
||||||
* Returns true if at least one patches or its dependencies matches the given predicate.
|
|
||||||
*/
|
|
||||||
fun PatchClass.anyRecursively(predicate: (PatchClass) -> Boolean): Boolean =
|
|
||||||
predicate(this) || dependencies?.any { dependency ->
|
|
||||||
dependency.java.anyRecursively(predicate)
|
|
||||||
} ?: false
|
|
||||||
|
|
||||||
// Determine if resource patching is required.
|
|
||||||
for (patch in patches) {
|
|
||||||
if (patch.anyRecursively { ResourcePatch::class.java.isAssignableFrom(it) }) {
|
|
||||||
options.resourceDecodingMode = ResourceContext.ResourceDecodingMode.FULL
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if merging integrations is required.
|
|
||||||
for (patch in patches) {
|
|
||||||
if (patch.anyRecursively { it.requiresIntegrations }) {
|
|
||||||
context.bytecodeContext.integrations.merge = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.patches.addAll(patches)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add integrations to the [Patcher].
|
* Saves the output to the output stream.
|
||||||
|
* Calling this method will close the input and output streams,
|
||||||
|
* meaning this method should NEVER be called after.
|
||||||
*
|
*
|
||||||
* @param integrations The integrations to add. Must be a DEX file or container of DEX files.
|
* @throws IOException if one of the streams are closed
|
||||||
*/
|
*/
|
||||||
override fun acceptIntegrations(integrations: List<File>) {
|
fun save() {
|
||||||
context.bytecodeContext.integrations.addAll(integrations)
|
io.saveAsJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun addPatches(vararg patches: Patch) {
|
||||||
* Execute [Patch]es that were added to ReVanced [Patcher].
|
this.patches.addAll(patches)
|
||||||
*
|
}
|
||||||
* @param returnOnError If true, ReVanced [Patcher] will return immediately if a [Patch] fails.
|
|
||||||
* @return A pair of the name of the [Patch] and its [PatchResult].
|
|
||||||
*/
|
|
||||||
override fun apply(returnOnError: Boolean) = flow {
|
|
||||||
class ExecutedPatch(val patchInstance: Patch<Context<*>>, val patchResult: PatchResult)
|
|
||||||
|
|
||||||
/**
|
fun applyPatches(stopOnError: Boolean = false): Map<String, Result<Nothing?>> {
|
||||||
* Execute a [Patch] and its dependencies recursively.
|
return buildMap {
|
||||||
*
|
for (patch in patches) {
|
||||||
* @param patchClass The [Patch] to execute.
|
val result: Result<Nothing?> = try {
|
||||||
* @param executedPatches A map to prevent [Patch]es from being executed twice due to dependencies.
|
val pr = patch.execute(cache)
|
||||||
* @return The result of executing the [Patch].
|
if (pr.isSuccess()) continue
|
||||||
*/
|
Result.failure(Exception(pr.error()?.errorMessage() ?: "Unknown error"))
|
||||||
fun executePatch(
|
} catch (e: Exception) {
|
||||||
patchClass: PatchClass,
|
Result.failure(e)
|
||||||
executedPatches: LinkedHashMap<String, ExecutedPatch>
|
|
||||||
): PatchResult {
|
|
||||||
val patchName = patchClass.patchName
|
|
||||||
|
|
||||||
executedPatches[patchName]?.let { executedPatch ->
|
|
||||||
executedPatch.patchResult.exception ?: return executedPatch.patchResult
|
|
||||||
|
|
||||||
// Return a new result with an exception indicating that the patch was not executed previously,
|
|
||||||
// because it is a dependency of another patch that failed.
|
|
||||||
return PatchResult(patchName, PatchException("'$patchName' did not succeed previously"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively execute all dependency patches.
|
|
||||||
patchClass.dependencies?.forEach { dependencyClass ->
|
|
||||||
val dependency = dependencyClass.java
|
|
||||||
|
|
||||||
val result = executePatch(dependency, executedPatches)
|
|
||||||
|
|
||||||
result.exception?.let {
|
|
||||||
return PatchResult(
|
|
||||||
patchName,
|
|
||||||
PatchException(
|
|
||||||
"'$patchName' depends on '${dependency.patchName}' that raised an exception: $it"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
this[patch.patchName] = result
|
||||||
|
if (stopOnError && result.isFailure) break
|
||||||
// TODO: Implement this in a more polymorphic way.
|
|
||||||
val patchInstance = patchClass.getDeclaredConstructor().newInstance()
|
|
||||||
|
|
||||||
val patchContext = if (patchInstance is BytecodePatch) {
|
|
||||||
patchInstance.fingerprints?.resolveUsingLookupMap(context.bytecodeContext)
|
|
||||||
|
|
||||||
context.bytecodeContext
|
|
||||||
} else {
|
|
||||||
context.resourceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
patchInstance.execute(patchContext)
|
|
||||||
|
|
||||||
PatchResult(patchName)
|
|
||||||
} catch (exception: PatchException) {
|
|
||||||
PatchResult(patchName, exception)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
PatchResult(patchName, PatchException(exception))
|
|
||||||
}.also { executedPatches[patchName] = ExecutedPatch(patchInstance, it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush()
|
|
||||||
|
|
||||||
MethodFingerprint.initializeFingerprintResolutionLookupMaps(context.bytecodeContext)
|
|
||||||
|
|
||||||
// Prevent from decoding the app manifest twice if it is not needed.
|
|
||||||
if (options.resourceDecodingMode == ResourceContext.ResourceDecodingMode.FULL)
|
|
||||||
context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.FULL)
|
|
||||||
|
|
||||||
logger.info("Executing patches")
|
|
||||||
|
|
||||||
val executedPatches = LinkedHashMap<String, ExecutedPatch>() // Key is name.
|
|
||||||
|
|
||||||
context.patches.forEach { patch ->
|
|
||||||
val result = executePatch(patch, executedPatches)
|
|
||||||
|
|
||||||
// If the patch failed, or if the patch is not closeable, emit the result.
|
|
||||||
// Results of patches that are closeable will be emitted later.
|
|
||||||
result.exception?.let {
|
|
||||||
emit(result)
|
|
||||||
|
|
||||||
if (returnOnError) return@flow
|
|
||||||
} ?: run {
|
|
||||||
if (executedPatches[result.patchName]!!.patchInstance is Closeable) return@run
|
|
||||||
|
|
||||||
emit(result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
executedPatches.values
|
|
||||||
.filter { it.patchResult.exception == null }
|
|
||||||
.filter { it.patchInstance is Closeable }.asReversed().forEach { executedPatch ->
|
|
||||||
val patchName = executedPatch.patchResult.patchName
|
|
||||||
|
|
||||||
val result = try {
|
|
||||||
(executedPatch.patchInstance as Closeable).close()
|
|
||||||
|
|
||||||
executedPatch.patchResult
|
|
||||||
} catch (exception: PatchException) {
|
|
||||||
PatchResult(patchName, exception)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
PatchResult(patchName, PatchException(exception))
|
|
||||||
}
|
|
||||||
|
|
||||||
result.exception?.let {
|
|
||||||
emit(
|
|
||||||
PatchResult(
|
|
||||||
patchName,
|
|
||||||
PatchException("'$patchName' raised an exception while being closed: $it")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (returnOnError) return@flow
|
|
||||||
} ?: run {
|
|
||||||
executedPatch
|
|
||||||
.patchInstance::class
|
|
||||||
.java
|
|
||||||
.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)
|
|
||||||
?: return@run
|
|
||||||
|
|
||||||
emit(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
MethodFingerprint.clearFingerprintResolutionLookupMaps()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile and save the patched APK file.
|
|
||||||
*
|
|
||||||
* @return The [PatcherResult] containing the patched input files.
|
|
||||||
*/
|
|
||||||
override fun get() = PatcherResult(
|
|
||||||
context.bytecodeContext.get(),
|
|
||||||
context.resourceContext.get(),
|
|
||||||
context.packageMetadata.apkInfo.doNotCompress?.toList()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.PatchClass
|
|
||||||
import brut.androlib.apk.ApkInfo
|
|
||||||
import brut.directory.ExtFile
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A context for ReVanced [Patcher].
|
|
||||||
*
|
|
||||||
* @param options The [PatcherOptions] used to create this context.
|
|
||||||
*/
|
|
||||||
class PatcherContext internal constructor(options: PatcherOptions) {
|
|
||||||
/**
|
|
||||||
* [PackageMetadata] of the supplied [PatcherOptions.inputFile].
|
|
||||||
*/
|
|
||||||
val packageMetadata = PackageMetadata(ApkInfo(ExtFile(options.inputFile)))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of [Patch]es to execute.
|
|
||||||
*/
|
|
||||||
internal val patches = mutableListOf<PatchClass>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The [ResourceContext] of this [PatcherContext].
|
|
||||||
* This holds the current state of the resources.
|
|
||||||
*/
|
|
||||||
internal val resourceContext = ResourceContext(this, options)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The [BytecodeContext] of this [PatcherContext].
|
|
||||||
* This holds the current state of the bytecode.
|
|
||||||
*/
|
|
||||||
internal val bytecodeContext = BytecodeContext(options)
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.logging.impl.NopLogger
|
|
||||||
import brut.androlib.Config
|
|
||||||
import java.io.File
|
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for ReVanced [Patcher].
|
|
||||||
* @param inputFile The input file to patch.
|
|
||||||
* @param resourceCachePath The path to the directory to use for caching resources.
|
|
||||||
* @param aaptBinaryPath The path to a custom aapt binary.
|
|
||||||
* @param frameworkFileDirectory The path to the directory to cache the framework file in.
|
|
||||||
* @param unusedLogger The logger to use for logging.
|
|
||||||
*/
|
|
||||||
data class PatcherOptions
|
|
||||||
@Deprecated("Use the constructor without the logger parameter instead")
|
|
||||||
constructor(
|
|
||||||
internal val inputFile: File,
|
|
||||||
internal val resourceCachePath: File = File("revanced-resource-cache"),
|
|
||||||
internal val aaptBinaryPath: String? = null,
|
|
||||||
internal val frameworkFileDirectory: String? = null,
|
|
||||||
internal val unusedLogger: app.revanced.patcher.logging.Logger = NopLogger
|
|
||||||
) {
|
|
||||||
private val logger = Logger.getLogger(PatcherOptions::class.java.name)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mode to use for resource decoding.
|
|
||||||
* @see ResourceContext.ResourceDecodingMode
|
|
||||||
*/
|
|
||||||
internal var resourceDecodingMode = ResourceContext.ResourceDecodingMode.MANIFEST_ONLY
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The configuration to use for resource decoding and compiling.
|
|
||||||
*/
|
|
||||||
internal val resourceConfig = Config.getDefaultConfig().apply {
|
|
||||||
useAapt2 = true
|
|
||||||
aaptPath = aaptBinaryPath ?: ""
|
|
||||||
frameworkDirectory = frameworkFileDirectory
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for ReVanced [Patcher].
|
|
||||||
* @param inputFile The input file to patch.
|
|
||||||
* @param resourceCachePath The path to the directory to use for caching resources.
|
|
||||||
* @param aaptBinaryPath The path to a custom aapt binary.
|
|
||||||
* @param frameworkFileDirectory The path to the directory to cache the framework file in.
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
inputFile: File,
|
|
||||||
resourceCachePath: File = File("revanced-resource-cache"),
|
|
||||||
aaptBinaryPath: String? = null,
|
|
||||||
frameworkFileDirectory: String? = null,
|
|
||||||
) : this(
|
|
||||||
inputFile,
|
|
||||||
resourceCachePath,
|
|
||||||
aaptBinaryPath,
|
|
||||||
frameworkFileDirectory,
|
|
||||||
NopLogger
|
|
||||||
)
|
|
||||||
|
|
||||||
fun recreateResourceCacheDirectory() = resourceCachePath.also {
|
|
||||||
if (it.exists()) {
|
|
||||||
logger.info("Deleting existing resource cache directory")
|
|
||||||
|
|
||||||
if (!it.deleteRecursively())
|
|
||||||
logger.severe("Failed to delete existing resource cache directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
it.mkdirs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The result of a patcher.
|
|
||||||
* @param dexFiles The patched dex files.
|
|
||||||
* @param resourceFile File containing resources that need to be extracted into the APK.
|
|
||||||
* @param doNotCompress List of relative paths of files to exclude from compressing.
|
|
||||||
*/
|
|
||||||
data class PatcherResult(
|
|
||||||
val dexFiles: List<PatchedDexFile>,
|
|
||||||
val resourceFile: File?,
|
|
||||||
val doNotCompress: List<String>? = null
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* Wrapper for dex files.
|
|
||||||
* @param name The original name of the dex file.
|
|
||||||
* @param stream The dex file as [InputStream].
|
|
||||||
*/
|
|
||||||
class PatchedDexFile(val name: String, val stream: InputStream)
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package app.revanced.patcher
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.PatchClass
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
interface PatchesConsumer {
|
|
||||||
fun acceptPatches(patches: List<PatchClass>)
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package app.revanced.patcher.annotation
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation to constrain a [Patch] to compatible packages.
|
|
||||||
* @param compatiblePackages A list of packages a [Patch] is compatible with.
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
annotation class Compatibility(
|
|
||||||
val compatiblePackages: Array<Package>,
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation to represent packages a patch can be compatible with.
|
|
||||||
* @param name The package identifier name.
|
|
||||||
* @param versions The versions of the package the [Patch] is compatible with.
|
|
||||||
*/
|
|
||||||
@Target()
|
|
||||||
annotation class Package(
|
|
||||||
val name: String,
|
|
||||||
val versions: Array<String> = [],
|
|
||||||
)
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package app.revanced.patcher.annotation
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation to name a [Patch].
|
|
||||||
* @param name A suggestive name for the [Patch].
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
annotation class Name(
|
|
||||||
val name: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation to describe a [Patch].
|
|
||||||
* @param description A description for the [Patch].
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
annotation class Description(
|
|
||||||
val description: String,
|
|
||||||
)
|
|
||||||
16
src/main/kotlin/app/revanced/patcher/cache/Cache.kt
vendored
Normal file
16
src/main/kotlin/app/revanced/patcher/cache/Cache.kt
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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)
|
||||||
22
src/main/kotlin/app/revanced/patcher/cache/PatchData.kt
vendored
Normal file
22
src/main/kotlin/app/revanced/patcher/cache/PatchData.kt
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
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
|
||||||
|
)
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
package app.revanced.patcher.data
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatcherContext
|
|
||||||
import app.revanced.patcher.PatcherOptions
|
|
||||||
import app.revanced.patcher.PatcherResult
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.annotations.RequiresIntegrations
|
|
||||||
import app.revanced.patcher.util.ClassMerger.merge
|
|
||||||
import app.revanced.patcher.util.ProxyClassList
|
|
||||||
import app.revanced.patcher.util.method.MethodWalker
|
|
||||||
import app.revanced.patcher.util.proxy.ClassProxy
|
|
||||||
import com.android.tools.smali.dexlib2.Opcodes
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
import com.android.tools.smali.dexlib2.iface.DexFile
|
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
|
||||||
import com.android.tools.smali.dexlib2.writer.io.MemoryDataStore
|
|
||||||
import lanchon.multidexlib2.BasicDexFileNamer
|
|
||||||
import lanchon.multidexlib2.DexIO
|
|
||||||
import lanchon.multidexlib2.MultiDexIO
|
|
||||||
import java.io.File
|
|
||||||
import java.io.Flushable
|
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A context for bytecode.
|
|
||||||
* This holds the current state of the bytecode.
|
|
||||||
*
|
|
||||||
* @param options The [PatcherOptions] used to create this context.
|
|
||||||
*/
|
|
||||||
class BytecodeContext internal constructor(private val options: PatcherOptions) :
|
|
||||||
Context<List<PatcherResult.PatchedDexFile>> {
|
|
||||||
private val logger = Logger.getLogger(BytecodeContext::class.java.name)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [Opcodes] of the supplied [PatcherOptions.inputFile].
|
|
||||||
*/
|
|
||||||
internal lateinit var opcodes: Opcodes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of classes.
|
|
||||||
*/
|
|
||||||
val classes by lazy {
|
|
||||||
ProxyClassList(
|
|
||||||
MultiDexIO.readDexFile(
|
|
||||||
true, options.inputFile, BasicDexFileNamer(), null, null
|
|
||||||
).also { opcodes = it.opcodes }.classes.toMutableSet()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The [Integrations] of this [PatcherContext].
|
|
||||||
*/
|
|
||||||
internal val integrations = Integrations()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a class by a given class name.
|
|
||||||
*
|
|
||||||
* @param className The name of the class.
|
|
||||||
* @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.
|
|
||||||
*
|
|
||||||
* @param predicate A predicate to match the class.
|
|
||||||
* @return A proxy for the first class that matches the predicate.
|
|
||||||
*/
|
|
||||||
fun findClass(predicate: (ClassDef) -> Boolean) =
|
|
||||||
// if we already proxied the class matching the predicate...
|
|
||||||
classes.proxies.firstOrNull { predicate(it.immutableClass) } ?:
|
|
||||||
// else resolve the class to a proxy and return it, if the predicate is matching a class
|
|
||||||
classes.find(predicate)?.let { proxy(it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy a class.
|
|
||||||
* This will allow the class to be modified.
|
|
||||||
*
|
|
||||||
* @param classDef The class to proxy.
|
|
||||||
* @return A proxy for the class.
|
|
||||||
*/
|
|
||||||
fun proxy(classDef: ClassDef) = this.classes.proxies.find { it.immutableClass.type == classDef.type } ?: let {
|
|
||||||
ClassProxy(classDef).also { this.classes.add(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a [MethodWalker] instance for the current [BytecodeContext].
|
|
||||||
*
|
|
||||||
* @param startMethod The method to start at.
|
|
||||||
* @return A [MethodWalker] instance.
|
|
||||||
*/
|
|
||||||
fun toMethodWalker(startMethod: Method) = MethodWalker(this, startMethod)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The integrations of a [PatcherContext].
|
|
||||||
*/
|
|
||||||
internal inner class Integrations : MutableList<File> by mutableListOf(), Flushable {
|
|
||||||
/**
|
|
||||||
* Whether to merge integrations.
|
|
||||||
* True when any supplied [Patch] is annotated with [RequiresIntegrations].
|
|
||||||
*/
|
|
||||||
var merge = false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merge integrations into the [BytecodeContext] and flush all [Integrations].
|
|
||||||
*/
|
|
||||||
override fun flush() {
|
|
||||||
if (!merge) return
|
|
||||||
|
|
||||||
logger.info("Merging integrations")
|
|
||||||
|
|
||||||
// TODO: Multi-thread this.
|
|
||||||
this@Integrations.forEach { integrations ->
|
|
||||||
MultiDexIO.readDexFile(
|
|
||||||
true,
|
|
||||||
integrations, BasicDexFileNamer(),
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
).classes.forEach classDef@{ classDef ->
|
|
||||||
val existingClass = classes.find { it.type == classDef.type } ?: run {
|
|
||||||
logger.fine("Merging $classDef")
|
|
||||||
classes.add(classDef)
|
|
||||||
return@classDef
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.fine("$classDef exists. Adding missing methods and fields.")
|
|
||||||
|
|
||||||
existingClass.merge(classDef, this@BytecodeContext).let { mergedClass ->
|
|
||||||
// If the class was merged, replace the original class with the merged class.
|
|
||||||
if (mergedClass === existingClass) return@let
|
|
||||||
classes.apply { remove(existingClass); add(mergedClass) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile bytecode from the [BytecodeContext].
|
|
||||||
*
|
|
||||||
* @return The compiled bytecode.
|
|
||||||
*/
|
|
||||||
override fun get(): List<PatcherResult.PatchedDexFile> {
|
|
||||||
logger.info("Compiling modified dex files")
|
|
||||||
|
|
||||||
return mutableMapOf<String, MemoryDataStore>().apply {
|
|
||||||
MultiDexIO.writeDexFile(
|
|
||||||
true, -1, // Defaults to amount of available cores.
|
|
||||||
this, BasicDexFileNamer(), object : DexFile {
|
|
||||||
override fun getClasses() = this@BytecodeContext.classes.also(ProxyClassList::replaceClasses)
|
|
||||||
override fun getOpcodes() = this@BytecodeContext.opcodes
|
|
||||||
}, DexIO.DEFAULT_MAX_DEX_POOL_SIZE, null
|
|
||||||
)
|
|
||||||
}.map { PatcherResult.PatchedDexFile(it.key, it.value.readAt(0)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patcher.data
|
|
||||||
|
|
||||||
import java.util.function.Supplier
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A common interface for contexts such as [ResourceContext] and [BytecodeContext].
|
|
||||||
*/
|
|
||||||
|
|
||||||
sealed interface Context<T> : Supplier<T>
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package app.revanced.patcher.data
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatcherContext
|
|
||||||
import app.revanced.patcher.PatcherOptions
|
|
||||||
import app.revanced.patcher.util.DomFileEditor
|
|
||||||
import brut.androlib.AaptInvoker
|
|
||||||
import brut.androlib.ApkDecoder
|
|
||||||
import brut.androlib.apk.UsesFramework
|
|
||||||
import brut.androlib.res.Framework
|
|
||||||
import brut.androlib.res.ResourcesDecoder
|
|
||||||
import brut.androlib.res.decoder.AndroidManifestResourceParser
|
|
||||||
import brut.androlib.res.decoder.XmlPullStreamDecoder
|
|
||||||
import brut.androlib.res.xml.ResXmlPatcher
|
|
||||||
import brut.directory.ExtFile
|
|
||||||
import java.io.File
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A context for resources.
|
|
||||||
* This holds the current state of the resources.
|
|
||||||
*
|
|
||||||
* @param context The [PatcherContext] to create the context for.
|
|
||||||
*/
|
|
||||||
class ResourceContext internal constructor(
|
|
||||||
private val context: PatcherContext,
|
|
||||||
private val options: PatcherOptions
|
|
||||||
) : Context<File?>, Iterable<File> {
|
|
||||||
private val logger = Logger.getLogger(ResourceContext::class.java.name)
|
|
||||||
|
|
||||||
val xmlEditor = XmlFileHolder()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode resources for the patcher.
|
|
||||||
*
|
|
||||||
* @param mode The [ResourceDecodingMode] to use when decoding.
|
|
||||||
*/
|
|
||||||
internal fun decodeResources(mode: ResourceDecodingMode) = with(context.packageMetadata.apkInfo) {
|
|
||||||
// Needed to decode resources.
|
|
||||||
val resourcesDecoder = ResourcesDecoder(options.resourceConfig, this)
|
|
||||||
|
|
||||||
when (mode) {
|
|
||||||
ResourceDecodingMode.FULL -> {
|
|
||||||
val outDir = options.recreateResourceCacheDirectory()
|
|
||||||
|
|
||||||
logger.info("Decoding resources")
|
|
||||||
|
|
||||||
resourcesDecoder.decodeResources(outDir)
|
|
||||||
resourcesDecoder.decodeManifest(outDir)
|
|
||||||
|
|
||||||
// Needed to record uncompressed files.
|
|
||||||
val apkDecoder = ApkDecoder(options.resourceConfig, this)
|
|
||||||
apkDecoder.recordUncompressedFiles(resourcesDecoder.resFileMapping)
|
|
||||||
|
|
||||||
usesFramework = UsesFramework().apply {
|
|
||||||
ids = resourcesDecoder.resTable.listFramePackages().map { it.id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceDecodingMode.MANIFEST_ONLY -> {
|
|
||||||
logger.info("Decoding app manifest")
|
|
||||||
|
|
||||||
// Decode manually instead of using resourceDecoder.decodeManifest
|
|
||||||
// because it does not support decoding to an OutputStream.
|
|
||||||
XmlPullStreamDecoder(
|
|
||||||
AndroidManifestResourceParser(resourcesDecoder.resTable),
|
|
||||||
resourcesDecoder.resXmlSerializer
|
|
||||||
).decodeManifest(
|
|
||||||
apkFile.directory.getFileInput("AndroidManifest.xml"),
|
|
||||||
// Older Android versions do not support OutputStream.nullOutputStream()
|
|
||||||
object : OutputStream() {
|
|
||||||
override fun write(b: Int) { /* do nothing */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get the package name and version from the manifest using the XmlPullStreamDecoder.
|
|
||||||
// XmlPullStreamDecoder.decodeManifest() sets metadata.apkInfo.
|
|
||||||
context.packageMetadata.let { metadata ->
|
|
||||||
metadata.packageName = resourcesDecoder.resTable.packageRenamed
|
|
||||||
versionInfo.let {
|
|
||||||
metadata.packageVersion = it.versionName ?: it.versionCode
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The ResTable if flagged as sparse if the main package is not loaded, which is the case here,
|
|
||||||
because ResourcesDecoder.decodeResources loads the main package
|
|
||||||
and not XmlPullStreamDecoder.decodeManifest.
|
|
||||||
See ARSCDecoder.readTableType for more info.
|
|
||||||
|
|
||||||
Set this to false again to prevent the ResTable from being flagged as sparse falsely.
|
|
||||||
*/
|
|
||||||
metadata.apkInfo.sparseResources = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun get(path: String) = options.resourceCachePath.resolve(path)
|
|
||||||
|
|
||||||
override fun iterator() = options.resourceCachePath.walkTopDown().iterator()
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile resources from the [ResourceContext].
|
|
||||||
*
|
|
||||||
* @return The compiled resources.
|
|
||||||
*/
|
|
||||||
override fun get(): File? {
|
|
||||||
var resourceFile: File? = null
|
|
||||||
|
|
||||||
if (options.resourceDecodingMode == ResourceDecodingMode.FULL) {
|
|
||||||
logger.info("Compiling modified resources")
|
|
||||||
|
|
||||||
val cacheDirectory = ExtFile(options.resourceCachePath)
|
|
||||||
val aaptFile = cacheDirectory.resolve("aapt_temp_file").also {
|
|
||||||
Files.deleteIfExists(it.toPath())
|
|
||||||
}.also { resourceFile = it }
|
|
||||||
|
|
||||||
try {
|
|
||||||
AaptInvoker(
|
|
||||||
options.resourceConfig, context.packageMetadata.apkInfo
|
|
||||||
).invokeAapt(aaptFile,
|
|
||||||
cacheDirectory.resolve("AndroidManifest.xml").also {
|
|
||||||
ResXmlPatcher.fixingPublicAttrsInProviderAttributes(it)
|
|
||||||
},
|
|
||||||
cacheDirectory.resolve("res"),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
context.packageMetadata.apkInfo.usesFramework.let { usesFramework ->
|
|
||||||
usesFramework.ids.map { id ->
|
|
||||||
Framework(options.resourceConfig).getFrameworkApk(id, usesFramework.tag)
|
|
||||||
}.toTypedArray()
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
cacheDirectory.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourceFile
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of decoding the resources.
|
|
||||||
*/
|
|
||||||
internal enum class ResourceDecodingMode {
|
|
||||||
/**
|
|
||||||
* Decode all resources.
|
|
||||||
*/
|
|
||||||
FULL,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode the manifest file only.
|
|
||||||
*/
|
|
||||||
MANIFEST_ONLY,
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class XmlFileHolder {
|
|
||||||
operator fun get(inputStream: InputStream) =
|
|
||||||
DomFileEditor(inputStream)
|
|
||||||
|
|
||||||
operator fun get(path: String): DomFileEditor {
|
|
||||||
return DomFileEditor(this@ResourceContext[path])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package app.revanced.patcher.extensions
|
|
||||||
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
internal object AnnotationExtensions {
|
|
||||||
/**
|
|
||||||
* Recursively find a given annotation on a class.
|
|
||||||
*
|
|
||||||
* @param targetAnnotation The annotation to find.
|
|
||||||
* @return The annotation.
|
|
||||||
*/
|
|
||||||
fun <T : Annotation> Class<*>.findAnnotationRecursively(targetAnnotation: KClass<T>): T? {
|
|
||||||
fun <T : Annotation> Class<*>.findAnnotationRecursively(
|
|
||||||
targetAnnotation: Class<T>, traversed: MutableSet<Annotation>
|
|
||||||
): T? {
|
|
||||||
val found = this.annotations.firstOrNull { it.annotationClass.java.name == targetAnnotation.name }
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST") if (found != null) return found as T
|
|
||||||
|
|
||||||
for (annotation in this.annotations) {
|
|
||||||
if (traversed.contains(annotation)) continue
|
|
||||||
traversed.add(annotation)
|
|
||||||
|
|
||||||
return (annotation.annotationClass.java.findAnnotationRecursively(targetAnnotation, traversed))
|
|
||||||
?: continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.findAnnotationRecursively(targetAnnotation.java, mutableSetOf())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package app.revanced.patcher.extensions
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a label for the instruction at given index.
|
|
||||||
*
|
|
||||||
* @param index The index to create the label for the instruction at.
|
|
||||||
* @return The label.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.newLabel(index: Int) = implementation!!.newLabelForIndex(index)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise OR operation between two [AccessFlags].
|
|
||||||
*
|
|
||||||
* @param other The other [AccessFlags] to perform the operation with.
|
|
||||||
*/
|
|
||||||
infix fun AccessFlags.or(other: AccessFlags) = value or other.value
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise OR operation between an [AccessFlags] and an [Int].
|
|
||||||
*
|
|
||||||
* @param other The [Int] to perform the operation with.
|
|
||||||
*/
|
|
||||||
infix fun Int.or(other: AccessFlags) = this or other.value
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise OR operation between an [Int] and an [AccessFlags].
|
|
||||||
*
|
|
||||||
* @param other The [AccessFlags] to perform the operation with.
|
|
||||||
*/
|
|
||||||
infix fun AccessFlags.or(other: Int) = value or other
|
|
||||||
@@ -1,330 +0,0 @@
|
|||||||
package app.revanced.patcher.extensions
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
|
||||||
import app.revanced.patcher.util.smali.toInstruction
|
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
|
||||||
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.builder.BuilderOffsetInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.builder.Label
|
|
||||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
|
||||||
import com.android.tools.smali.dexlib2.builder.instruction.*
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|
||||||
|
|
||||||
object InstructionExtensions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add instructions to a method at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to add the instructions at.
|
|
||||||
* @param instructions The instructions to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethodImplementation.addInstructions(
|
|
||||||
index: Int,
|
|
||||||
instructions: List<BuilderInstruction>
|
|
||||||
) = instructions.asReversed().forEach { addInstruction(index, it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add instructions to a method.
|
|
||||||
* The instructions will be added at the end of the method.
|
|
||||||
*
|
|
||||||
* @param instructions The instructions to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethodImplementation.addInstructions(instructions: List<BuilderInstruction>) =
|
|
||||||
instructions.forEach { this.addInstruction(it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove instructions from a method at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to remove the instructions at.
|
|
||||||
* @param count The amount of instructions to remove.
|
|
||||||
*/
|
|
||||||
fun MutableMethodImplementation.removeInstructions(index: Int, count: Int) = repeat(count) {
|
|
||||||
removeInstruction(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the first instructions from a method.
|
|
||||||
*
|
|
||||||
* @param count The amount of instructions to remove.
|
|
||||||
*/
|
|
||||||
fun MutableMethodImplementation.removeInstructions(count: Int) = removeInstructions(0, count)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace instructions at the given index with the given instructions.
|
|
||||||
* The amount of instructions to replace is the amount of instructions in the given list.
|
|
||||||
*
|
|
||||||
* @param index The index to replace the instructions at.
|
|
||||||
* @param instructions The instructions to replace the instructions with.
|
|
||||||
*/
|
|
||||||
fun MutableMethodImplementation.replaceInstructions(index: Int, instructions: List<BuilderInstruction>) {
|
|
||||||
// Remove the instructions at the given index.
|
|
||||||
removeInstructions(index, instructions.size)
|
|
||||||
|
|
||||||
// Add the instructions at the given index.
|
|
||||||
addInstructions(index, instructions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an instruction to a method at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to add the instruction at.
|
|
||||||
* @param instruction The instruction to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstruction(index: Int, instruction: BuilderInstruction) =
|
|
||||||
implementation!!.addInstruction(index, instruction)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an instruction to a method.
|
|
||||||
*
|
|
||||||
* @param instruction The instructions to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstruction(instruction: BuilderInstruction) =
|
|
||||||
implementation!!.addInstruction(instruction)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an instruction to a method at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to add the instruction at.
|
|
||||||
* @param smaliInstructions The instruction to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstruction(index: Int, smaliInstructions: String) =
|
|
||||||
implementation!!.addInstruction(index, smaliInstructions.toInstruction(this))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an instruction to a method.
|
|
||||||
*
|
|
||||||
* @param smaliInstructions The instruction to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstruction(smaliInstructions: String) =
|
|
||||||
implementation!!.addInstruction(smaliInstructions.toInstruction(this))
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add instructions to a method at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to add the instructions at.
|
|
||||||
* @param instructions The instructions to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstructions(index: Int, instructions: List<BuilderInstruction>) =
|
|
||||||
implementation!!.addInstructions(index, instructions)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add instructions to a method.
|
|
||||||
*
|
|
||||||
* @param instructions The instructions to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstructions(instructions: List<BuilderInstruction>) =
|
|
||||||
implementation!!.addInstructions(instructions)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add instructions to a method.
|
|
||||||
*
|
|
||||||
* @param smaliInstructions The instructions to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstructions(index: Int, smaliInstructions: String) =
|
|
||||||
implementation!!.addInstructions(index, smaliInstructions.toInstructions(this))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add instructions to a method.
|
|
||||||
*
|
|
||||||
* @param smaliInstructions The instructions to add.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.addInstructions(smaliInstructions: String) =
|
|
||||||
implementation!!.addInstructions(smaliInstructions.toInstructions(this))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add instructions to a method at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to add the instructions at.
|
|
||||||
* @param smaliInstructions The instructions to add.
|
|
||||||
* @param externalLabels A list of [ExternalLabel] for instructions outside of [smaliInstructions].
|
|
||||||
*/
|
|
||||||
// Special function for adding instructions with external labels.
|
|
||||||
fun MutableMethod.addInstructionsWithLabels(
|
|
||||||
index: Int,
|
|
||||||
smaliInstructions: String,
|
|
||||||
vararg externalLabels: ExternalLabel
|
|
||||||
) {
|
|
||||||
// Create reference dummy instructions for the instructions.
|
|
||||||
val nopSmali = StringBuilder(smaliInstructions).also { builder ->
|
|
||||||
externalLabels.forEach { (name, _) ->
|
|
||||||
builder.append("\n:$name\nnop")
|
|
||||||
}
|
|
||||||
}.toString()
|
|
||||||
|
|
||||||
// Compile the instructions with the dummy labels
|
|
||||||
val compiledInstructions = nopSmali.toInstructions(this)
|
|
||||||
|
|
||||||
// Add the compiled list of instructions to the method.
|
|
||||||
addInstructions(
|
|
||||||
index,
|
|
||||||
compiledInstructions.subList(0, compiledInstructions.size - externalLabels.size)
|
|
||||||
)
|
|
||||||
|
|
||||||
implementation!!.apply {
|
|
||||||
this@apply.instructions.subList(index, index + compiledInstructions.size - externalLabels.size)
|
|
||||||
.forEachIndexed { compiledInstructionIndex, compiledInstruction ->
|
|
||||||
// If the compiled instruction is not an offset instruction, skip it.
|
|
||||||
if (compiledInstruction !is BuilderOffsetInstruction) return@forEachIndexed
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new label for the instruction
|
|
||||||
* and replaces it with the label of the [compiledInstruction] at [compiledInstructionIndex].
|
|
||||||
*/
|
|
||||||
fun Instruction.makeNewLabel() {
|
|
||||||
fun replaceOffset(
|
|
||||||
i: BuilderOffsetInstruction, label: Label
|
|
||||||
): BuilderOffsetInstruction {
|
|
||||||
return when (i) {
|
|
||||||
is BuilderInstruction10t -> BuilderInstruction10t(i.opcode, label)
|
|
||||||
is BuilderInstruction20t -> BuilderInstruction20t(i.opcode, label)
|
|
||||||
is BuilderInstruction21t -> BuilderInstruction21t(i.opcode, i.registerA, label)
|
|
||||||
is BuilderInstruction22t -> BuilderInstruction22t(
|
|
||||||
i.opcode,
|
|
||||||
i.registerA,
|
|
||||||
i.registerB,
|
|
||||||
label
|
|
||||||
)
|
|
||||||
is BuilderInstruction30t -> BuilderInstruction30t(i.opcode, label)
|
|
||||||
is BuilderInstruction31t -> BuilderInstruction31t(i.opcode, i.registerA, label)
|
|
||||||
else -> throw IllegalStateException(
|
|
||||||
"A non-offset instruction was given, this should never happen!"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the final label.
|
|
||||||
val label = newLabelForIndex(this@apply.instructions.indexOf(this))
|
|
||||||
|
|
||||||
// Create the final instruction with the new label.
|
|
||||||
val newInstruction = replaceOffset(
|
|
||||||
compiledInstruction, label
|
|
||||||
)
|
|
||||||
|
|
||||||
// Replace the instruction pointing to the dummy label
|
|
||||||
// with the new instruction pointing to the real instruction.
|
|
||||||
replaceInstruction(index + compiledInstructionIndex, newInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the compiled instruction targets its own instruction,
|
|
||||||
// which means it points to some of its own, simply an offset has to be applied.
|
|
||||||
val labelIndex = compiledInstruction.target.location.index
|
|
||||||
if (labelIndex < compiledInstructions.size - externalLabels.size) {
|
|
||||||
// Get the targets index (insertion index + the index of the dummy instruction).
|
|
||||||
this.instructions[index + labelIndex].makeNewLabel()
|
|
||||||
return@forEachIndexed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since the compiled instruction points to a dummy instruction,
|
|
||||||
// we can find the real instruction which it was created for by calculation.
|
|
||||||
|
|
||||||
// Get the index of the instruction in the externalLabels list
|
|
||||||
// which the dummy instruction was created for.
|
|
||||||
// This works because we created the dummy instructions in the same order as the externalLabels list.
|
|
||||||
val (_, instruction) = externalLabels[(compiledInstructions.size - 1) - labelIndex]
|
|
||||||
instruction.makeNewLabel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an instruction at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to remove the instruction at.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.removeInstruction(index: Int) =
|
|
||||||
implementation!!.removeInstruction(index)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove instructions at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to remove the instructions at.
|
|
||||||
* @param count The amount of instructions to remove.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.removeInstructions(index: Int, count: Int) =
|
|
||||||
implementation!!.removeInstructions(index, count)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove instructions at the given index.
|
|
||||||
*
|
|
||||||
* @param count The amount of instructions to remove.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.removeInstructions(count: Int) =
|
|
||||||
implementation!!.removeInstructions(count)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace an instruction at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to replace the instruction at.
|
|
||||||
* @param instruction The instruction to replace the instruction with.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.replaceInstruction(index: Int, instruction: BuilderInstruction) =
|
|
||||||
implementation!!.replaceInstruction(index, instruction)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace an instruction at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to replace the instruction at.
|
|
||||||
* @param smaliInstruction The smali instruction to replace the instruction with.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.replaceInstruction(index: Int, smaliInstruction: String) =
|
|
||||||
implementation!!.replaceInstruction(index, smaliInstruction.toInstruction(this))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace instructions at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to replace the instructions at.
|
|
||||||
* @param instructions The instructions to replace the instructions with.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.replaceInstructions(index: Int, instructions: List<BuilderInstruction>) =
|
|
||||||
implementation!!.replaceInstructions(index, instructions)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace instructions at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to replace the instructions at.
|
|
||||||
* @param smaliInstructions The smali instructions to replace the instructions with.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.replaceInstructions(index: Int, smaliInstructions: String) =
|
|
||||||
implementation!!.replaceInstructions(index, smaliInstructions.toInstructions(this))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an instruction at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to get the instruction at.
|
|
||||||
* @return The instruction.
|
|
||||||
*/
|
|
||||||
fun MutableMethodImplementation.getInstruction(index: Int): BuilderInstruction = instructions[index]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an instruction at the given index.
|
|
||||||
*
|
|
||||||
* @param index The index to get the instruction at.
|
|
||||||
* @param T The type of instruction to return.
|
|
||||||
* @return The instruction.
|
|
||||||
*/
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun <T> MutableMethodImplementation.getInstruction(index: Int): T = getInstruction(index) as T
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an instruction at the given index.
|
|
||||||
* @param index The index to get the instruction at.
|
|
||||||
* @return The instruction.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.getInstruction(index: Int): BuilderInstruction = implementation!!.getInstruction(index)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an instruction at the given index.
|
|
||||||
* @param index The index to get the instruction at.
|
|
||||||
* @param T The type of instruction to return.
|
|
||||||
* @return The instruction.
|
|
||||||
*/
|
|
||||||
fun <T> MutableMethod.getInstruction(index: Int): T = implementation!!.getInstruction<T>(index)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the instructions of a method.
|
|
||||||
* @return The instructions.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.getInstructions(): MutableList<BuilderInstruction> = implementation!!.instructions
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package app.revanced.patcher.extensions
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
object MethodFingerprintExtensions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of a [MethodFingerprint].
|
|
||||||
*/
|
|
||||||
val MethodFingerprint.name: String
|
|
||||||
get() = this.javaClass.simpleName
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The [FuzzyPatternScanMethod] annotation of a [MethodFingerprint].
|
|
||||||
*/
|
|
||||||
val MethodFingerprint.fuzzyPatternScanMethod
|
|
||||||
get() = javaClass.findAnnotationRecursively(FuzzyPatternScanMethod::class)
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package app.revanced.patcher.extensions
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
|
||||||
import app.revanced.patcher.patch.OptionsContainer
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.PatchClass
|
|
||||||
import app.revanced.patcher.patch.PatchOptions
|
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
|
||||||
import app.revanced.patcher.patch.annotations.RequiresIntegrations
|
|
||||||
import kotlin.reflect.KVisibility
|
|
||||||
import kotlin.reflect.full.companionObject
|
|
||||||
import kotlin.reflect.full.companionObjectInstance
|
|
||||||
|
|
||||||
object PatchExtensions {
|
|
||||||
/**
|
|
||||||
* The name of a [Patch].
|
|
||||||
*/
|
|
||||||
val PatchClass.patchName: String
|
|
||||||
get() = findAnnotationRecursively(Name::class)?.name ?: this.simpleName
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Weather or not a [Patch] should be included.
|
|
||||||
*/
|
|
||||||
val PatchClass.include
|
|
||||||
get() = findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)!!.include
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The description of a [Patch].
|
|
||||||
*/
|
|
||||||
val PatchClass.description
|
|
||||||
get() = findAnnotationRecursively(Description::class)?.description
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The dependencies of a [Patch].
|
|
||||||
*/
|
|
||||||
val PatchClass.dependencies
|
|
||||||
get() = findAnnotationRecursively(DependsOn::class)?.dependencies
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The packages a [Patch] is compatible with.
|
|
||||||
*/
|
|
||||||
val PatchClass.compatiblePackages
|
|
||||||
get() = findAnnotationRecursively(Compatibility::class)?.compatiblePackages
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Weather or not a [Patch] requires integrations.
|
|
||||||
*/
|
|
||||||
internal val PatchClass.requiresIntegrations
|
|
||||||
get() = findAnnotationRecursively(RequiresIntegrations::class) != null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The options of a [Patch].
|
|
||||||
*/
|
|
||||||
val PatchClass.options: PatchOptions?
|
|
||||||
get() = kotlin.companionObject?.let { cl ->
|
|
||||||
if (cl.visibility != KVisibility.PUBLIC) return null
|
|
||||||
kotlin.companionObjectInstance?.let {
|
|
||||||
(it as? OptionsContainer)?.options
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patcher.fingerprint
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A ReVanced fingerprint.
|
|
||||||
* Can be a [MethodFingerprint].
|
|
||||||
*/
|
|
||||||
interface Fingerprint
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package app.revanced.patcher.fingerprint.method.annotation
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotations to scan a pattern [MethodFingerprint] with fuzzy algorithm.
|
|
||||||
* @param threshold if [threshold] or more of the opcodes do not match, skip.
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
annotation class FuzzyPatternScanMethod(
|
|
||||||
val threshold: Int = 1
|
|
||||||
)
|
|
||||||
@@ -1,513 +0,0 @@
|
|||||||
package app.revanced.patcher.fingerprint.method.impl
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.Fingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.patch.PatchException
|
|
||||||
import app.revanced.patcher.util.proxy.ClassProxy
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
private typealias StringMatch = MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult.StringMatch
|
|
||||||
private typealias StringsScanResult = MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult
|
|
||||||
private typealias MethodClassPair = Pair<Method, ClassDef>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A fingerprint to resolve methods.
|
|
||||||
*
|
|
||||||
* @param returnType The method's return type compared using [String.startsWith].
|
|
||||||
* @param accessFlags The method's exact access flags using values of [AccessFlags].
|
|
||||||
* @param parameters The parameters of the method. Partial matches allowed and follow the same rules as [returnType].
|
|
||||||
* @param opcodes An opcode pattern of the method's instructions. Wildcard or unknown opcodes can be specified by `null`.
|
|
||||||
* @param strings A list of the method's strings compared each using [String.contains].
|
|
||||||
* @param customFingerprint A custom condition for this fingerprint.
|
|
||||||
*/
|
|
||||||
abstract class MethodFingerprint(
|
|
||||||
internal val returnType: String? = null,
|
|
||||||
internal val accessFlags: Int? = null,
|
|
||||||
internal val parameters: Iterable<String>? = null,
|
|
||||||
internal val opcodes: Iterable<Opcode?>? = null,
|
|
||||||
internal val strings: Iterable<String>? = null,
|
|
||||||
internal val customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null
|
|
||||||
) : Fingerprint {
|
|
||||||
/**
|
|
||||||
* The result of the [MethodFingerprint].
|
|
||||||
*/
|
|
||||||
var result: MethodFingerprintResult? = null
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* A list of methods and the class they were found in.
|
|
||||||
*/
|
|
||||||
private val methods = mutableListOf<MethodClassPair>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup map for methods keyed to the methods access flags, return type and parameter.
|
|
||||||
*/
|
|
||||||
private val methodSignatureLookupMap = mutableMapOf<String, MutableList<MethodClassPair>>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup map for methods keyed to the strings contained in the method.
|
|
||||||
*/
|
|
||||||
private val methodStringsLookupMap = mutableMapOf<String, MutableList<MethodClassPair>>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends a string based on the parameter reference types of this method.
|
|
||||||
*/
|
|
||||||
private fun StringBuilder.appendParameters(parameters: Iterable<CharSequence>) {
|
|
||||||
// Maximum parameters to use in the signature key.
|
|
||||||
// Some apps have methods with an incredible number of parameters (over 100 parameters have been seen).
|
|
||||||
// To keep the signature map from becoming needlessly bloated,
|
|
||||||
// group together in the same map entry all methods with the same access/return and 5 or more parameters.
|
|
||||||
// The value of 5 was chosen based on local performance testing and is not set in stone.
|
|
||||||
val maxSignatureParameters = 5
|
|
||||||
// Must append a unique value before the parameters to distinguish this key includes the parameters.
|
|
||||||
// If this is not appended, then methods with no parameters
|
|
||||||
// will collide with different keys that specify access/return but omit the parameters.
|
|
||||||
append("p:")
|
|
||||||
parameters.forEachIndexed { index, parameter ->
|
|
||||||
if (index >= maxSignatureParameters) return
|
|
||||||
append(parameter.first())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes lookup maps for [MethodFingerprint] resolution
|
|
||||||
* using attributes of methods such as the method signature or strings.
|
|
||||||
*
|
|
||||||
* @param context The [BytecodeContext] containing the classes to initialize the lookup maps with.
|
|
||||||
*/
|
|
||||||
internal fun initializeFingerprintResolutionLookupMaps(context: BytecodeContext) {
|
|
||||||
fun MutableMap<String, MutableList<MethodClassPair>>.add(
|
|
||||||
key: String,
|
|
||||||
methodClassPair: MethodClassPair
|
|
||||||
) {
|
|
||||||
var methodClassPairs = this[key]
|
|
||||||
|
|
||||||
methodClassPairs ?: run {
|
|
||||||
methodClassPairs = LinkedList<MethodClassPair>().also { this[key] = it }
|
|
||||||
}
|
|
||||||
|
|
||||||
methodClassPairs!!.add(methodClassPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methods.isNotEmpty()) clearFingerprintResolutionLookupMaps()
|
|
||||||
|
|
||||||
context.classes.forEach { classDef ->
|
|
||||||
classDef.methods.forEach { method ->
|
|
||||||
val methodClassPair = method to classDef
|
|
||||||
|
|
||||||
// For fingerprints with no access or return type specified.
|
|
||||||
methods += methodClassPair
|
|
||||||
|
|
||||||
val accessFlagsReturnKey = method.accessFlags.toString() + method.returnType.first()
|
|
||||||
|
|
||||||
// Add <access><returnType> as the key.
|
|
||||||
methodSignatureLookupMap.add(accessFlagsReturnKey, methodClassPair)
|
|
||||||
|
|
||||||
// Add <access><returnType>[parameters] as the key.
|
|
||||||
methodSignatureLookupMap.add(
|
|
||||||
buildString {
|
|
||||||
append(accessFlagsReturnKey)
|
|
||||||
appendParameters(method.parameterTypes)
|
|
||||||
},
|
|
||||||
methodClassPair
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add strings contained in the method as the key.
|
|
||||||
method.implementation?.instructions?.forEach instructions@{ instruction ->
|
|
||||||
if (instruction.opcode != Opcode.CONST_STRING && instruction.opcode != Opcode.CONST_STRING_JUMBO)
|
|
||||||
return@instructions
|
|
||||||
|
|
||||||
val string = ((instruction as ReferenceInstruction).reference as StringReference).string
|
|
||||||
|
|
||||||
methodStringsLookupMap.add(string, methodClassPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the future, the class type could be added to the lookup map.
|
|
||||||
// This would require MethodFingerprint to be changed to include the class type.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the internal lookup maps created in [initializeFingerprintResolutionLookupMaps]
|
|
||||||
*/
|
|
||||||
internal fun clearFingerprintResolutionLookupMaps() {
|
|
||||||
methods.clear()
|
|
||||||
methodSignatureLookupMap.clear()
|
|
||||||
methodStringsLookupMap.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a list of [MethodFingerprint] using the lookup map built by [initializeFingerprintResolutionLookupMaps].
|
|
||||||
*
|
|
||||||
* [MethodFingerprint] resolution is fast, but if many are present they can consume a noticeable
|
|
||||||
* amount of time because they are resolved in sequence.
|
|
||||||
*
|
|
||||||
* For apps with many fingerprints, resolving performance can be improved by:
|
|
||||||
* - Slowest: Specify [opcodes] and nothing else.
|
|
||||||
* - Fast: Specify [accessFlags], [returnType].
|
|
||||||
* - Faster: Specify [accessFlags], [returnType] and [parameters].
|
|
||||||
* - Fastest: Specify [strings], with at least one string being an exact (non-partial) match.
|
|
||||||
*/
|
|
||||||
internal fun Iterable<MethodFingerprint>.resolveUsingLookupMap(context: BytecodeContext) {
|
|
||||||
if (methods.isEmpty()) throw PatchException("lookup map not initialized")
|
|
||||||
|
|
||||||
for (fingerprint in this) {
|
|
||||||
fingerprint.resolveUsingLookupMap(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a [MethodFingerprint] using the lookup map built by [initializeFingerprintResolutionLookupMaps].
|
|
||||||
*
|
|
||||||
* [MethodFingerprint] resolution is fast, but if many are present they can consume a noticeable
|
|
||||||
* amount of time because they are resolved in sequence.
|
|
||||||
*
|
|
||||||
* For apps with many fingerprints, resolving performance can be improved by:
|
|
||||||
* - Slowest: Specify [opcodes] and nothing else.
|
|
||||||
* - Fast: Specify [accessFlags], [returnType].
|
|
||||||
* - Faster: Specify [accessFlags], [returnType] and [parameters].
|
|
||||||
* - Fastest: Specify [strings], with at least one string being an exact (non-partial) match.
|
|
||||||
*/
|
|
||||||
internal fun MethodFingerprint.resolveUsingLookupMap(context: BytecodeContext): Boolean {
|
|
||||||
/**
|
|
||||||
* Lookup [MethodClassPair]s that match the methods strings present in a [MethodFingerprint].
|
|
||||||
*
|
|
||||||
* @return A list of [MethodClassPair]s that match the methods strings present in a [MethodFingerprint].
|
|
||||||
*/
|
|
||||||
fun MethodFingerprint.methodStringsLookup(): List<MethodClassPair>? {
|
|
||||||
strings?.forEach {
|
|
||||||
val methods = methodStringsLookupMap[it]
|
|
||||||
if (methods != null) return methods
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup [MethodClassPair]s that match the method signature present in a [MethodFingerprint].
|
|
||||||
*
|
|
||||||
* @return A list of [MethodClassPair]s that match the method signature present in a [MethodFingerprint].
|
|
||||||
*/
|
|
||||||
fun MethodFingerprint.methodSignatureLookup(): List<MethodClassPair> {
|
|
||||||
if (accessFlags == null) return methods
|
|
||||||
|
|
||||||
var returnTypeValue = returnType
|
|
||||||
if (returnTypeValue == null) {
|
|
||||||
if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
|
||||||
// Constructors always have void return type
|
|
||||||
returnTypeValue = "V"
|
|
||||||
} else {
|
|
||||||
return methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val key = buildString {
|
|
||||||
append(accessFlags)
|
|
||||||
append(returnTypeValue.first())
|
|
||||||
if (parameters != null) appendParameters(parameters)
|
|
||||||
}
|
|
||||||
return methodSignatureLookupMap[key] ?: return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a [MethodFingerprint] using a list of [MethodClassPair].
|
|
||||||
*
|
|
||||||
* @return True if the resolution was successful, false otherwise.
|
|
||||||
*/
|
|
||||||
fun MethodFingerprint.resolveUsingMethodClassPair(classMethods: Iterable<MethodClassPair>): Boolean {
|
|
||||||
classMethods.forEach { classAndMethod ->
|
|
||||||
if (resolve(context, classAndMethod.first, classAndMethod.second)) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val methodsWithSameStrings = methodStringsLookup()
|
|
||||||
if (methodsWithSameStrings != null) if (resolveUsingMethodClassPair(methodsWithSameStrings)) return true
|
|
||||||
|
|
||||||
// No strings declared or none matched (partial matches are allowed).
|
|
||||||
// Use signature matching.
|
|
||||||
return resolveUsingMethodClassPair(methodSignatureLookup())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a list of [MethodFingerprint] against a list of [ClassDef].
|
|
||||||
*
|
|
||||||
* @param classes The classes on which to resolve the [MethodFingerprint] in.
|
|
||||||
* @param context The [BytecodeContext] to host proxies.
|
|
||||||
* @return True if the resolution was successful, false otherwise.
|
|
||||||
*/
|
|
||||||
fun Iterable<MethodFingerprint>.resolve(context: BytecodeContext, classes: Iterable<ClassDef>) {
|
|
||||||
for (fingerprint in this) // For each fingerprint...
|
|
||||||
classes@ for (classDef in classes) // ...search through all classes for the MethodFingerprint
|
|
||||||
if (fingerprint.resolve(context, classDef))
|
|
||||||
break@classes // ...if the resolution succeeded, continue with the next MethodFingerprint.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a [MethodFingerprint] against a [ClassDef].
|
|
||||||
*
|
|
||||||
* @param forClass The class on which to resolve the [MethodFingerprint] in.
|
|
||||||
* @param context The [BytecodeContext] to host proxies.
|
|
||||||
* @return True if the resolution was successful, false otherwise.
|
|
||||||
*/
|
|
||||||
fun MethodFingerprint.resolve(context: BytecodeContext, forClass: ClassDef): Boolean {
|
|
||||||
for (method in forClass.methods)
|
|
||||||
if (this.resolve(context, method, forClass))
|
|
||||||
return true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a [MethodFingerprint] against a [Method].
|
|
||||||
*
|
|
||||||
* @param method The class on which to resolve the [MethodFingerprint] in.
|
|
||||||
* @param forClass The class on which to resolve the [MethodFingerprint].
|
|
||||||
* @param context The [BytecodeContext] to host proxies.
|
|
||||||
* @return True if the resolution was successful or if the fingerprint is already resolved, false otherwise.
|
|
||||||
*/
|
|
||||||
fun MethodFingerprint.resolve(context: BytecodeContext, method: Method, forClass: ClassDef): Boolean {
|
|
||||||
val methodFingerprint = this
|
|
||||||
|
|
||||||
if (methodFingerprint.result != null) return true
|
|
||||||
|
|
||||||
if (methodFingerprint.returnType != null && !method.returnType.startsWith(methodFingerprint.returnType))
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (methodFingerprint.accessFlags != null && methodFingerprint.accessFlags != method.accessFlags)
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
fun parametersEqual(
|
|
||||||
parameters1: Iterable<CharSequence>, parameters2: Iterable<CharSequence>
|
|
||||||
): Boolean {
|
|
||||||
if (parameters1.count() != parameters2.count()) return false
|
|
||||||
val iterator1 = parameters1.iterator()
|
|
||||||
parameters2.forEach {
|
|
||||||
if (!it.startsWith(iterator1.next())) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodFingerprint.parameters != null && !parametersEqual(
|
|
||||||
methodFingerprint.parameters, // TODO: parseParameters()
|
|
||||||
method.parameterTypes
|
|
||||||
)
|
|
||||||
) return false
|
|
||||||
|
|
||||||
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
|
|
||||||
if (methodFingerprint.customFingerprint != null && !methodFingerprint.customFingerprint!!(method, forClass))
|
|
||||||
return false
|
|
||||||
|
|
||||||
val stringsScanResult: StringsScanResult? =
|
|
||||||
if (methodFingerprint.strings != null) {
|
|
||||||
StringsScanResult(
|
|
||||||
buildList {
|
|
||||||
val implementation = method.implementation ?: return false
|
|
||||||
|
|
||||||
val stringsList = methodFingerprint.strings.toMutableList()
|
|
||||||
|
|
||||||
implementation.instructions.forEachIndexed { instructionIndex, instruction ->
|
|
||||||
if (
|
|
||||||
instruction.opcode != Opcode.CONST_STRING &&
|
|
||||||
instruction.opcode != Opcode.CONST_STRING_JUMBO
|
|
||||||
) return@forEachIndexed
|
|
||||||
|
|
||||||
val string = ((instruction as ReferenceInstruction).reference as StringReference).string
|
|
||||||
val index = stringsList.indexOfFirst(string::contains)
|
|
||||||
if (index == -1) return@forEachIndexed
|
|
||||||
|
|
||||||
add(
|
|
||||||
StringMatch(
|
|
||||||
string,
|
|
||||||
instructionIndex
|
|
||||||
)
|
|
||||||
)
|
|
||||||
stringsList.removeAt(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringsList.isNotEmpty()) return false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else null
|
|
||||||
|
|
||||||
val patternScanResult = if (methodFingerprint.opcodes != null) {
|
|
||||||
method.implementation?.instructions ?: return false
|
|
||||||
|
|
||||||
fun Method.patternScan(
|
|
||||||
fingerprint: MethodFingerprint
|
|
||||||
): MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult? {
|
|
||||||
val instructions = this.implementation!!.instructions
|
|
||||||
val fingerprintFuzzyPatternScanThreshold = fingerprint.fuzzyPatternScanMethod?.threshold ?: 0
|
|
||||||
|
|
||||||
val pattern = fingerprint.opcodes!!
|
|
||||||
val instructionLength = instructions.count()
|
|
||||||
val patternLength = pattern.count()
|
|
||||||
|
|
||||||
for (index in 0 until instructionLength) {
|
|
||||||
var patternIndex = 0
|
|
||||||
var threshold = fingerprintFuzzyPatternScanThreshold
|
|
||||||
|
|
||||||
while (index + patternIndex < instructionLength) {
|
|
||||||
val originalOpcode = instructions.elementAt(index + patternIndex).opcode
|
|
||||||
val patternOpcode = pattern.elementAt(patternIndex)
|
|
||||||
|
|
||||||
if (patternOpcode != null && patternOpcode.ordinal != originalOpcode.ordinal) {
|
|
||||||
// reaching maximum threshold (0) means,
|
|
||||||
// the pattern does not match to the current instructions
|
|
||||||
if (threshold-- == 0) break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (patternIndex < patternLength - 1) {
|
|
||||||
// if the entire pattern has not been scanned yet
|
|
||||||
// continue the scan
|
|
||||||
patternIndex++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// the pattern is valid, generate warnings if fuzzyPatternScanMethod is FuzzyPatternScanMethod
|
|
||||||
val result =
|
|
||||||
MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult(
|
|
||||||
index,
|
|
||||||
index + patternIndex
|
|
||||||
)
|
|
||||||
if (fingerprint.fuzzyPatternScanMethod !is FuzzyPatternScanMethod) return result
|
|
||||||
result.warnings = result.createWarnings(pattern, instructions)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
method.patternScan(methodFingerprint) ?: return false
|
|
||||||
} else null
|
|
||||||
|
|
||||||
methodFingerprint.result = MethodFingerprintResult(
|
|
||||||
method,
|
|
||||||
forClass,
|
|
||||||
MethodFingerprintResult.MethodFingerprintScanResult(
|
|
||||||
patternScanResult,
|
|
||||||
stringsScanResult
|
|
||||||
),
|
|
||||||
context
|
|
||||||
)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult.createWarnings(
|
|
||||||
pattern: Iterable<Opcode?>, instructions: Iterable<Instruction>
|
|
||||||
) = buildList {
|
|
||||||
for ((patternIndex, instructionIndex) in (this@createWarnings.startIndex until this@createWarnings.endIndex).withIndex()) {
|
|
||||||
val originalOpcode = instructions.elementAt(instructionIndex).opcode
|
|
||||||
val patternOpcode = pattern.elementAt(patternIndex)
|
|
||||||
|
|
||||||
if (patternOpcode == null || patternOpcode.ordinal == originalOpcode.ordinal) continue
|
|
||||||
|
|
||||||
this.add(
|
|
||||||
MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult.Warning(
|
|
||||||
originalOpcode,
|
|
||||||
patternOpcode,
|
|
||||||
instructionIndex,
|
|
||||||
patternIndex
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the result of a [MethodFingerprintResult].
|
|
||||||
*
|
|
||||||
* @param method The matching method.
|
|
||||||
* @param classDef The [ClassDef] that contains the matching [method].
|
|
||||||
* @param scanResult The result of scanning for the [MethodFingerprint].
|
|
||||||
* @param context The [BytecodeContext] this [MethodFingerprintResult] is attached to, to create proxies.
|
|
||||||
*/
|
|
||||||
data class MethodFingerprintResult(
|
|
||||||
val method: Method,
|
|
||||||
val classDef: ClassDef,
|
|
||||||
val scanResult: MethodFingerprintScanResult,
|
|
||||||
internal val context: BytecodeContext
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* Returns a mutable clone of [classDef]
|
|
||||||
*
|
|
||||||
* Please note, this method allocates a [ClassProxy].
|
|
||||||
* Use [classDef] where possible.
|
|
||||||
*/
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
val mutableClass by lazy { context.proxy(classDef).mutableClass }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a mutable clone of [method]
|
|
||||||
*
|
|
||||||
* Please note, this method allocates a [ClassProxy].
|
|
||||||
* Use [method] where possible.
|
|
||||||
*/
|
|
||||||
val mutableMethod by lazy {
|
|
||||||
mutableClass.methods.first {
|
|
||||||
MethodUtil.methodSignaturesMatch(it, this.method)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The result of scanning on the [MethodFingerprint].
|
|
||||||
* @param patternScanResult The result of the pattern scan.
|
|
||||||
* @param stringsScanResult The result of the string scan.
|
|
||||||
*/
|
|
||||||
data class MethodFingerprintScanResult(
|
|
||||||
val patternScanResult: PatternScanResult?,
|
|
||||||
val stringsScanResult: StringsScanResult?
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* The result of scanning strings on the [MethodFingerprint].
|
|
||||||
* @param matches The list of strings that were matched.
|
|
||||||
*/
|
|
||||||
data class StringsScanResult(val matches: List<StringMatch>) {
|
|
||||||
/**
|
|
||||||
* Represents a match for a string at an index.
|
|
||||||
* @param string The string that was matched.
|
|
||||||
* @param index The index of the string.
|
|
||||||
*/
|
|
||||||
data class StringMatch(val string: String, val index: Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The result of a pattern scan.
|
|
||||||
* @param startIndex The start index of the instructions where to which this pattern matches.
|
|
||||||
* @param endIndex The end index of the instructions where to which this pattern matches.
|
|
||||||
* @param warnings A list of warnings considering this [PatternScanResult].
|
|
||||||
*/
|
|
||||||
data class PatternScanResult(
|
|
||||||
val startIndex: Int,
|
|
||||||
val endIndex: Int,
|
|
||||||
var warnings: List<Warning>? = null
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* Represents warnings of the pattern scan.
|
|
||||||
* @param correctOpcode The opcode the instruction list has.
|
|
||||||
* @param wrongOpcode The opcode the pattern list of the signature currently has.
|
|
||||||
* @param instructionIndex The index of the opcode relative to the instruction list.
|
|
||||||
* @param patternIndex The index of the opcode relative to the pattern list from the signature.
|
|
||||||
*/
|
|
||||||
data class Warning(
|
|
||||||
val correctOpcode: Opcode,
|
|
||||||
val wrongOpcode: Opcode,
|
|
||||||
val instructionIndex: Int,
|
|
||||||
val patternIndex: Int,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patcher.logging
|
|
||||||
|
|
||||||
@Deprecated("This will be removed in a future release")
|
|
||||||
interface Logger {
|
|
||||||
fun error(msg: String) {}
|
|
||||||
fun warn(msg: String) {}
|
|
||||||
fun info(msg: String) {}
|
|
||||||
fun trace(msg: String) {}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package app.revanced.patcher.logging.impl
|
|
||||||
|
|
||||||
import app.revanced.patcher.logging.Logger
|
|
||||||
|
|
||||||
@Deprecated("This will be removed in a future release")
|
|
||||||
object NopLogger : Logger
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package app.revanced.patcher.patch
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A container for patch options.
|
|
||||||
*/
|
|
||||||
abstract class OptionsContainer {
|
|
||||||
/**
|
|
||||||
* A list of [PatchOption]s.
|
|
||||||
* @see PatchOptions
|
|
||||||
*/
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
val options = PatchOptions()
|
|
||||||
|
|
||||||
protected fun <T> option(opt: PatchOption<T>): PatchOption<T> {
|
|
||||||
options.register(opt)
|
|
||||||
return opt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +1,7 @@
|
|||||||
package app.revanced.patcher.patch
|
package app.revanced.patcher.patch
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.cache.Cache
|
||||||
import app.revanced.patcher.data.Context
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import java.io.Closeable
|
|
||||||
|
|
||||||
typealias PatchClass = Class<out Patch<Context<*>>>
|
abstract class Patch(val patchName: String) {
|
||||||
|
abstract fun execute(cache: Cache): PatchResult
|
||||||
/**
|
|
||||||
* A ReVanced patch.
|
|
||||||
*
|
|
||||||
* If it implements [Closeable], it will be closed after all patches have been executed.
|
|
||||||
* Closing will be done in reverse execution order.
|
|
||||||
*/
|
|
||||||
sealed interface Patch<out T : Context<*>> {
|
|
||||||
/**
|
|
||||||
* The main function of the [Patch] which the patcher will call.
|
|
||||||
*
|
|
||||||
* @param context The [Context] the patch will work on.
|
|
||||||
* @return The result of executing the patch.
|
|
||||||
*/
|
|
||||||
fun execute(context: @UnsafeVariance T)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resource patch for the Patcher.
|
|
||||||
*/
|
|
||||||
interface ResourcePatch : Patch<ResourceContext>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bytecode patch for the Patcher.
|
|
||||||
*
|
|
||||||
* @param fingerprints A list of [MethodFingerprint] this patch relies on.
|
|
||||||
*/
|
|
||||||
abstract class BytecodePatch(
|
|
||||||
internal val fingerprints: Iterable<MethodFingerprint>? = null
|
|
||||||
) : Patch<BytecodeContext>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package app.revanced.patcher.patch
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception thrown when patching.
|
|
||||||
*
|
|
||||||
* @param errorMessage The exception message.
|
|
||||||
* @param cause The corresponding [Throwable].
|
|
||||||
*/
|
|
||||||
class PatchException(errorMessage: String?, cause: Throwable?) : Exception(errorMessage, cause) {
|
|
||||||
constructor(errorMessage: String) : this(errorMessage, null)
|
|
||||||
constructor(cause: Throwable) : this(cause.message, cause)
|
|
||||||
}
|
|
||||||
@@ -1,232 +0,0 @@
|
|||||||
@file:Suppress("CanBeParameter", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST")
|
|
||||||
|
|
||||||
package app.revanced.patcher.patch
|
|
||||||
|
|
||||||
import java.nio.file.Path
|
|
||||||
import kotlin.io.path.pathString
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
class NoSuchOptionException(val option: String) : Exception("No such option: $option")
|
|
||||||
class IllegalValueException(val value: Any?) : Exception("Illegal value: $value")
|
|
||||||
class InvalidTypeException(val got: String, val expected: String) :
|
|
||||||
Exception("Invalid option value type: $got, expected $expected")
|
|
||||||
|
|
||||||
object RequirementNotMetException : Exception("null was passed into an option that requires a value")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A registry for an array of [PatchOption]s.
|
|
||||||
* @param options An array of [PatchOption]s.
|
|
||||||
*/
|
|
||||||
class PatchOptions(vararg options: PatchOption<*>) : Iterable<PatchOption<*>> {
|
|
||||||
private val register = mutableMapOf<String, PatchOption<*>>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
options.forEach { register(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun register(option: PatchOption<*>) {
|
|
||||||
if (register.containsKey(option.key)) {
|
|
||||||
throw IllegalStateException("Multiple options found with the same key")
|
|
||||||
}
|
|
||||||
register[option.key] = option
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a [PatchOption] by its key.
|
|
||||||
* @param key The key of the [PatchOption].
|
|
||||||
*/
|
|
||||||
@JvmName("getUntyped")
|
|
||||||
operator fun get(key: String) = register[key] ?: throw NoSuchOptionException(key)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a [PatchOption] by its key.
|
|
||||||
* @param key The key of the [PatchOption].
|
|
||||||
*/
|
|
||||||
inline operator fun <reified T> get(key: String): PatchOption<T> {
|
|
||||||
val opt = get(key)
|
|
||||||
if (opt.value !is T) throw InvalidTypeException(
|
|
||||||
opt.value?.let { it::class.java.canonicalName } ?: "null",
|
|
||||||
T::class.java.canonicalName
|
|
||||||
)
|
|
||||||
return opt as PatchOption<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the value of a [PatchOption].
|
|
||||||
* @param key The key of the [PatchOption].
|
|
||||||
* @param value The value you want it to be.
|
|
||||||
* Please note that using the wrong value type results in a runtime error.
|
|
||||||
*/
|
|
||||||
inline operator fun <reified T> set(key: String, value: T) {
|
|
||||||
val opt = get<T>(key)
|
|
||||||
if (opt.value !is T) throw InvalidTypeException(
|
|
||||||
T::class.java.canonicalName,
|
|
||||||
opt.value?.let { it::class.java.canonicalName } ?: "null"
|
|
||||||
)
|
|
||||||
opt.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the value of a [PatchOption] to `null`.
|
|
||||||
* @param key The key of the [PatchOption].
|
|
||||||
*/
|
|
||||||
fun nullify(key: String) {
|
|
||||||
get(key).value = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator() = register.values.iterator()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [Patch] option.
|
|
||||||
* @param key Unique identifier of the option. Example: _`settings`_
|
|
||||||
* @param default The default value of the option.
|
|
||||||
* @param title A human-readable title of the option. Example: _Patch Settings_
|
|
||||||
* @param description A human-readable description of the option. Example: _Settings for the patches._
|
|
||||||
* @param required Whether the option is required.
|
|
||||||
*/
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
sealed class PatchOption<T>(
|
|
||||||
val key: String,
|
|
||||||
default: T?,
|
|
||||||
val title: String,
|
|
||||||
val description: String,
|
|
||||||
val required: Boolean,
|
|
||||||
val validator: (T?) -> Boolean
|
|
||||||
) {
|
|
||||||
var value: T? = default
|
|
||||||
get() {
|
|
||||||
if (field == null && required) {
|
|
||||||
throw RequirementNotMetException
|
|
||||||
}
|
|
||||||
return field
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
if (value == null && required) {
|
|
||||||
throw RequirementNotMetException
|
|
||||||
}
|
|
||||||
if (!validator(value)) {
|
|
||||||
throw IllegalValueException(value)
|
|
||||||
}
|
|
||||||
field = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the option.
|
|
||||||
* Please note that using the wrong value type results in a runtime error.
|
|
||||||
*/
|
|
||||||
@JvmName("getValueTyped")
|
|
||||||
inline operator fun <reified V> getValue(thisRef: Nothing?, property: KProperty<*>): V? {
|
|
||||||
if (value !is V?) throw InvalidTypeException(
|
|
||||||
V::class.java.canonicalName,
|
|
||||||
value?.let { it::class.java.canonicalName } ?: "null"
|
|
||||||
)
|
|
||||||
return value as? V?
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the option.
|
|
||||||
* Please note that using the wrong value type results in a runtime error.
|
|
||||||
*/
|
|
||||||
@JvmName("setValueTyped")
|
|
||||||
inline operator fun <reified V> setValue(thisRef: Nothing?, property: KProperty<*>, new: V) {
|
|
||||||
if (value !is V) throw InvalidTypeException(
|
|
||||||
V::class.java.canonicalName,
|
|
||||||
value?.let { it::class.java.canonicalName } ?: "null"
|
|
||||||
)
|
|
||||||
value = new as T
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, new: T?) {
|
|
||||||
value = new
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [PatchOption] representing a [String].
|
|
||||||
* @see PatchOption
|
|
||||||
*/
|
|
||||||
class StringOption(
|
|
||||||
key: String,
|
|
||||||
default: String?,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
required: Boolean = false,
|
|
||||||
validator: (String?) -> Boolean = { true }
|
|
||||||
) : PatchOption<String>(
|
|
||||||
key, default, title, description, required, validator
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [PatchOption] representing a [Boolean].
|
|
||||||
* @see PatchOption
|
|
||||||
*/
|
|
||||||
class BooleanOption(
|
|
||||||
key: String,
|
|
||||||
default: Boolean?,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
required: Boolean = false,
|
|
||||||
validator: (Boolean?) -> Boolean = { true }
|
|
||||||
) : PatchOption<Boolean>(
|
|
||||||
key, default, title, description, required, validator
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [PatchOption] with a list of allowed options.
|
|
||||||
* @param options A list of allowed options for the [ListOption].
|
|
||||||
* @see PatchOption
|
|
||||||
*/
|
|
||||||
sealed class ListOption<E>(
|
|
||||||
key: String,
|
|
||||||
default: E?,
|
|
||||||
val options: Iterable<E>,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
required: Boolean = false,
|
|
||||||
validator: (E?) -> Boolean = { true }
|
|
||||||
) : PatchOption<E>(
|
|
||||||
key, default, title, description, required, {
|
|
||||||
(it?.let { it in options } ?: true) && validator(it)
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
init {
|
|
||||||
if (default != null && default !in options) {
|
|
||||||
throw IllegalStateException("Default option must be an allowed option")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [ListOption] of type [String].
|
|
||||||
* @see ListOption
|
|
||||||
*/
|
|
||||||
class StringListOption(
|
|
||||||
key: String,
|
|
||||||
default: String?,
|
|
||||||
options: Iterable<String>,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
required: Boolean = false,
|
|
||||||
validator: (String?) -> Boolean = { true }
|
|
||||||
) : ListOption<String>(
|
|
||||||
key, default, options, title, description, required, validator
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [ListOption] of type [Int].
|
|
||||||
* @see ListOption
|
|
||||||
*/
|
|
||||||
class IntListOption(
|
|
||||||
key: String,
|
|
||||||
default: Int?,
|
|
||||||
options: Iterable<Int>,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
required: Boolean = false,
|
|
||||||
validator: (Int?) -> Boolean = { true }
|
|
||||||
) : ListOption<Int>(
|
|
||||||
key, default, options, title, description, required, validator
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,33 @@
|
|||||||
package app.revanced.patcher.patch
|
package app.revanced.patcher.patch
|
||||||
|
|
||||||
/**
|
interface PatchResult {
|
||||||
* A result of executing a [Patch].
|
fun error(): PatchResultError? {
|
||||||
*
|
if (this is PatchResultError) {
|
||||||
* @param patchName The name of the [Patch].
|
return this
|
||||||
* @param exception The [PatchException] thrown, if any.
|
}
|
||||||
*/
|
return null
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
}
|
||||||
class PatchResult internal constructor(val patchName: String, val exception: PatchException? = null)
|
|
||||||
|
fun success(): PatchResultSuccess? {
|
||||||
|
if (this is PatchResultSuccess) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isError(): Boolean {
|
||||||
|
return this is PatchResultError
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSuccess(): Boolean {
|
||||||
|
return this is PatchResultSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PatchResultError(private val errorMessage: String) : PatchResult {
|
||||||
|
fun errorMessage(): String {
|
||||||
|
return errorMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PatchResultSuccess : PatchResult
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package app.revanced.patcher.patch.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.Context
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation to mark a class as a patch.
|
|
||||||
* @param include If false, the patch should be treated as optional by default.
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
annotation class Patch(val include: Boolean = true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation for dependencies of [Patch]es.
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
annotation class DependsOn(
|
|
||||||
val dependencies: Array<KClass<out Patch<Context<*>>>> = []
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: Remove this annotation, once integrations are coupled with patches.
|
|
||||||
/**
|
|
||||||
* Annotation to mark [Patch]es which depend on integrations.
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
annotation class RequiresIntegrations
|
|
||||||
159
src/main/kotlin/app/revanced/patcher/resolver/MethodResolver.kt
Normal file
159
src/main/kotlin/app/revanced/patcher/resolver/MethodResolver.kt
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package app.revanced.patcher.resolver
|
||||||
|
|
||||||
|
import mu.KotlinLogging
|
||||||
|
import app.revanced.patcher.cache.MethodMap
|
||||||
|
import app.revanced.patcher.cache.PatchData
|
||||||
|
import app.revanced.patcher.cache.PatternScanData
|
||||||
|
import app.revanced.patcher.signature.Signature
|
||||||
|
import app.revanced.patcher.util.ExtraTypes
|
||||||
|
import org.objectweb.asm.Type
|
||||||
|
import org.objectweb.asm.tree.ClassNode
|
||||||
|
import org.objectweb.asm.tree.InsnList
|
||||||
|
import org.objectweb.asm.tree.MethodNode
|
||||||
|
|
||||||
|
private val logger = KotlinLogging.logger("MethodResolver")
|
||||||
|
|
||||||
|
internal class MethodResolver(private val classList: List<ClassNode>, private val signatures: Array<Signature>) {
|
||||||
|
fun resolve(): MethodMap {
|
||||||
|
val methodMap = MethodMap()
|
||||||
|
|
||||||
|
for ((classNode, methods) in classList) {
|
||||||
|
for (method in methods) {
|
||||||
|
for (signature in signatures) {
|
||||||
|
if (methodMap.containsKey(signature.name)) { // method already found for this sig
|
||||||
|
logger.debug { "Sig ${signature.name} already found, skipping." }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.debug { "Resolving sig ${signature.name}: ${classNode.name} / ${method.name}" }
|
||||||
|
val (r, sr) = cmp(method, signature)
|
||||||
|
if (!r || sr == null) {
|
||||||
|
logger.debug { "Compare result for sig ${signature.name} has failed!" }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.debug { "Method for sig ${signature.name} found!" }
|
||||||
|
methodMap[signature.name] = PatchData(
|
||||||
|
classNode,
|
||||||
|
method,
|
||||||
|
PatternScanData(
|
||||||
|
// sadly we cannot create contracts for a data class, so we must assert
|
||||||
|
sr.startIndex!!,
|
||||||
|
sr.endIndex!!
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (signature in signatures) {
|
||||||
|
if (methodMap.containsKey(signature.name)) continue
|
||||||
|
logger.error { "Could not find method for sig ${signature.name}!" }
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// These functions do not require the constructor values, so they can be static.
|
||||||
|
companion object {
|
||||||
|
fun resolveMethod(classNode: ClassNode, signature: Signature): PatchData? {
|
||||||
|
for (method in classNode.methods) {
|
||||||
|
val (r, sr) = cmp(method, signature)
|
||||||
|
if (!r || sr == null) continue
|
||||||
|
return PatchData(
|
||||||
|
classNode,
|
||||||
|
method,
|
||||||
|
PatternScanData(0, 0) // opcode list is always ignored.
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cmp(method: MethodNode, signature: Signature): Pair<Boolean, ScanResult?> {
|
||||||
|
signature.returns?.let { _ ->
|
||||||
|
val methodReturns = Type.getReturnType(method.desc).convertObject()
|
||||||
|
if (signature.returns != methodReturns) {
|
||||||
|
logger.debug {
|
||||||
|
"""
|
||||||
|
Comparing sig ${signature.name}: invalid return type:
|
||||||
|
expected ${signature.returns},
|
||||||
|
got $methodReturns
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
return@cmp false to null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signature.accessors?.let { _ ->
|
||||||
|
if (signature.accessors != method.access) {
|
||||||
|
logger.debug {
|
||||||
|
"""
|
||||||
|
Comparing sig ${signature.name}: invalid accessors:
|
||||||
|
expected ${signature.accessors},
|
||||||
|
got ${method.access}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
return@cmp false to null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signature.parameters?.let { _ ->
|
||||||
|
val parameters = Type.getArgumentTypes(method.desc).convertObjects()
|
||||||
|
if (!signature.parameters.contentEquals(parameters)) {
|
||||||
|
logger.debug {
|
||||||
|
"""
|
||||||
|
Comparing sig ${signature.name}: invalid parameter types:
|
||||||
|
expected ${signature.parameters.joinToString()}},
|
||||||
|
got ${parameters.joinToString()}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
return@cmp false to null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signature.opcodes?.let { _ ->
|
||||||
|
val result = method.instructions.scanFor(signature.opcodes)
|
||||||
|
if (!result.found) {
|
||||||
|
logger.debug { "Comparing sig ${signature.name}: invalid opcode pattern" }
|
||||||
|
return@cmp false to null
|
||||||
|
}
|
||||||
|
return@cmp true to result
|
||||||
|
}
|
||||||
|
|
||||||
|
return true to ScanResult(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private operator fun ClassNode.component1(): ClassNode {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private operator fun ClassNode.component2(): List<MethodNode> {
|
||||||
|
return this.methods
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun InsnList.scanFor(pattern: IntArray): ScanResult {
|
||||||
|
for (i in 0 until this.size()) {
|
||||||
|
var occurrence = 0
|
||||||
|
while (i + occurrence < this.size()) {
|
||||||
|
if (this[i + occurrence].opcode != pattern[occurrence]) break
|
||||||
|
if (++occurrence >= pattern.size) {
|
||||||
|
val current = i + occurrence
|
||||||
|
return ScanResult(true, current - pattern.size, current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ScanResult(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Type.convertObject(): Type {
|
||||||
|
return when (this.sort) {
|
||||||
|
Type.OBJECT -> ExtraTypes.Any
|
||||||
|
Type.ARRAY -> ExtraTypes.ArrayAny
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Array<Type>.convertObjects(): Array<Type> {
|
||||||
|
return this.map { it.convertObject() }.toTypedArray()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package app.revanced.patcher.resolver
|
||||||
|
|
||||||
|
internal data class ScanResult(
|
||||||
|
val found: Boolean,
|
||||||
|
val startIndex: Int? = 0,
|
||||||
|
val endIndex: Int? = 0
|
||||||
|
)
|
||||||
27
src/main/kotlin/app/revanced/patcher/signature/Signature.kt
Normal file
27
src/main/kotlin/app/revanced/patcher/signature/Signature.kt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package app.revanced.patcher.signature
|
||||||
|
|
||||||
|
import org.objectweb.asm.Type
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ASM signature list for the Patcher.
|
||||||
|
*
|
||||||
|
* @param name The name of the method.
|
||||||
|
* Do not use the actual method name, instead try to guess what the method name originally was.
|
||||||
|
* If you are unable to guess a method name, doing something like "patch-name-1" is fine too.
|
||||||
|
* For example: "override-codec-1".
|
||||||
|
* This method name will be mapped to the method matching the signature.
|
||||||
|
* Even though this is technically not needed for the `findParentMethod` method,
|
||||||
|
* it is still recommended giving the method a name, so it can be identified easily.
|
||||||
|
* @param returns The return type/signature of the method.
|
||||||
|
* @param accessors The accessors of the method.
|
||||||
|
* @param parameters The parameter types of the method.
|
||||||
|
* @param opcodes The opcode pattern of the method, used to find the method by pattern scanning.
|
||||||
|
*/
|
||||||
|
@Suppress("ArrayInDataClass")
|
||||||
|
data class Signature(
|
||||||
|
val name: String,
|
||||||
|
val returns: Type?,
|
||||||
|
val accessors: Int?,
|
||||||
|
val parameters: Array<Type>?,
|
||||||
|
val opcodes: IntArray?
|
||||||
|
)
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
package app.revanced.patcher.util
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.util.ClassMerger.Utils.asMutableClass
|
|
||||||
import app.revanced.patcher.util.ClassMerger.Utils.filterAny
|
|
||||||
import app.revanced.patcher.util.ClassMerger.Utils.filterNotAny
|
|
||||||
import app.revanced.patcher.util.ClassMerger.Utils.isPublic
|
|
||||||
import app.revanced.patcher.util.ClassMerger.Utils.toPublic
|
|
||||||
import app.revanced.patcher.util.ClassMerger.Utils.traverseClassHierarchy
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass.Companion.toMutable
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
|
||||||
import java.util.logging.Logger
|
|
||||||
import kotlin.reflect.KFunction2
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Experimental class to merge a [ClassDef] with another.
|
|
||||||
* Note: This will not consider method implementations or if the class is missing a superclass or interfaces.
|
|
||||||
*/
|
|
||||||
internal object ClassMerger {
|
|
||||||
private val logger = Logger.getLogger(ClassMerger::class.java.name)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merge a class with [otherClass].
|
|
||||||
*
|
|
||||||
* @param otherClass The class to merge with
|
|
||||||
* @param context The context to traverse the class hierarchy in.
|
|
||||||
* @return The merged class or the original class if no merge was needed.
|
|
||||||
*/
|
|
||||||
fun ClassDef.merge(otherClass: ClassDef, context: BytecodeContext) = this
|
|
||||||
//.fixFieldAccess(otherClass)
|
|
||||||
//.fixMethodAccess(otherClass)
|
|
||||||
.addMissingFields(otherClass)
|
|
||||||
.addMissingMethods(otherClass)
|
|
||||||
.publicize(otherClass, context)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add methods which are missing but existing in [fromClass].
|
|
||||||
*
|
|
||||||
* @param fromClass The class to add missing methods from.
|
|
||||||
*/
|
|
||||||
private fun ClassDef.addMissingMethods(fromClass: ClassDef): ClassDef {
|
|
||||||
val missingMethods = fromClass.methods.let { fromMethods ->
|
|
||||||
methods.filterNot { method ->
|
|
||||||
fromMethods.any { fromMethod ->
|
|
||||||
MethodUtil.methodSignaturesMatch(fromMethod, method)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (missingMethods.isEmpty()) return this
|
|
||||||
|
|
||||||
logger.fine("Found ${missingMethods.size} missing methods")
|
|
||||||
|
|
||||||
return asMutableClass().apply {
|
|
||||||
methods.addAll(missingMethods.map { it.toMutable() })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add fields which are missing but existing in [fromClass].
|
|
||||||
*
|
|
||||||
* @param fromClass The class to add missing fields from.
|
|
||||||
*/
|
|
||||||
private fun ClassDef.addMissingFields(fromClass: ClassDef): ClassDef {
|
|
||||||
val missingFields = fields.filterNotAny(fromClass.fields) { field, fromField ->
|
|
||||||
fromField.name == field.name
|
|
||||||
}
|
|
||||||
|
|
||||||
if (missingFields.isEmpty()) return this
|
|
||||||
|
|
||||||
logger.fine("Found ${missingFields.size} missing fields")
|
|
||||||
|
|
||||||
return asMutableClass().apply {
|
|
||||||
fields.addAll(missingFields.map { it.toMutable() })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a class and its super class public recursively.
|
|
||||||
* @param reference The class to check the [AccessFlags] of.
|
|
||||||
* @param context The context to traverse the class hierarchy in.
|
|
||||||
*/
|
|
||||||
private fun ClassDef.publicize(reference: ClassDef, context: BytecodeContext) =
|
|
||||||
if (reference.accessFlags.isPublic() && !accessFlags.isPublic())
|
|
||||||
this.asMutableClass().apply {
|
|
||||||
context.traverseClassHierarchy(this) {
|
|
||||||
if (accessFlags.isPublic()) return@traverseClassHierarchy
|
|
||||||
|
|
||||||
logger.fine("Publicizing ${this.type}")
|
|
||||||
|
|
||||||
accessFlags = accessFlags.toPublic()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publicize fields if they are public in [reference].
|
|
||||||
*
|
|
||||||
* @param reference The class to check the [AccessFlags] of the fields in.
|
|
||||||
*/
|
|
||||||
private fun ClassDef.fixFieldAccess(reference: ClassDef): ClassDef {
|
|
||||||
val brokenFields = fields.filterAny(reference.fields) { field, referenceField ->
|
|
||||||
if (field.name != referenceField.name) return@filterAny false
|
|
||||||
|
|
||||||
referenceField.accessFlags.isPublic() && !field.accessFlags.isPublic()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brokenFields.isEmpty()) return this
|
|
||||||
|
|
||||||
logger.fine("Found ${brokenFields.size} broken fields")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a field public.
|
|
||||||
*/
|
|
||||||
fun MutableField.publicize() {
|
|
||||||
accessFlags = accessFlags.toPublic()
|
|
||||||
}
|
|
||||||
|
|
||||||
return asMutableClass().apply {
|
|
||||||
fields.filter { brokenFields.contains(it) }.forEach(MutableField::publicize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publicize methods if they are public in [reference].
|
|
||||||
*
|
|
||||||
* @param reference The class to check the [AccessFlags] of the methods in.
|
|
||||||
*/
|
|
||||||
private fun ClassDef.fixMethodAccess(reference: ClassDef): ClassDef {
|
|
||||||
val brokenMethods = methods.filterAny(reference.methods) { method, referenceMethod ->
|
|
||||||
if (!MethodUtil.methodSignaturesMatch(method, referenceMethod)) return@filterAny false
|
|
||||||
|
|
||||||
referenceMethod.accessFlags.isPublic() && !method.accessFlags.isPublic()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brokenMethods.isEmpty()) return this
|
|
||||||
|
|
||||||
logger.fine("Found ${brokenMethods.size} methods")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a method public.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.publicize() {
|
|
||||||
accessFlags = accessFlags.toPublic()
|
|
||||||
}
|
|
||||||
|
|
||||||
return asMutableClass().apply {
|
|
||||||
methods.filter { brokenMethods.contains(it) }.forEach(MutableMethod::publicize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private object Utils {
|
|
||||||
/**
|
|
||||||
* traverse the class hierarchy starting from the given root class
|
|
||||||
*
|
|
||||||
* @param targetClass the class to start traversing the class hierarchy from
|
|
||||||
* @param callback function that is called for every class in the hierarchy
|
|
||||||
*/
|
|
||||||
fun BytecodeContext.traverseClassHierarchy(targetClass: MutableClass, callback: MutableClass.() -> Unit) {
|
|
||||||
callback(targetClass)
|
|
||||||
this.findClass(targetClass.superclass ?: return)?.mutableClass?.let {
|
|
||||||
traverseClassHierarchy(it, callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ClassDef.asMutableClass() = if (this is MutableClass) this else this.toMutable()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the [AccessFlags.PUBLIC] flag is set.
|
|
||||||
*
|
|
||||||
* @return True, if the flag is set.
|
|
||||||
*/
|
|
||||||
fun Int.isPublic() = AccessFlags.PUBLIC.isSet(this)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make [AccessFlags] public.
|
|
||||||
*
|
|
||||||
* @return The new [AccessFlags].
|
|
||||||
*/
|
|
||||||
fun Int.toPublic() = this.or(AccessFlags.PUBLIC).and(AccessFlags.PRIVATE.value.inv())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter [this] on [needles] matching the given [predicate].
|
|
||||||
*
|
|
||||||
* @param needles The needles to filter [this] with.
|
|
||||||
* @param predicate The filter.
|
|
||||||
* @return The [this] filtered on [needles] matching the given [predicate].
|
|
||||||
*/
|
|
||||||
fun <HayType, NeedleType> Iterable<HayType>.filterAny(
|
|
||||||
needles: Iterable<NeedleType>, predicate: (HayType, NeedleType) -> Boolean
|
|
||||||
) = Iterable<HayType>::filter.any(this, needles, predicate)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter [this] on [needles] not matching the given [predicate].
|
|
||||||
*
|
|
||||||
* @param needles The needles to filter [this] with.
|
|
||||||
* @param predicate The filter.
|
|
||||||
* @return The [this] filtered on [needles] not matching the given [predicate].
|
|
||||||
*/
|
|
||||||
fun <HayType, NeedleType> Iterable<HayType>.filterNotAny(
|
|
||||||
needles: Iterable<NeedleType>, predicate: (HayType, NeedleType) -> Boolean
|
|
||||||
) = Iterable<HayType>::filterNot.any(this, needles, predicate)
|
|
||||||
|
|
||||||
fun <HayType, NeedleType> KFunction2<Iterable<HayType>, (HayType) -> Boolean, List<HayType>>.any(
|
|
||||||
haystack: Iterable<HayType>,
|
|
||||||
needles: Iterable<NeedleType>,
|
|
||||||
predicate: (HayType, NeedleType) -> Boolean
|
|
||||||
) = this(haystack) { hay ->
|
|
||||||
needles.any { needle ->
|
|
||||||
predicate(hay, needle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package app.revanced.patcher.util
|
|
||||||
|
|
||||||
import org.w3c.dom.Document
|
|
||||||
import java.io.Closeable
|
|
||||||
import java.io.File
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory
|
|
||||||
import javax.xml.transform.TransformerFactory
|
|
||||||
import javax.xml.transform.dom.DOMSource
|
|
||||||
import javax.xml.transform.stream.StreamResult
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for a file that can be edited as a dom document.
|
|
||||||
*
|
|
||||||
* This constructor does not check for locks to the file when writing.
|
|
||||||
* Use the secondary constructor.
|
|
||||||
*
|
|
||||||
* @param inputStream the input stream to read the xml file from.
|
|
||||||
* @param outputStream the output stream to write the xml file to. If null, the file will be read only.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class DomFileEditor internal constructor(
|
|
||||||
private val inputStream: InputStream,
|
|
||||||
private val outputStream: Lazy<OutputStream>? = null,
|
|
||||||
) : Closeable {
|
|
||||||
// path to the xml file to unlock the resource when closing the editor
|
|
||||||
private var filePath: String? = null
|
|
||||||
private var closed: Boolean = false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The document of the xml file
|
|
||||||
*/
|
|
||||||
val file: Document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream)
|
|
||||||
.also(Document::normalize)
|
|
||||||
|
|
||||||
|
|
||||||
// lazily open an output stream
|
|
||||||
// this is required because when constructing a DomFileEditor the output stream is created along with the input stream, which is not allowed
|
|
||||||
// the workaround is to lazily create the output stream. This way it would be used after the input stream is closed, which happens in the constructor
|
|
||||||
constructor(file: File) : this(file.inputStream(), lazy { file.outputStream() }) {
|
|
||||||
// increase the lock
|
|
||||||
locks.merge(file.path, 1, Integer::sum)
|
|
||||||
filePath = file.path
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the editor. Write backs and decreases the lock count.
|
|
||||||
*
|
|
||||||
* Will not write back to the file if the file is still locked.
|
|
||||||
*/
|
|
||||||
override fun close() {
|
|
||||||
if (closed) return
|
|
||||||
|
|
||||||
inputStream.close()
|
|
||||||
|
|
||||||
// if the output stream is not null, do not close it
|
|
||||||
outputStream?.let {
|
|
||||||
// prevent writing to same file, if it is being locked
|
|
||||||
// isLocked will be false if the editor was created through a stream
|
|
||||||
val isLocked = filePath?.let { path ->
|
|
||||||
val isLocked = locks[path]!! > 1
|
|
||||||
// decrease the lock count if the editor was opened for a file
|
|
||||||
locks.merge(path, -1, Integer::sum)
|
|
||||||
isLocked
|
|
||||||
} ?: false
|
|
||||||
|
|
||||||
// if unlocked, write back to the file
|
|
||||||
if (!isLocked) {
|
|
||||||
it.value.use { stream ->
|
|
||||||
val result = StreamResult(stream)
|
|
||||||
TransformerFactory.newInstance().newTransformer().transform(DOMSource(file), result)
|
|
||||||
}
|
|
||||||
|
|
||||||
it.value.close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
// map of concurrent open files
|
|
||||||
val locks = mutableMapOf<String, Int>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
src/main/kotlin/app/revanced/patcher/util/ExtraTypes.kt
Normal file
12
src/main/kotlin/app/revanced/patcher/util/ExtraTypes.kt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package app.revanced.patcher.util
|
||||||
|
|
||||||
|
import org.objectweb.asm.Type
|
||||||
|
|
||||||
|
object ExtraTypes {
|
||||||
|
/**
|
||||||
|
* Any object type.
|
||||||
|
* Should be used instead of types such as: "Ljava/lang/String;"
|
||||||
|
*/
|
||||||
|
val Any: Type = Type.getType(Object::class.java)
|
||||||
|
val ArrayAny: Type = Type.getType(Array<Any>::class.java)
|
||||||
|
}
|
||||||
93
src/main/kotlin/app/revanced/patcher/util/Io.kt
Normal file
93
src/main/kotlin/app/revanced/patcher/util/Io.kt
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package app.revanced.patcher.util
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader
|
||||||
|
import org.objectweb.asm.ClassWriter
|
||||||
|
import org.objectweb.asm.tree.ClassNode
|
||||||
|
import java.io.BufferedInputStream
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.util.jar.JarEntry
|
||||||
|
import java.util.jar.JarInputStream
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
|
internal class Io(
|
||||||
|
private val input: InputStream,
|
||||||
|
private val output: OutputStream,
|
||||||
|
private val classes: MutableList<ClassNode>
|
||||||
|
) {
|
||||||
|
private val bufferedInputStream = BufferedInputStream(input)
|
||||||
|
|
||||||
|
fun readFromJar() {
|
||||||
|
bufferedInputStream.mark(Integer.MAX_VALUE)
|
||||||
|
// create a BufferedInputStream in order to read the input stream again when calling saveAsJar(..)
|
||||||
|
val jis = JarInputStream(bufferedInputStream)
|
||||||
|
|
||||||
|
// read all entries from the input stream
|
||||||
|
// we use JarEntry because we only read .class files
|
||||||
|
lateinit var jarEntry: JarEntry
|
||||||
|
while (jis.nextJarEntry.also { if (it != null) jarEntry = it } != null) {
|
||||||
|
// if the current entry ends with .class (indicating a java class file), add it to our list of classes to return
|
||||||
|
if (jarEntry.name.endsWith(".class")) {
|
||||||
|
// create a new ClassNode
|
||||||
|
val classNode = ClassNode()
|
||||||
|
// read the bytes with a ClassReader into the ClassNode
|
||||||
|
ClassReader(jis.readBytes()).accept(classNode, ClassReader.EXPAND_FRAMES)
|
||||||
|
// add it to our list
|
||||||
|
classes.add(classNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, close the entry
|
||||||
|
jis.closeEntry()
|
||||||
|
}
|
||||||
|
|
||||||
|
// at last reset the buffered input stream
|
||||||
|
bufferedInputStream.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveAsJar() {
|
||||||
|
val jis = ZipInputStream(bufferedInputStream)
|
||||||
|
val jos = ZipOutputStream(output)
|
||||||
|
|
||||||
|
// first write all non .class zip entries from the original input stream to the output stream
|
||||||
|
// we read it first to close the input stream as fast as possible
|
||||||
|
// TODO(oSumAtrIX): There is currently no way to remove non .class files.
|
||||||
|
lateinit var zipEntry: ZipEntry
|
||||||
|
while (jis.nextEntry.also { if (it != null) zipEntry = it } != null) {
|
||||||
|
// skip all class files because we added them in the loop above
|
||||||
|
// TODO(oSumAtrIX): Check for zipEntry.isDirectory
|
||||||
|
if (zipEntry.name.endsWith(".class")) continue
|
||||||
|
|
||||||
|
// create a new zipEntry and write the contents of the zipEntry to the output stream
|
||||||
|
jos.putNextEntry(ZipEntry(zipEntry))
|
||||||
|
jos.write(jis.readBytes())
|
||||||
|
|
||||||
|
// close the newly created zipEntry
|
||||||
|
jos.closeEntry()
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, close the input stream
|
||||||
|
jis.close()
|
||||||
|
bufferedInputStream.close()
|
||||||
|
input.close()
|
||||||
|
|
||||||
|
// now write all the patched classes to the output stream
|
||||||
|
for (patchedClass in classes) {
|
||||||
|
// create a new entry of the patched class
|
||||||
|
jos.putNextEntry(JarEntry(patchedClass.name + ".class"))
|
||||||
|
|
||||||
|
// parse the patched class to a byte array and write it to the output stream
|
||||||
|
val cw = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES)
|
||||||
|
patchedClass.accept(cw)
|
||||||
|
jos.write(cw.toByteArray())
|
||||||
|
|
||||||
|
// close the newly created jar entry
|
||||||
|
jos.closeEntry()
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, close the rest of the streams
|
||||||
|
jos.close()
|
||||||
|
output.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package app.revanced.patcher.util
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.ClassProxy
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that represents a set of classes and proxies.
|
|
||||||
*
|
|
||||||
* @param classes The classes to be backed by proxies.
|
|
||||||
*/
|
|
||||||
class ProxyClassList internal constructor(classes: MutableSet<ClassDef>) : MutableSet<ClassDef> by classes {
|
|
||||||
internal val proxies = mutableListOf<ClassProxy>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a [ClassProxy].
|
|
||||||
*/
|
|
||||||
fun add(classProxy: ClassProxy) = proxies.add(classProxy)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace all classes with their mutated versions.
|
|
||||||
*/
|
|
||||||
internal fun replaceClasses() = proxies.removeIf { proxy ->
|
|
||||||
// If the proxy is unused, return false to keep it in the proxies list.
|
|
||||||
if (!proxy.resolved) return@removeIf false
|
|
||||||
|
|
||||||
// If it has been used, replace the original class with the mutable class.
|
|
||||||
remove(proxy.immutableClass)
|
|
||||||
add(proxy.mutableClass)
|
|
||||||
|
|
||||||
// Return true to remove the proxy from the proxies list.
|
|
||||||
return@removeIf true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package app.revanced.patcher.util.method
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a method from another method via instruction offsets.
|
|
||||||
* @param bytecodeContext The context to use when resolving the next method reference.
|
|
||||||
* @param currentMethod The method to start from.
|
|
||||||
*/
|
|
||||||
class MethodWalker internal constructor(
|
|
||||||
private val bytecodeContext: BytecodeContext,
|
|
||||||
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.
|
|
||||||
*
|
|
||||||
* @return The method which was walked last.
|
|
||||||
*/
|
|
||||||
fun getMethod(): Method {
|
|
||||||
return currentMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Walk to a method defined at the offset in the instruction list of the current method.
|
|
||||||
*
|
|
||||||
* The current method will be mutable.
|
|
||||||
*
|
|
||||||
* @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.
|
|
||||||
* @return The same [MethodWalker] instance with the method at [offset].
|
|
||||||
*/
|
|
||||||
fun nextMethod(offset: Int, walkMutable: Boolean = false): MethodWalker {
|
|
||||||
currentMethod.implementation?.instructions?.let { instructions ->
|
|
||||||
val instruction = instructions.elementAt(offset)
|
|
||||||
|
|
||||||
val newMethod = (instruction as ReferenceInstruction).reference as MethodReference
|
|
||||||
val proxy = bytecodeContext.findClass(newMethod.definingClass)!!
|
|
||||||
|
|
||||||
val methods = if (walkMutable) proxy.mutableClass.methods else proxy.immutableClass.methods
|
|
||||||
currentMethod = methods.first {
|
|
||||||
return@first MethodUtil.methodSignaturesMatch(it, newMethod)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
throw MethodNotFoundException("This method can not be walked at offset $offset inside the method ${currentMethod.name}")
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class MethodNotFoundException(exception: String) : Exception(exception)
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
|
||||||
import com.android.tools.smali.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 internal constructor(
|
|
||||||
val immutableClass: ClassDef,
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* Weather the proxy was actually used.
|
|
||||||
*/
|
|
||||||
internal var resolved = false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mutable clone of the original class.
|
|
||||||
*
|
|
||||||
* Note: This is only allocated if the proxy is actually used.
|
|
||||||
*/
|
|
||||||
val mutableClass by lazy {
|
|
||||||
resolved = true
|
|
||||||
if (immutableClass is MutableClass) {
|
|
||||||
immutableClass
|
|
||||||
} else
|
|
||||||
MutableClass(immutableClass)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotationElement.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.base.BaseAnnotation
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.base.BaseAnnotationElement
|
|
||||||
import com.android.tools.smali.dexlib2.iface.AnnotationElement
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
|
||||||
import com.google.common.collect.Iterables
|
|
||||||
import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
import com.android.tools.smali.dexlib2.util.FieldUtil
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.HiddenApiRestriction
|
|
||||||
import com.android.tools.smali.dexlib2.base.reference.BaseFieldReference
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethodParameter.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.HiddenApiRestriction
|
|
||||||
import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference
|
|
||||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
|
||||||
import com.android.tools.smali.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 }
|
|
||||||
|
|
||||||
fun setDefiningClass(definingClass: String) {
|
|
||||||
this.definingClass = definingClass
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setName(name: String) {
|
|
||||||
this.name = name
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setAccessFlags(accessFlags: Int) {
|
|
||||||
this.accessFlags = accessFlags
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setReturnType(returnType: String) {
|
|
||||||
this.returnType = returnType
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.base.BaseMethodParameter
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotationElement.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseAnnotationEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.AnnotationElement
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseArrayEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.ArrayEncodedValue
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseBooleanEncodedValue
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseByteEncodedValue
|
|
||||||
import com.android.tools.smali.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseCharEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.CharEncodedValue
|
|
||||||
|
|
||||||
class MutableCharEncodedValue(charEncodedValue: CharEncodedValue) : BaseCharEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = charEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): Char {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: Char) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun CharEncodedValue.toMutable(): MutableCharEncodedValue {
|
|
||||||
return MutableCharEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseDoubleEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.DoubleEncodedValue
|
|
||||||
|
|
||||||
class MutableDoubleEncodedValue(doubleEncodedValue: DoubleEncodedValue) : BaseDoubleEncodedValue(),
|
|
||||||
MutableEncodedValue {
|
|
||||||
private var value = doubleEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): Double {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: Double) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun DoubleEncodedValue.toMutable(): MutableDoubleEncodedValue {
|
|
||||||
return MutableDoubleEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.ValueType
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.*
|
|
||||||
|
|
||||||
interface MutableEncodedValue : EncodedValue {
|
|
||||||
companion object {
|
|
||||||
fun EncodedValue.toMutable(): MutableEncodedValue {
|
|
||||||
return when (this.valueType) {
|
|
||||||
ValueType.TYPE -> MutableTypeEncodedValue(this as TypeEncodedValue)
|
|
||||||
ValueType.FIELD -> MutableFieldEncodedValue(this as FieldEncodedValue)
|
|
||||||
ValueType.METHOD -> MutableMethodEncodedValue(this as MethodEncodedValue)
|
|
||||||
ValueType.ENUM -> MutableEnumEncodedValue(this as EnumEncodedValue)
|
|
||||||
ValueType.ARRAY -> MutableArrayEncodedValue(this as ArrayEncodedValue)
|
|
||||||
ValueType.ANNOTATION -> MutableAnnotationEncodedValue(this as AnnotationEncodedValue)
|
|
||||||
ValueType.BYTE -> MutableByteEncodedValue(this as ByteEncodedValue)
|
|
||||||
ValueType.SHORT -> MutableShortEncodedValue(this as ShortEncodedValue)
|
|
||||||
ValueType.CHAR -> MutableCharEncodedValue(this as CharEncodedValue)
|
|
||||||
ValueType.INT -> MutableIntEncodedValue(this as IntEncodedValue)
|
|
||||||
ValueType.LONG -> MutableLongEncodedValue(this as LongEncodedValue)
|
|
||||||
ValueType.FLOAT -> MutableFloatEncodedValue(this as FloatEncodedValue)
|
|
||||||
ValueType.DOUBLE -> MutableDoubleEncodedValue(this as DoubleEncodedValue)
|
|
||||||
ValueType.METHOD_TYPE -> MutableMethodTypeEncodedValue(this as MethodTypeEncodedValue)
|
|
||||||
ValueType.METHOD_HANDLE -> MutableMethodHandleEncodedValue(this as MethodHandleEncodedValue)
|
|
||||||
ValueType.STRING -> MutableStringEncodedValue(this as StringEncodedValue)
|
|
||||||
ValueType.BOOLEAN -> MutableBooleanEncodedValue(this as BooleanEncodedValue)
|
|
||||||
ValueType.NULL -> MutableNullEncodedValue()
|
|
||||||
else -> this as MutableEncodedValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseEnumEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.EnumEncodedValue
|
|
||||||
|
|
||||||
class MutableEnumEncodedValue(enumEncodedValue: EnumEncodedValue) : BaseEnumEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = enumEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): FieldReference {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: FieldReference) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun EnumEncodedValue.toMutable(): MutableEnumEncodedValue {
|
|
||||||
return MutableEnumEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.ValueType
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseFieldEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.FieldEncodedValue
|
|
||||||
|
|
||||||
class MutableFieldEncodedValue(fieldEncodedValue: FieldEncodedValue) : BaseFieldEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = fieldEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValueType(): Int {
|
|
||||||
return ValueType.FIELD
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getValue(): FieldReference {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: FieldReference) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun FieldEncodedValue.toMutable(): MutableFieldEncodedValue {
|
|
||||||
return MutableFieldEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseFloatEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.FloatEncodedValue
|
|
||||||
|
|
||||||
class MutableFloatEncodedValue(floatEncodedValue: FloatEncodedValue) : BaseFloatEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = floatEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): Float {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: Float) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun FloatEncodedValue.toMutable(): MutableFloatEncodedValue {
|
|
||||||
return MutableFloatEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseIntEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.IntEncodedValue
|
|
||||||
|
|
||||||
class MutableIntEncodedValue(intEncodedValue: IntEncodedValue) : BaseIntEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = intEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): Int {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: Int) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun IntEncodedValue.toMutable(): MutableIntEncodedValue {
|
|
||||||
return MutableIntEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseLongEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.LongEncodedValue
|
|
||||||
|
|
||||||
class MutableLongEncodedValue(longEncodedValue: LongEncodedValue) : BaseLongEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = longEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): Long {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: Long) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun LongEncodedValue.toMutable(): MutableLongEncodedValue {
|
|
||||||
return MutableLongEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseMethodEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.MethodEncodedValue
|
|
||||||
|
|
||||||
class MutableMethodEncodedValue(methodEncodedValue: MethodEncodedValue) : BaseMethodEncodedValue(),
|
|
||||||
MutableEncodedValue {
|
|
||||||
private var value = methodEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): MethodReference {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: MethodReference) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun MethodEncodedValue.toMutable(): MutableMethodEncodedValue {
|
|
||||||
return MutableMethodEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseMethodHandleEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.MethodHandleEncodedValue
|
|
||||||
|
|
||||||
class MutableMethodHandleEncodedValue(methodHandleEncodedValue: MethodHandleEncodedValue) :
|
|
||||||
BaseMethodHandleEncodedValue(),
|
|
||||||
MutableEncodedValue {
|
|
||||||
private var value = methodHandleEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): MethodHandleReference {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: MethodHandleReference) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun MethodHandleEncodedValue.toMutable(): MutableMethodHandleEncodedValue {
|
|
||||||
return MutableMethodHandleEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseMethodTypeEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodProtoReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.MethodTypeEncodedValue
|
|
||||||
|
|
||||||
class MutableMethodTypeEncodedValue(methodTypeEncodedValue: MethodTypeEncodedValue) : BaseMethodTypeEncodedValue(),
|
|
||||||
MutableEncodedValue {
|
|
||||||
private var value = methodTypeEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): MethodProtoReference {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: MethodProtoReference) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun MethodTypeEncodedValue.toMutable(): MutableMethodTypeEncodedValue {
|
|
||||||
return MutableMethodTypeEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseNullEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.ByteEncodedValue
|
|
||||||
|
|
||||||
class MutableNullEncodedValue : BaseNullEncodedValue(), MutableEncodedValue {
|
|
||||||
companion object {
|
|
||||||
fun ByteEncodedValue.toMutable(): MutableByteEncodedValue {
|
|
||||||
return MutableByteEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseShortEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.ShortEncodedValue
|
|
||||||
|
|
||||||
class MutableShortEncodedValue(shortEncodedValue: ShortEncodedValue) : BaseShortEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = shortEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): Short {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: Short) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun ShortEncodedValue.toMutable(): MutableShortEncodedValue {
|
|
||||||
return MutableShortEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseStringEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.ByteEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue
|
|
||||||
|
|
||||||
class MutableStringEncodedValue(stringEncodedValue: StringEncodedValue) : BaseStringEncodedValue(),
|
|
||||||
MutableEncodedValue {
|
|
||||||
private var value = stringEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): String {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: String) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun ByteEncodedValue.toMutable(): MutableByteEncodedValue {
|
|
||||||
return MutableByteEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.base.value.BaseTypeEncodedValue
|
|
||||||
import com.android.tools.smali.dexlib2.iface.value.TypeEncodedValue
|
|
||||||
|
|
||||||
class MutableTypeEncodedValue(typeEncodedValue: TypeEncodedValue) : BaseTypeEncodedValue(), MutableEncodedValue {
|
|
||||||
private var value = typeEncodedValue.value
|
|
||||||
|
|
||||||
override fun getValue(): String {
|
|
||||||
return this.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(value: String) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun TypeEncodedValue.toMutable(): MutableTypeEncodedValue {
|
|
||||||
return MutableTypeEncodedValue(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package app.revanced.patcher.util.smali
|
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that represents a label for an instruction.
|
|
||||||
* @param name The label name.
|
|
||||||
* @param instruction The instruction that this label is for.
|
|
||||||
*/
|
|
||||||
data class ExternalLabel(internal val name: String, internal val instruction: Instruction)
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package app.revanced.patcher.util.smali
|
|
||||||
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import org.antlr.runtime.CommonTokenStream
|
|
||||||
import org.antlr.runtime.TokenSource
|
|
||||||
import org.antlr.runtime.tree.CommonTreeNodeStream
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
import com.android.tools.smali.dexlib2.Opcodes
|
|
||||||
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.writer.builder.DexBuilder
|
|
||||||
import com.android.tools.smali.smali.LexerErrorInterface
|
|
||||||
import com.android.tools.smali.smali.smaliFlexLexer
|
|
||||||
import com.android.tools.smali.smali.smaliParser
|
|
||||||
import com.android.tools.smali.smali.smaliTreeWalker
|
|
||||||
import java.io.InputStreamReader
|
|
||||||
|
|
||||||
private const val METHOD_TEMPLATE = """
|
|
||||||
.class LInlineCompiler;
|
|
||||||
.super Ljava/lang/Object;
|
|
||||||
.method %s dummyMethod(%s)V
|
|
||||||
.registers %d
|
|
||||||
%s
|
|
||||||
.end method
|
|
||||||
"""
|
|
||||||
|
|
||||||
class InlineSmaliCompiler {
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Compiles a string of Smali code to a list of instructions.
|
|
||||||
* Special registers (such as p0, p1) will only work correctly
|
|
||||||
* if the parameters and registers of the method are passed.
|
|
||||||
*/
|
|
||||||
fun compile(
|
|
||||||
instructions: String, parameters: String, registers: Int, forStaticMethod: Boolean
|
|
||||||
): List<BuilderInstruction> {
|
|
||||||
val input = METHOD_TEMPLATE.format(
|
|
||||||
if (forStaticMethod) {
|
|
||||||
"static"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}, parameters, registers, instructions
|
|
||||||
)
|
|
||||||
val reader = InputStreamReader(input.byteInputStream())
|
|
||||||
val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
|
|
||||||
val tokens = CommonTokenStream(lexer as TokenSource)
|
|
||||||
val parser = smaliParser(tokens)
|
|
||||||
val result = parser.smali_file()
|
|
||||||
if (parser.numberOfSyntaxErrors > 0 || lexer.numberOfSyntaxErrors > 0) {
|
|
||||||
throw IllegalStateException(
|
|
||||||
"Encountered ${parser.numberOfSyntaxErrors} parser syntax errors and ${lexer.numberOfSyntaxErrors} lexer syntax errors!"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val treeStream = CommonTreeNodeStream(result.tree)
|
|
||||||
treeStream.tokenStream = tokens
|
|
||||||
val dexGen = smaliTreeWalker(treeStream)
|
|
||||||
dexGen.setDexBuilder(DexBuilder(Opcodes.getDefault()))
|
|
||||||
val classDef = dexGen.smali_file()
|
|
||||||
return classDef.methods.first().implementation!!.instructions.map { it as BuilderInstruction }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile lines of Smali code to a list of instructions.
|
|
||||||
*
|
|
||||||
* Note: Adding compiled instructions to an existing method with
|
|
||||||
* offset instructions WITHOUT specifying a parent method will not work.
|
|
||||||
* @param method The method to compile the instructions against.
|
|
||||||
* @returns A list of instructions.
|
|
||||||
*/
|
|
||||||
fun String.toInstructions(method: MutableMethod? = null): List<BuilderInstruction> {
|
|
||||||
return InlineSmaliCompiler.compile(this,
|
|
||||||
method?.parameters?.joinToString("") { it } ?: "",
|
|
||||||
method?.implementation?.registerCount ?: 1,
|
|
||||||
method?.let { AccessFlags.STATIC.isSet(it.accessFlags) } ?: true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile a line of Smali code to an instruction.
|
|
||||||
* @param templateMethod The method to compile the instructions against.
|
|
||||||
* @return The instruction.
|
|
||||||
*/
|
|
||||||
fun String.toInstruction(templateMethod: MutableMethod? = null) = this.toInstructions(templateMethod).first()
|
|
||||||
21
src/main/kotlin/app/revanced/patcher/writer/ASMWriter.kt
Normal file
21
src/main/kotlin/app/revanced/patcher/writer/ASMWriter.kt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.patcher.writer
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode
|
||||||
|
import org.objectweb.asm.tree.InsnList
|
||||||
|
|
||||||
|
object ASMWriter {
|
||||||
|
fun InsnList.setAt(index: Int, node: AbstractInsnNode) {
|
||||||
|
this[this.get(index)] = node
|
||||||
|
}
|
||||||
|
|
||||||
|
fun InsnList.insertAt(index: Int = 0, vararg nodes: AbstractInsnNode) {
|
||||||
|
this.insert(this.get(index), nodes.toInsnList())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Sculas): Should this be public?
|
||||||
|
private fun Array<out AbstractInsnNode>.toInsnList(): InsnList {
|
||||||
|
val list = InsnList()
|
||||||
|
this.forEach { list.add(it) }
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
version=${projectVersion}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user