├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── dependabot.yml ├── scripts │ └── telegram_url.py └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── apd ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs └── src │ ├── apd.rs │ ├── assets.rs │ ├── banner │ ├── cli.rs │ ├── defs.rs │ ├── event.rs │ ├── installer.sh │ ├── installer_bind.sh │ ├── m_mount.rs │ ├── main.rs │ ├── module.rs │ ├── mount.rs │ ├── package.rs │ ├── pty.rs │ ├── restorecon.rs │ ├── supercall.rs │ └── utils.rs ├── app ├── .gitignore ├── build.gradle.kts ├── libs │ └── arm64-v8a │ │ ├── .gitignore │ │ ├── libbootctl.so │ │ ├── libbusybox.so │ │ ├── libmagiskboot.so │ │ ├── libmagiskpolicy.so │ │ └── libresetprop.so ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ └── me │ │ └── bmax │ │ └── apatch │ │ └── IAPRootService.aidl │ ├── assets │ ├── .gitignore │ ├── InstallAP.sh │ ├── UninstallAP.sh │ ├── boot_extract.sh │ ├── boot_patch.sh │ ├── boot_unpatch.sh │ └── util_functions.sh │ ├── cpp │ ├── CMakeLists.txt │ ├── apjni.cpp │ ├── apjni.hpp │ ├── supercall.h │ ├── uapi │ │ └── scdefs.h │ └── version │ ├── ic_launcher-playstore.png │ ├── java │ └── me │ │ └── bmax │ │ └── apatch │ │ ├── APatchApp.kt │ │ ├── Natives.kt │ │ ├── services │ │ └── RootServices.java │ │ ├── ui │ │ ├── CrashHandleActivity.kt │ │ ├── MainActivity.kt │ │ ├── WebUIActivity.kt │ │ ├── component │ │ │ ├── Dialog.kt │ │ │ ├── DropdownMenu.kt │ │ │ ├── KeyEventBlocker.kt │ │ │ ├── ModuleCardComponents.kt │ │ │ ├── SearchBar.kt │ │ │ └── SettingsItem.kt │ │ ├── screen │ │ │ ├── APM.kt │ │ │ ├── AboutScreen.kt │ │ │ ├── BottomBarDestination.kt │ │ │ ├── ExecuteAPMAction.kt │ │ │ ├── Home.kt │ │ │ ├── Install.kt │ │ │ ├── InstallModeSelect.kt │ │ │ ├── KPM.kt │ │ │ ├── Patches.kt │ │ │ ├── Settings.kt │ │ │ └── SuperUser.kt │ │ ├── theme │ │ │ ├── AmberTheme.kt │ │ │ ├── BlueGreyTheme.kt │ │ │ ├── BlueTheme.kt │ │ │ ├── BrownTheme.kt │ │ │ ├── CyanTheme.kt │ │ │ ├── DeepOrangeTheme.kt │ │ │ ├── DeepPurpleTheme.kt │ │ │ ├── GreenTheme.kt │ │ │ ├── IndigoTheme.kt │ │ │ ├── LightBlueTheme.kt │ │ │ ├── LightGreenTheme.kt │ │ │ ├── LimeTheme.kt │ │ │ ├── OrangeTheme.kt │ │ │ ├── PinkTheme.kt │ │ │ ├── PurpleTheme.kt │ │ │ ├── RedTheme.kt │ │ │ ├── SakuraTheme.kt │ │ │ ├── TealTheme.kt │ │ │ ├── Theme.kt │ │ │ ├── Type.kt │ │ │ └── YellowTheme.kt │ │ ├── viewmodel │ │ │ ├── APModuleViewModel.kt │ │ │ ├── KPModel.kt │ │ │ ├── KPModuleViewModel.kt │ │ │ ├── PatchesViewModel.kt │ │ │ └── SuperUserViewModel.kt │ │ └── webui │ │ │ ├── MimeUtil.java │ │ │ ├── SuFilePathHandler.java │ │ │ └── WebViewInterface.kt │ │ └── util │ │ ├── APatchCli.kt │ │ ├── APatchKeyHelper.java │ │ ├── DeviceInfoUtils.kt │ │ ├── Downloader.kt │ │ ├── HanziToPinyin.java │ │ ├── IOStreamUtils.kt │ │ ├── LatestVersionInfo.kt │ │ ├── LogEvent.kt │ │ ├── PkgConfig.kt │ │ ├── Version.kt │ │ ├── apksign │ │ ├── ApkSignerV2.java │ │ ├── ByteArrayStream.java │ │ ├── JarMap.java │ │ ├── SignApk.java │ │ └── ZipUtils.java │ │ ├── hideapk │ │ ├── AXML.kt │ │ ├── HideAPK.kt │ │ └── Keygen.kt │ │ └── ui │ │ ├── APDialogBlurBehindUtils.kt │ │ ├── CompositionProvider.kt │ │ ├── HyperlinkText.kt │ │ └── NavigationBarsSpacer.kt │ └── res │ ├── drawable │ ├── device_mobile_down.xml │ ├── github.xml │ ├── ic_launcher_background.xml │ ├── ic_launcher_foreground.xml │ ├── ic_launcher_monochrome.xml │ ├── info_circle_filled.xml │ ├── launcher_splash.xml │ ├── package_import.xml │ ├── settings.xml │ ├── telegram.xml │ ├── trash.xml │ └── weblate.xml │ ├── mipmap-anydpi │ └── ic_launcher.xml │ ├── resources.properties │ ├── values-ar │ └── strings.xml │ ├── values-arq │ └── strings.xml │ ├── values-az │ └── strings.xml │ ├── values-bn │ └── strings.xml │ ├── values-ca │ └── strings.xml │ ├── values-cs │ └── strings.xml │ ├── values-de │ └── strings.xml │ ├── values-el │ └── strings.xml │ ├── values-es │ └── strings.xml │ ├── values-fa │ └── strings.xml │ ├── values-fil │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-gl │ └── strings.xml │ ├── values-hr │ └── strings.xml │ ├── values-hu │ └── strings.xml │ ├── values-in │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-jv │ └── strings.xml │ ├── values-ko │ └── strings.xml │ ├── values-lt │ └── strings.xml │ ├── values-ms │ └── strings.xml │ ├── values-nb-rNO │ └── strings.xml │ ├── values-night │ └── themes.xml │ ├── values-nl │ └── strings.xml │ ├── values-pl │ └── strings.xml │ ├── values-pt-rBR │ └── strings.xml │ ├── values-pt │ └── strings.xml │ ├── values-ro │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-si │ └── strings.xml │ ├── values-sv │ └── strings.xml │ ├── values-th │ └── strings.xml │ ├── values-tr │ └── strings.xml │ ├── values-uk │ └── strings.xml │ ├── values-vi │ └── strings.xml │ ├── values-zh-rCN │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ ├── values │ ├── arrays.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ ├── data_extraction_rules.xml │ ├── file_paths.xml │ └── network_security_config.xml ├── build.gradle.kts ├── docs ├── az │ └── faq_az.md ├── cn │ ├── ap_module.md │ └── faq_cn.md ├── cn_tw │ └── faq_cn_tw.md ├── de │ └── faq_de.md ├── en │ └── faq.md ├── es │ └── faq_es.md ├── fr │ └── faq_fr.md ├── id │ └── faq.md ├── it │ └── faq_it.md ├── kr │ └── faq_kr.md ├── pt_br │ └── faq_pt_br.md ├── ru │ ├── .gitkeep │ └── faq_ru.md ├── tr │ └── faq_tr.md └── uk │ └── faq_uk.md ├── fastlane └── metadata │ └── android │ └── en-US │ ├── full_description.txt │ ├── images │ └── icon.png │ └── short_description.txt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── scripts ├── update_binary.sh └── update_script.sh └── settings.gradle.kts /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text eol=lf 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | # *.c text 7 | # *.h text 8 | 9 | # Declare files that will always have CRLF line endings on checkout. 10 | *.cmd text eol=crlf 11 | *.bat text eol=crlf 12 | 13 | # Denote all files that are truly binary and should not be modified. 14 | tools/** binary 15 | *.jar binary 16 | *.exe binary 17 | *.apk binary 18 | *.png binary 19 | *.jpg binary 20 | *.ttf binary 21 | *.so binary 22 | 23 | # Help GitHub detect languages 24 | native/jni/external/** linguist-vendored 25 | native/jni/systemproperties/** linguist-language=C++ 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report/反馈 Bug 2 | description: Report errors or unexpected behavior./报告错误或未预料的行为 3 | labels: [bug] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for reporting issues of APatch! 10 | 11 | To make it easier for us to help you please enter detailed information below. 12 | 13 | 感谢给 APatch 汇报问题! 14 | 为了使我们更好地帮助你,请提供以下信息。 15 | 为了防止重复汇报,标题请务必使用英文。 16 | 17 | - type: checkboxes 18 | attributes: 19 | label: Please check before submitting an issue/在提交 issue 前请检查 20 | options: 21 | - label: I have searched the issues and haven't found anything relevant/我已经搜索了 issues 列表,没有发现于本问题相关内容 22 | required: true 23 | 24 | - label: If patch failed, root failed, or device unable to boot after flashing the new boot.img. Please goto KernelPatch/修复失败或刷入修补后镜像不能启动,请前往 KernelPatch 提问 25 | required: true 26 | 27 | - label: I will upload bugreport file in APatch Manager - Settings - Report log/我会上传 bureport 文件从 APatch 管理器 - 设置 - 发送日志 28 | required: true 29 | 30 | - label: I know how to reproduce the issue which may not be specific to my device/我知道如何重新复现这个问题 31 | required: false 32 | 33 | - type: checkboxes 34 | id: latest 35 | attributes: 36 | label: Version requirement/版本要求 37 | options: 38 | - label: I am using latest CI version of APatch/我正在使用最新 CI 版本 39 | required: true 40 | 41 | - type: textarea 42 | attributes: 43 | label: Describe the bug/描述 bug 44 | description: A clear and concise description of what the bug is/对 bug 的清晰简洁的描述 45 | validations: 46 | required: true 47 | 48 | - type: textarea 49 | attributes: 50 | label: Reproduce method/复现方法 51 | description: Steps to reproduce the behaviour/复现的步骤 52 | placeholder: | 53 | - 1. Go to '...' 54 | - 2. Click on '....' 55 | - 3. Scroll down to '....' 56 | - 4. See error 57 | validations: 58 | required: true 59 | 60 | - type: textarea 61 | attributes: 62 | label: Expected behavior/预期行为 63 | description: A clear and concise description of what you expected to happen./对你期望发生的行为进行清晰简洁的描述 64 | validations: 65 | required: true 66 | 67 | - type: textarea 68 | attributes: 69 | label: Actual behaviour /实际行为 70 | placeholder: Tell us what happens instead/告诉我们实际发生了什么 71 | validations: 72 | required: true 73 | 74 | - type: textarea 75 | attributes: 76 | label: Screenshots/截图 77 | description: If applicable, add screenshots to help explain your problem./如果可以的话,添加截图可以帮你解释问题 78 | 79 | - type: textarea 80 | attributes: 81 | label: Logs/日志 82 | description: If applicable, add crash or any other logs to help us figure out the problem./如果可以的话,添加崩溃日志可以帮助我们找到问题 83 | 84 | - type: input 85 | attributes: 86 | label: Device Name/设备名称 87 | validations: 88 | required: true 89 | 90 | - type: input 91 | attributes: 92 | label: OS Version/系统版本 93 | validations: 94 | required: true 95 | 96 | - type: input 97 | attributes: 98 | label: APatch Version/APatch 版本 99 | validations: 100 | required: true 101 | 102 | - type: input 103 | attributes: 104 | label: Kernel Version/内核版本 105 | validations: 106 | required: true 107 | 108 | - type: input 109 | attributes: 110 | label: KernelPatch Version/KernelPatch 版本 111 | validations: 112 | required: true 113 | 114 | - type: textarea 115 | attributes: 116 | label: Additional context/其他信息 117 | description: Add any other context about the problem here./添加关于问题的任何信息。 118 | placeholder: Upload logs zip by clicking the bar on the bottom. Upload logs to other websites or using external links is prohibited./点击文本框底栏上传日志压缩包,禁止上传到其它网站或使用外链提供日志。 119 | validations: 120 | required: true 121 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question/提问 4 | url: https://github.com/bmax121/APatch/discussions/new?category=Q-A 5 | about: Please ask and answer questions here./如果有任何疑问请在这里提问 6 | - name: Official Telegram Channel/官方 Telegram 频道 7 | url: https://t.me/APatchChannel 8 | about: Subscribe for notifications and releases/可以订阅通知和发行版 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request/新特性请求 3 | description: Suggest an idea for this project./提出建议 4 | labels: [enhancement] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Is your feature request related to a problem?/你的请求是否与某个问题相关? 9 | placeholder: A clear and concise description of what the problem is./请清晰准确表述该问题。 10 | validations: 11 | required: true 12 | - type: textarea 13 | attributes: 14 | label: Describe the solution you'd like/描述你想要的解决方案 15 | placeholder: A clear and concise description of what you want to happen./请清晰准确描述新特性的预期行为 16 | validations: 17 | required: true 18 | - type: textarea 19 | attributes: 20 | label: Describe alternatives you've considered/描述您考虑过的备选方案 21 | placeholder: A clear and concise description of any alternative solutions or features you've considered./对您考虑过的任何替代解决方案或功能的清晰简洁的描述。 22 | validations: 23 | required: true 24 | - type: textarea 25 | attributes: 26 | label: Additional context/其他信息 27 | placeholder: Add any other context or screenshots about the feature request here./其他关于新特性的信息或者截图。 28 | validations: 29 | required: false -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | target-branch: main 8 | registries: 9 | - maven-google 10 | - gradle-plugin 11 | groups: 12 | maven-dependencies: 13 | patterns: 14 | - "*" 15 | 16 | - package-ecosystem: github-actions 17 | target-branch: main 18 | directory: / 19 | schedule: 20 | interval: daily 21 | groups: 22 | action-dependencies: 23 | patterns: 24 | - "*" 25 | 26 | - package-ecosystem: cargo 27 | target-branch: main 28 | directory: apd/ 29 | schedule: 30 | interval: daily 31 | allow: 32 | - dependency-type: "all" 33 | groups: 34 | rust-dependencies: 35 | patterns: 36 | - "*" 37 | 38 | registries: 39 | maven-google: 40 | type: maven-repository 41 | url: "https://dl.google.com/dl/android/maven2/" 42 | gradle-plugin: 43 | type: maven-repository 44 | url: "https://plugins.gradle.org/m2/" 45 | -------------------------------------------------------------------------------- /.github/scripts/telegram_url.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import sys 4 | import urllib.parse 5 | 6 | 7 | url = f'https://api.telegram.org/bot{os.environ["BOT_TOKEN"]}' 8 | url += f'/sendMediaGroup?chat_id={urllib.parse.quote(sys.argv[1])}&media=' 9 | 10 | # https://core.telegram.org/bots/api#markdownv2-style 11 | msg = os.environ["COMMIT_MESSAGE"] 12 | for c in ['\\', '_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!']: 13 | msg = msg.replace(c, f'\\{c}') 14 | commit_url = os.environ["COMMIT_URL"] 15 | commit_id = os.environ["COMMIT_ID"][:7] 16 | 17 | caption = f"[{commit_id}]({commit_url})\n{msg}"[:1024] 18 | 19 | data = json.dumps([ 20 | {"type": "document", "media": "attach://Release","caption": caption,"parse_mode":"MarkdownV2"} 21 | ]) 22 | 23 | url += urllib.parse.quote(data) 24 | print(url) -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Manager 2 | 3 | on: 4 | push: 5 | tags: [ "*" ] 6 | branches: [ "main" ] 7 | paths: 8 | - '.github/workflows/build.yml' 9 | - 'app/**' 10 | - 'apd/**' 11 | - 'build.gradle.kts' 12 | - 'gradle/libs.versions.toml' 13 | pull_request: 14 | branches: [ "main" ] 15 | paths: 16 | - '.github/workflows/build.yml' 17 | - 'app/**' 18 | - 'apd/**' 19 | - 'build.gradle.kts' 20 | - 'gradle/libs.versions.toml' 21 | workflow_call: 22 | workflow_dispatch: 23 | 24 | jobs: 25 | build-manager: 26 | runs-on: ubuntu-latest 27 | permissions: 28 | contents: write 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v4 32 | with: 33 | fetch-depth: 0 34 | 35 | - name: Generate version 36 | id: parse_version 37 | run: | 38 | COMMIT_NUM=$(git rev-list --count HEAD) 39 | VERSION=$(echo "$COMMIT_NUM + 198 + 10000" | bc) 40 | echo "Generated Version: $VERSION" 41 | echo "VERSION=$VERSION" >> $GITHUB_OUTPUT 42 | 43 | - name: Setup Java 44 | uses: actions/setup-java@v4 45 | with: 46 | distribution: temurin 47 | java-version: 21 48 | 49 | - name: Setup Gradle 50 | uses: gradle/actions/setup-gradle@v4 51 | 52 | - name: Setup Android SDK 53 | uses: android-actions/setup-android@v3 54 | with: 55 | packages: '' 56 | 57 | - name: Install toolchain 58 | run: | 59 | rustup default stable 60 | rustup update stable 61 | cargo install cargo-ndk 62 | rustup target install aarch64-linux-android 63 | 64 | - name: Cache Rust 65 | uses: Swatinem/rust-cache@v2 66 | with: 67 | workspaces: apd 68 | cache-targets: false 69 | 70 | - name: Build with Gradle 71 | run: | 72 | echo 'org.gradle.parallel=true' >> gradle.properties 73 | echo 'org.gradle.vfs.watch=true' >> gradle.properties 74 | echo 'org.gradle.jvmargs=-Xmx2048m' >> gradle.properties 75 | echo 'android.native.buildOutput=verbose' >> gradle.properties 76 | sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties 77 | ./gradlew clean assembleRelease 78 | echo "BUILD_TOOL_VERSION=$(ls /usr/local/lib/android/sdk/build-tools/ | tail -n 1)" >> $GITHUB_ENV 79 | 80 | - name: Sign Release 81 | env: 82 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 83 | if: ${{ env.SIGNING_KEY != '' }} 84 | continue-on-error: true 85 | uses: noriban/sign-android-release@v5.1 86 | id: sign_app 87 | with: 88 | releaseDirectory: app/build/outputs/apk/release 89 | signingKeyBase64: ${{ secrets.SIGNING_KEY }} 90 | alias: ${{ secrets.ALIAS }} 91 | keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} 92 | keyPassword: ${{ secrets.KEY_PASSWORD }} 93 | 94 | - name: Upload build artifact 95 | env: 96 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 97 | if: ${{ env.SIGNING_KEY != '' }} 98 | uses: actions/upload-artifact@v4 99 | with: 100 | name: APatchLite 101 | path: ${{steps.sign_app.outputs.signedReleaseFile}} 102 | 103 | - name: Post to channel 104 | if: ${{github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && github.ref_type != 'tag'}} 105 | env: 106 | BOT_TOKEN: ${{ secrets.BOT_TOKEN }} 107 | COMMIT_MESSAGE: ${{ github.event.head_commit.message }} 108 | COMMIT_URL: ${{ github.event.head_commit.url }} 109 | COMMIT_ID: ${{ github.event.head_commit.id }} 110 | run: | 111 | if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then 112 | OUTPUT="app/build/outputs/apk/release" 113 | export Release=$(find $OUTPUT -name "*.apk") 114 | URL=$(python3 .github/scripts/telegram_url.py -1002058433411) 115 | curl -v "$URL" -F Release=@${{ steps.sign_app.outputs.signedReleaseFile }} 116 | URL=$(python3 .github/scripts/telegram_url.py -1001910818234) 117 | curl -v "$URL" -F Release=@${{ steps.sign_app.outputs.signedReleaseFile }} 118 | fi 119 | 120 | - name: Release apk 121 | env: 122 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 123 | if: ${{ env.SIGNING_KEY != '' && github.ref_type == 'tag' }} 124 | continue-on-error: true 125 | uses: ncipollo/release-action@v1 126 | with: 127 | token: ${{ github.token }} 128 | tag: ${{ steps.parse_version.outputs.VERSION }} 129 | artifacts: ${{steps.sign_app.outputs.signedReleaseFile}} 130 | generateReleaseNotes: true 131 | makeLatest: true 132 | replacesArtifacts: true 133 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | local.properties 4 | .idea 5 | .DS_Store 6 | build 7 | captures 8 | .cxx 9 | key.jks 10 | key.jks.base64.txt 11 | .vscode 12 | .kotlin 13 | app/src/main/resources/ 14 | private 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > :warning: This is a fork of the original APatch project. 2 | 3 | > :warning: This is a simplified version which uses an **HARDCODED SUPERKEY** for the kernel super calls. You may consider this as non-secure for your use cases so consider yourself warned! 4 | 5 | > :warning: If you intend to use the official version, please go to the [official APatch](https://github.com/bmax121/APatch) project page to download an official release package. 6 | 7 | I made this fork with simplicity and an easy-to-use UI in mind for my daily usage of a simple SuperUser management app with OverlayFS support. 8 | These are the differences compared with the original version: 9 | - Hardcoded superkey for simplicity 10 | - Simplified patching UI 11 | - No KPM management 12 | 13 | --- 14 | 15 |
(filename: P) -> io::Result>(emptyList())
21 | }
22 |
23 | var isRefreshing by mutableStateOf(false)
24 | private set
25 |
26 | val moduleList by derivedStateOf {
27 | val comparator = compareBy(Collator.getInstance(Locale.getDefault()), KPModel.KPMInfo::name)
28 | modules.sortedWith(comparator).also {
29 | isRefreshing = false
30 | }
31 | }
32 |
33 | var isNeedRefresh by mutableStateOf(false)
34 | private set
35 |
36 | fun markNeedRefresh() {
37 | isNeedRefresh = true
38 | }
39 |
40 | fun fetchModuleList() {
41 | viewModelScope.launch(Dispatchers.IO) {
42 | isRefreshing = true
43 | val oldModuleList = modules
44 | val start = SystemClock.elapsedRealtime()
45 |
46 | kotlin.runCatching {
47 | var names = Natives.kernelPatchModuleList()
48 | if (Natives.kernelPatchModuleNum() <= 0)
49 | names = ""
50 | val nameList = names.split('\n').toList()
51 | Log.d(TAG, "kpm list: $nameList")
52 | modules = nameList.filter { it.isNotEmpty() }.map {
53 | val infoline = Natives.kernelPatchModuleInfo(it)
54 | val spi = infoline.split('\n')
55 | val name = spi.find { it.startsWith("name=") }?.removePrefix("name=")
56 | val version = spi.find { it.startsWith("version=") }?.removePrefix("version=")
57 | val license = spi.find { it.startsWith("license=") }?.removePrefix("license=")
58 | val author = spi.find { it.startsWith("author=") }?.removePrefix("author=")
59 | val description =
60 | spi.find { it.startsWith("description=") }?.removePrefix("description=")
61 | val args = spi.find { it.startsWith("args=") }?.removePrefix("args=")
62 | val info = KPModel.KPMInfo(
63 | KPModel.ExtraType.KPM,
64 | name ?: "",
65 | "",
66 | args ?: "",
67 | version ?: "",
68 | license ?: "",
69 | author ?: "",
70 | description ?: ""
71 | )
72 | info
73 | }
74 | isNeedRefresh = false
75 | }.onFailure { e ->
76 | Log.e(TAG, "fetchModuleList: ", e)
77 | isRefreshing = false
78 | }
79 |
80 | // when both old and new is kotlin.collections.EmptyList
81 | // moduleList update will don't trigger
82 | if (oldModuleList === modules) {
83 | isRefreshing = false
84 | }
85 |
86 | Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules")
87 | }
88 | }
89 |
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/me/bmax/apatch/ui/webui/MimeUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package me.bmax.apatch.ui.webui;
18 |
19 | import java.net.URLConnection;
20 |
21 | class MimeUtil {
22 |
23 | public static String getMimeFromFileName(String fileName) {
24 | if (fileName == null) {
25 | return null;
26 | }
27 |
28 | // Copying the logic and mapping that Chromium follows.
29 | // First we check against the OS (this is a limited list by default)
30 | // but app developers can extend this.
31 | // We then check against a list of hardcoded mime types above if the
32 | // OS didn't provide a result.
33 | String mimeType = URLConnection.guessContentTypeFromName(fileName);
34 |
35 | if (mimeType != null) {
36 | return mimeType;
37 | }
38 |
39 | return guessHardcodedMime(fileName);
40 | }
41 |
42 | // We should keep this map in sync with the lists under
43 | // //net/base/mime_util.cc in Chromium.
44 | // A bunch of the mime types don't really apply to Android land
45 | // like word docs so feel free to filter out where necessary.
46 | private static String guessHardcodedMime(String fileName) {
47 | int finalFullStop = fileName.lastIndexOf('.');
48 | if (finalFullStop == -1) {
49 | return null;
50 | }
51 |
52 | final String extension = fileName.substring(finalFullStop + 1).toLowerCase();
53 |
54 | switch (extension) {
55 | case "webm":
56 | return "video/webm";
57 | case "mpeg":
58 | case "mpg":
59 | return "video/mpeg";
60 | case "mp3":
61 | return "audio/mpeg";
62 | case "wasm":
63 | return "application/wasm";
64 | case "xhtml":
65 | case "xht":
66 | case "xhtm":
67 | return "application/xhtml+xml";
68 | case "flac":
69 | return "audio/flac";
70 | case "ogg":
71 | case "oga":
72 | case "opus":
73 | return "audio/ogg";
74 | case "wav":
75 | return "audio/wav";
76 | case "m4a":
77 | return "audio/x-m4a";
78 | case "gif":
79 | return "image/gif";
80 | case "jpeg":
81 | case "jpg":
82 | case "jfif":
83 | case "pjpeg":
84 | case "pjp":
85 | return "image/jpeg";
86 | case "png":
87 | return "image/png";
88 | case "apng":
89 | return "image/apng";
90 | case "svg":
91 | case "svgz":
92 | return "image/svg+xml";
93 | case "webp":
94 | return "image/webp";
95 | case "mht":
96 | case "mhtml":
97 | return "multipart/related";
98 | case "css":
99 | return "text/css";
100 | case "html":
101 | case "htm":
102 | case "shtml":
103 | case "shtm":
104 | case "ehtml":
105 | return "text/html";
106 | case "js":
107 | case "mjs":
108 | return "application/javascript";
109 | case "xml":
110 | return "text/xml";
111 | case "mp4":
112 | case "m4v":
113 | return "video/mp4";
114 | case "ogv":
115 | case "ogm":
116 | return "video/ogg";
117 | case "ico":
118 | return "image/x-icon";
119 | case "woff":
120 | return "application/font-woff";
121 | case "gz":
122 | case "tgz":
123 | return "application/gzip";
124 | case "json":
125 | return "application/json";
126 | case "pdf":
127 | return "application/pdf";
128 | case "zip":
129 | return "application/zip";
130 | case "bmp":
131 | return "image/bmp";
132 | case "tiff":
133 | case "tif":
134 | return "image/tiff";
135 | default:
136 | return null;
137 | }
138 | }
139 | }
--------------------------------------------------------------------------------
/app/src/main/java/me/bmax/apatch/util/DeviceInfoUtils.kt:
--------------------------------------------------------------------------------
1 | package me.bmax.apatch.util
2 |
3 | import android.util.Log
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.res.stringResource
6 | import com.topjohnwu.superuser.Shell
7 | import me.bmax.apatch.R
8 |
9 | @Composable
10 | fun getSELinuxStatus(): String {
11 | val shell = Shell.Builder.create()
12 | .build("sh")
13 |
14 | val list = ArrayList
Sertai saluran kami di %2$s
3 |
9 | inline-hook
and syscall-table-hook
enabled).
10 |
13 | Support for Samsung devices with security protection: Planned
14 | Kernel configs:
15 |
16 |
23 | The SuperKey has higher privileges than root access.
24 | Weak or compromised keys can lead to unauthorized control of your device.
25 | It is critical to use robust keys and safeguard them from exposure to maintain the security of your device.
26 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
1 | ../../../../../app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | The patching of Android kernel and Android system
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.experimental.enableNewResourceShrinker.preciseShrinking=true
2 | android.enableAppCompileTimeRClass=true
3 | android.useAndroidX=true
4 |
5 | org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.7.2"
3 | kotlin = "2.0.21"
4 | ksp = "2.0.21-1.0.28"
5 | compose-bom = "2024.11.00"
6 | lifecycle = "2.8.7"
7 | compose-destination = "2.1.0-beta14"
8 | libsu = "6.0.0"
9 | sheets-compose-dialogs = "1.3.0"
10 |
11 | [plugins]
12 | agp-app = { id = "com.android.application", version.ref = "agp" }
13 | agp-lib = { id = "com.android.library", version.ref = "agp" }
14 | kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
15 | ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
16 | lsplugin-apksign = { id = "org.lsposed.lsplugin.apksign", version = "1.4" }
17 | lsplugin-resopt = { id = "org.lsposed.lsplugin.resopt", version = "1.6" }
18 | lsplugin-cmaker = { id = "org.lsposed.lsplugin.cmaker", version = "1.2" }
19 | kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
20 |
21 | [libraries]
22 | androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version = "1.7.0" }
23 | androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version = "1.9.3" }
24 | androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version = "1.0.1" }
25 | androidx-webkit = { group = "androidx.webkit", name = "webkit", version = "1.12.1" }
26 |
27 | androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
28 | androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" }
29 | androidx-compose-material = { group = "androidx.compose.material", name = "material" }
30 | androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version = "1.4.0-alpha04" } # For material3 PullToRefresh, work around https://issuetracker.google.com/issues/359949836, remove the `version` when 1.4.0 released
31 | androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
32 | androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
33 | androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
34 | androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
35 | androidx-compose-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata" }
36 |
37 | androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
38 | androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" }
39 | androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" }
40 |
41 | com-github-topjohnwu-libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref = "libsu" }
42 | com-github-topjohnwu-libsu-service = { group = "com.github.topjohnwu.libsu", name = "service", version.ref = "libsu" }
43 | com-github-topjohnwu-libsu-nio = { group = "com.github.topjohnwu.libsu", name = "nio", version.ref = "libsu" }
44 | com-github-topjohnwu-libsu-io = { group = "com.github.topjohnwu.libsu", name = "io", version.ref = "libsu" }
45 |
46 | dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:parcelablelist", version = "2.0.1" }
47 |
48 | io-coil-kt-coil-compose = { group = "io.coil-kt", name = "coil-compose", version = "2.7.0" }
49 |
50 | kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.9.0" }
51 |
52 | me-zhanghai-android-appiconloader-coil = { group = "me.zhanghai.android.appiconloader", name = "appiconloader-coil", version = "1.5.0" }
53 |
54 | compose-destinations-core = { group = "io.github.raamcosta.compose-destinations", name = "core", version.ref = "compose-destination" }
55 | compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destination" }
56 |
57 | sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets-compose-dialogs" }
58 | sheet-compose-dialogs-list = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "list", version.ref = "sheets-compose-dialogs" }
59 | sheet-compose-dialogs-input = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "input", version.ref = "sheets-compose-dialogs" }
60 |
61 | markdown = { group = "io.noties.markwon", name = "core", version = "4.6.2" }
62 |
63 | timber = { group = "com.jakewharton.timber", name = "timber", version = "5.0.1" }
64 | ini4j = { group = "org.ini4j", name = "ini4j", version = "0.5.4" }
65 | bcpkix = { group = "org.bouncycastle", name = "bcpkix-jdk18on", version = "1.79" }
66 |
67 | cxx = { module = "org.lsposed.libcxx:libcxx", version = "27.0.12077973" }
68 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ponces/APatchLite/98f9cb734d936e3f5716252429dcdb6a026851f0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/scripts/update_binary.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | TMPDIR=/dev/tmp
4 | rm -rf $TMPDIR
5 | mkdir -p $TMPDIR 2>/dev/null
6 |
7 | export BBBIN=$TMPDIR/busybox
8 | unzip -o "$3" "busybox" -d $TMPDIR >&2
9 |
10 | for arch in "arm64-v8a" ; do
11 | unzip -o "$3" "lib/$arch/libbusybox.so" -d $TMPDIR >&2
12 | libpath="$TMPDIR/lib/$arch/libbusybox.so"
13 | chmod 755 $libpath
14 | if [ -x $libpath ] && $libpath >/dev/null 2>&1; then
15 | mv -f $libpath $BBBIN
16 | break
17 | fi
18 | done
19 | $BBBIN rm -rf $TMPDIR/lib
20 |
21 | export INSTALLER=$TMPDIR/install
22 | $BBBIN mkdir -p $INSTALLER
23 | $BBBIN unzip -o "$3" "assets/*" "META-INF/com/google/*" "lib/*" "META-INF/com/google/*" -x "lib/*/libbusybox.so" -d $INSTALLER >&2
24 | export ASH_STANDALONE=1
25 | if echo "$3" | $BBBIN grep -q "uninstall"; then
26 | exec $BBBIN sh "$INSTALLER/assets/UninstallAP.sh" "$@"
27 | elif echo "$3" | $BBBIN grep -q "uninstaller"; then
28 | exec $BBBIN sh "$INSTALLER/assets/UninstallAP.sh" "$@"
29 | else
30 | exec $BBBIN sh "$INSTALLER/assets/InstallAP.sh" "$@"
31 | fi
--------------------------------------------------------------------------------
/scripts/update_script.sh:
--------------------------------------------------------------------------------
1 | ######################
2 | # APatch Empty script
3 | # Check update-binary
4 | ######################
5 |
6 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
2 |
3 | pluginManagement {
4 | repositories {
5 | gradlePluginPortal()
6 | google()
7 | mavenCentral()
8 | }
9 | }
10 |
11 | plugins {
12 | id("org.gradle.toolchains.foojay-resolver-convention").version("0.8.0")
13 | }
14 |
15 | dependencyResolutionManagement {
16 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
17 | repositories {
18 | google()
19 | mavenCentral()
20 | maven("https://jitpack.io")
21 | }
22 | }
23 |
24 | rootProject.name = "APatchLite"
25 | include(":app")
26 |
--------------------------------------------------------------------------------
CONFIG_KALLSYMS=y
and CONFIG_KALLSYMS_ALL=y
18 | CONFIG_KALLSYMS=y
and CONFIG_KALLSYMS_ALL=n
: Initial support
21 |