diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000000..d4f07b614a0e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Feature Request
+ url: https://github.com/tiann/KernelSU/issues/1705
+ about: "We do not accept external Feature Requests, see this link for more details."
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
deleted file mode 100644
index f094b0234e5e..000000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: Feature Request
-description: "Suggest an idea for this project"
-title: "[Feature]"
-labels: "feature"
-body:
- - type: markdown
- id: feature-info
- attributes:
- value: "## Feature Infomation"
- - type: textarea
- id: feature-main
- validations:
- required: true
- attributes:
- label: "Is your feature request related to a problem? Please describe."
- description: "A clear and concise description of what the problem is."
- placeholder: "I'm always frustrated when [...]"
- - type: textarea
- id: feature-solution
- validations:
- required: true
- attributes:
- label: "Describe the solution you'd like."
- description: "A clear and concise description of what you want to happen."
- - type: textarea
- id: feature-describe
- validations:
- required: true
- attributes:
- label: "Describe alternatives you've considered."
- description: "A clear and concise description of any alternative solutions or features you've considered."
- - type: textarea
- id: feature-extra
- validations:
- required: false
- attributes:
- label: "Additional context"
- description: "Add any other context or screenshots about the feature request here."
-
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 018b1c009ce3..95e3839ef7ad 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,18 +4,35 @@ updates:
directory: /
schedule:
interval: daily
-
+ groups:
+ actions:
+ patterns:
+ - "*"
- package-ecosystem: cargo
directory: userspace/ksud
schedule:
interval: daily
-
+ allow:
+ - dependency-type: "all"
+ groups:
+ crates:
+ patterns:
+ - "*"
- package-ecosystem: gradle
directory: manager
schedule:
interval: daily
-
+ groups:
+ maven:
+ patterns:
+ - "*"
- package-ecosystem: npm
directory: website
schedule:
interval: daily
+ allow:
+ - dependency-type: "all"
+ groups:
+ npm:
+ patterns:
+ - "*"
diff --git a/.github/workflows/add-device.yml b/.github/workflows/add-device.yml
index 0b3a01a7ab11..c98c2ac4f9b9 100644
--- a/.github/workflows/add-device.yml
+++ b/.github/workflows/add-device.yml
@@ -26,7 +26,7 @@ jobs:
- name: Make pull request
if: steps.handle-add-device.outputs.success == 'true'
id: cpr
- uses: peter-evans/create-pull-request@v6
+ uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
@@ -37,6 +37,7 @@ jobs:
branch: "add-device-${{ github.event.issue.number }}"
labels: add-device
delete-branch: true
+ sign-commits: true
- name: Check outputs
if: ${{ steps.cpr.outputs.pull-request-number }}
run: |
diff --git a/.github/workflows/build-debug-kernel.yml b/.github/workflows/build-debug-kernel.yml
index a0cab91b2238..5ddb4b3d3014 100644
--- a/.github/workflows/build-debug-kernel.yml
+++ b/.github/workflows/build-debug-kernel.yml
@@ -7,9 +7,9 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
- version_name: android12-5.10.209
- tag: android12-5.10-2024-05
- os_patch_level: 2024-05
+ version_name: android12-5.10.218
+ tag: android12-5.10-2024-08
+ os_patch_level: 2024-08
patch_path: "5.10"
debug: true
build-debug-kernel-a13:
@@ -17,11 +17,11 @@ jobs:
matrix:
include:
- version: "5.10"
- sub_level: 209
- os_patch_level: 2024-05
+ sub_level: 218
+ os_patch_level: 2024-08
- version: "5.15"
- sub_level: 148
- os_patch_level: 2024-05
+ sub_level: 151
+ os_patch_level: 2024-08
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
@@ -34,15 +34,29 @@ jobs:
matrix:
include:
- version: "5.15"
- sub_level: 148
- os_patch_level: 2024-05
+ sub_level: 158
+ os_patch_level: 2024-08
- version: "6.1"
- sub_level: 75
- os_patch_level: 2024-05
+ sub_level: 90
+ os_patch_level: 2024-08
uses: ./.github/workflows/gki-kernel.yml
with:
version: android14-${{ matrix.version }}
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
+ debug: true
+ build-debug-kernel-a15:
+ strategy:
+ matrix:
+ include:
+ - version: "6.6"
+ sub_level: 30
+ os_patch_level: 2024-08
+ uses: ./.github/workflows/gki-kernel.yml
+ with:
+ version: android15-${{ matrix.version }}
+ version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
+ tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
+ patch_path: ${{ matrix.version }}
debug: true
\ No newline at end of file
diff --git a/.github/workflows/build-kernel-a12.yml b/.github/workflows/build-kernel-a12.yml
index 89f9c984dc36..5c1411009567 100644
--- a/.github/workflows/build-kernel-a12.yml
+++ b/.github/workflows/build-kernel-a12.yml
@@ -27,6 +27,8 @@ jobs:
os_patch_level: 2024-03
- sub_level: 209
os_patch_level: 2024-05
+ - sub_level: 218
+ os_patch_level: 2024-08
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -63,7 +65,7 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
- BRANCH=main-kernel-build-2023
+ BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
@@ -112,7 +114,7 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
- version_name: android12-5.10.209
- tag: android12-5.10-2024-05
- os_patch_level: 2024-05
+ version_name: android12-5.10.218
+ tag: android12-5.10-2024-08
+ os_patch_level: 2024-08
patch_path: "5.10"
\ No newline at end of file
diff --git a/.github/workflows/build-kernel-a13.yml b/.github/workflows/build-kernel-a13.yml
index 9390b48e7f6f..9c2f335df9b7 100644
--- a/.github/workflows/build-kernel-a13.yml
+++ b/.github/workflows/build-kernel-a13.yml
@@ -33,6 +33,15 @@ jobs:
- version: "5.10"
sub_level: 209
os_patch_level: 2024-05
+ - version: "5.10"
+ sub_level: 210
+ os_patch_level: 2024-06
+ - version: "5.10"
+ sub_level: 214
+ os_patch_level: 2024-07
+ - version: "5.10"
+ sub_level: 218
+ os_patch_level: 2024-08
- version: "5.15"
sub_level: 123
os_patch_level: 2023-11
@@ -45,6 +54,12 @@ jobs:
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
+ - version: "5.15"
+ sub_level: 149
+ os_patch_level: 2024-07
+ - version: "5.15"
+ sub_level: 151
+ os_patch_level: 2024-08
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -81,7 +96,7 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
- BRANCH=main-kernel-build-2023
+ BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
@@ -131,11 +146,11 @@ jobs:
matrix:
include:
- version: "5.10"
- sub_level: 209
- os_patch_level: 2024-05
+ sub_level: 218
+ os_patch_level: 2024-08
- version: "5.15"
- sub_level: 148
- os_patch_level: 2024-05
+ sub_level: 151
+ os_patch_level: 2024-08
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
diff --git a/.github/workflows/build-kernel-a14.yml b/.github/workflows/build-kernel-a14.yml
index a06f02b1f732..4d8a97b8a9ee 100644
--- a/.github/workflows/build-kernel-a14.yml
+++ b/.github/workflows/build-kernel-a14.yml
@@ -33,6 +33,15 @@ jobs:
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
+ - version: "5.15"
+ sub_level: 149
+ os_patch_level: 2024-06
+ - version: "5.15"
+ sub_level: 153
+ os_patch_level: 2024-07
+ - version: "5.15"
+ sub_level: 158
+ os_patch_level: 2024-08
- version: "6.1"
sub_level: 25
os_patch_level: 2023-10
@@ -48,6 +57,15 @@ jobs:
- version: "6.1"
sub_level: 75
os_patch_level: 2024-05
+ - version: "6.1"
+ sub_level: 78
+ os_patch_level: 2024-06
+ - version: "6.1"
+ sub_level: 84
+ os_patch_level: 2024-07
+ - version: "6.1"
+ sub_level: 90
+ os_patch_level: 2024-08
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -84,7 +102,7 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
- BRANCH=main-kernel-build-2023
+ BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
@@ -134,11 +152,11 @@ jobs:
matrix:
include:
- version: "5.15"
- sub_level: 148
- os_patch_level: 2024-05
+ sub_level: 158
+ os_patch_level: 2024-08
- version: "6.1"
- sub_level: 75
- os_patch_level: 2024-05
+ sub_level: 90
+ os_patch_level: 2024-08
uses: ./.github/workflows/gki-kernel.yml
with:
version: android14-${{ matrix.version }}
diff --git a/.github/workflows/build-kernel-a15.yml b/.github/workflows/build-kernel-a15.yml
new file mode 100644
index 000000000000..b59e8b9369fe
--- /dev/null
+++ b/.github/workflows/build-kernel-a15.yml
@@ -0,0 +1,121 @@
+name: Build Kernel - Android 15
+on:
+ push:
+ branches: ["main", "ci", "checkci"]
+ paths:
+ - ".github/workflows/build-kernel-a15.yml"
+ - ".github/workflows/gki-kernel.yml"
+ - ".github/scripts/build_a13.sh"
+ - "kernel/**"
+ pull_request:
+ branches: ["main"]
+ paths:
+ - ".github/workflows/build-kernel-a15.yml"
+ - ".github/workflows/gki-kernel.yml"
+ - ".github/scripts/build-a13.sh"
+ - "kernel/**"
+ workflow_call:
+jobs:
+ build-kernel:
+ if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
+ strategy:
+ matrix:
+ include:
+ - version: "6.6"
+ sub_level: 30
+ os_patch_level: 2024-08
+ uses: ./.github/workflows/gki-kernel.yml
+ secrets: inherit
+ with:
+ version: android15-${{ matrix.version }}
+ version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
+ tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
+ os_patch_level: ${{ matrix.os_patch_level }}
+ patch_path: ${{ matrix.version }}
+
+ upload-artifacts:
+ needs: build-kernel
+ runs-on: ubuntu-latest
+ if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
+ env:
+ CHAT_ID: ${{ secrets.CHAT_ID }}
+ BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
+ MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
+ COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
+ COMMIT_URL: ${{ github.event.head_commit.url }}
+ RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ steps:
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
+
+ - uses: actions/checkout@v4
+ with:
+ path: KernelSU
+ fetch-depth: 0
+
+ - name: List artifacts
+ run: |
+ tree
+
+ - name: Download prebuilt toolchain
+ run: |
+ AOSP_MIRROR=https://android.googlesource.com
+ BRANCH=main-kernel-build-2024
+ git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
+ git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
+ git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
+ pip3 install telethon
+
+ - name: Set boot sign key
+ env:
+ BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
+ run: |
+ if [ ! -z "$BOOT_SIGN_KEY" ]; then
+ echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
+ fi
+
+ - name: Bot session cache
+ id: bot_session_cache
+ uses: actions/cache@v4
+ if: false
+ with:
+ path: scripts/ksubot.session
+ key: ${{ runner.os }}-bot-session
+
+ - name: Build boot images
+ run: |
+ export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
+ export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
+ export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
+ export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
+ export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
+ cd $GITHUB_WORKSPACE/KernelSU
+ export VERSION=$(($(git rev-list --count HEAD) + 10200))
+ echo "VERSION: $VERSION"
+ cd -
+ bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
+
+ - name: Display structure of boot files
+ run: ls -R
+
+ - name: Upload images artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: boot-images-android15
+ path: Image-android15*/*.img.gz
+
+ check-build-kernel:
+ if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
+ strategy:
+ matrix:
+ include:
+ - version: "6.6"
+ sub_level: 30
+ os_patch_level: 2024-08
+ uses: ./.github/workflows/gki-kernel.yml
+ with:
+ version: android15-${{ matrix.version }}
+ version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
+ tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
+ os_patch_level: ${{ matrix.os_patch_level }}
+ patch_path: ${{ matrix.version }}
\ No newline at end of file
diff --git a/.github/workflows/build-kernel-arcvm.yml b/.github/workflows/build-kernel-arcvm.yml
index 18c97c2f949d..9dbe8de1a0f6 100644
--- a/.github/workflows/build-kernel-arcvm.yml
+++ b/.github/workflows/build-kernel-arcvm.yml
@@ -82,7 +82,7 @@ jobs:
SUBLEVEL=$(grep -E '^SUBLEVEL = ' Makefile | awk '{print $3}')
echo "ChromeOS ARCVM Linux kernel version: $VERSION.$PATCHLEVEL.$SUBLEVEL"
echo "version=$VERSION.$PATCHLEVEL.$SUBLEVEL" >> $GITHUB_ENV
-
+
- name: Setup KernelSU
working-directory: kernel
run: |
@@ -94,7 +94,9 @@ jobs:
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
- grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
+ DRIVER_KCONFIG=$KERNEL_ROOT/drivers/Kconfig
+ grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
+ grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch || echo "[-] No patch found"
diff --git a/.github/workflows/build-lkm.yml b/.github/workflows/build-lkm.yml
new file mode 100644
index 000000000000..9e70d39be370
--- /dev/null
+++ b/.github/workflows/build-lkm.yml
@@ -0,0 +1,41 @@
+name: Build LKM for KernelSU
+on:
+ push:
+ branches: ["main", "ci", "checkci"]
+ paths:
+ - ".github/workflows/build-lkm.yml"
+ pull_request:
+ branches: ["main"]
+ paths:
+ - ".github/workflows/build-lkm.yml"
+ workflow_call:
+jobs:
+ build-lkm:
+ strategy:
+ matrix:
+ include:
+ - version: "android12-5.10"
+ sub_level: 218
+ os_patch_level: 2024-08
+ - version: "android13-5.10"
+ sub_level: 218
+ os_patch_level: 2024-08
+ - version: "android13-5.15"
+ sub_level: 151
+ os_patch_level: 2024-08
+ - version: "android14-5.15"
+ sub_level: 158
+ os_patch_level: 2024-08
+ - version: "android14-6.1"
+ sub_level: 90
+ os_patch_level: 2024-08
+ - version: "android15-6.6"
+ sub_level: 30
+ os_patch_level: 2024-08
+ uses: ./.github/workflows/gki-kernel.yml
+ with:
+ version: ${{ matrix.version }}
+ version_name: ${{ matrix.version }}.${{ matrix.sub_level }}
+ tag: ${{ matrix.version }}-${{ matrix.os_patch_level }}
+ os_patch_level: ${{ matrix.os_patch_level }}
+ build_lkm: true
\ No newline at end of file
diff --git a/.github/workflows/build-manager.yml b/.github/workflows/build-manager.yml
index 5014fb6fe014..bc9cbabdd585 100644
--- a/.github/workflows/build-manager.yml
+++ b/.github/workflows/build-manager.yml
@@ -2,7 +2,7 @@ name: Build Manager
on:
push:
- branches: [ "main", "ci" ]
+ branches: [ "main", "ci", "test" ]
paths:
- '.github/workflows/build-manager.yml'
- 'manager/**'
@@ -13,6 +13,7 @@ on:
paths:
- 'manager/**'
workflow_call:
+ workflow_dispatch:
jobs:
build-ksud:
@@ -23,24 +24,18 @@ jobs:
os: ubuntu-latest
- target: x86_64-linux-android
os: ubuntu-latest
- - target: x86_64-pc-windows-gnu # windows pc
- os: ubuntu-latest
- - target: x86_64-apple-darwin # Intel mac
- os: macos-latest
- - target: aarch64-apple-darwin # M chip mac
- os: macos-latest
- - target: aarch64-unknown-linux-musl # arm64 Linux
- os: ubuntu-latest
- target: x86_64-unknown-linux-musl # x86 Linux
os: ubuntu-latest
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
+ pack_lkm: false
build-manager:
needs: build-ksud
runs-on: ubuntu-latest
+ environment: signing
defaults:
run:
working-directory: ./manager
@@ -63,15 +58,12 @@ jobs:
- name: Write key
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
run: |
- if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
{
- echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
- echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
- echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
- echo KEYSTORE_FILE='key.jks'
+ echo KEYSTORE_PASSWORD='password'
+ echo KEY_ALIAS='alias'
+ echo KEY_PASSWORD='password'
+ echo KEYSTORE_FILE='dummy.keystore'
} >> gradle.properties
- echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
- fi
- name: Setup Java
uses: actions/setup-java@v4
@@ -80,9 +72,10 @@ jobs:
java-version: 21
- name: Setup Gradle
- uses: gradle/actions/setup-gradle@v3
- with:
- gradle-home-cache-cleanup: true
+ uses: gradle/actions/setup-gradle@v4
+
+ - name: Setup Android SDK
+ uses: android-actions/setup-android@v3
- name: Download arm64 ksud
uses: actions/download-artifact@v4
diff --git a/.github/workflows/build-su.yml b/.github/workflows/build-su.yml
index 2fbb93a9a485..22fd58af4508 100644
--- a/.github/workflows/build-su.yml
+++ b/.github/workflows/build-su.yml
@@ -26,14 +26,11 @@ jobs:
else
echo "UPLOAD=false" >> $GITHUB_OUTPUT
fi
- - uses: nttld/setup-ndk@v1
- with:
- ndk-version: r26d
- name: Build su
working-directory: ./userspace/su
- run: ndk-build
+ run: $ANDROID_NDK/ndk-build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4
with:
name: su
- path: ./userspace/su/libs
\ No newline at end of file
+ path: ./userspace/su/libs
diff --git a/docs/README.md b/docs/README.md
index 0128cd3d221e..3e99c1e8cd33 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,4 +1,4 @@
-**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_CN.md b/docs/README_CN.md
index dc34b86ab139..17e44e942763 100644
--- a/docs/README_CN.md
+++ b/docs/README_CN.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_ES.md b/docs/README_ES.md
index ed4f699b791d..42a4828fa0fa 100644
--- a/docs/README_ES.md
+++ b/docs/README_ES.md
@@ -1,4 +1,4 @@
-[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_ID.md b/docs/README_ID.md
index 511683a7503d..33bfa733fefb 100644
--- a/docs/README_ID.md
+++ b/docs/README_ID.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_IN.md b/docs/README_IN.md
index 7396ab5c2b10..392a99041613 100644
--- a/docs/README_IN.md
+++ b/docs/README_IN.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | **हिंदी**
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | **हिंदी** | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_IT.md b/docs/README_IT.md
new file mode 100644
index 000000000000..54216b65ff62
--- /dev/null
+++ b/docs/README_IT.md
@@ -0,0 +1,58 @@
+[English](REAME.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | **Italiano**
+
+# KernelSU
+
+
+
+Una soluzione per il root basata sul kernel per i dispositivi Android.
+
+[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
+[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
+[![Canale Telegraml](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
+[![Licenza componenti kernel: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
+[![Licenza elementi non kern](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
+
+## Funzionalità
+
+1. `su` e accesso root basato sul kernel.
+2. Sistema di moduli per la modifica del sistema basato su [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
+3. [App profile](https://kernelsu.org/guide/app-profile.html): Limita i poteri dell'accesso root a permessi specifici.
+
+## Compatibilità
+
+KernelSU supporta ufficialmente i dispositivi Android GKI 2.0 (kernel 5.10 o superiore). I kernel precedenti (kernel 4.14+) sono anche compatibili, ma il kernel deve essere compilato manualmente.
+
+Questo implica che WSA, ChromeOS e tutti le varianti di Android basate su container e virtualizzazione sono supportate.
+
+Allo stato attuale solo le architetture a 64-bit ARM (arm64-v8a) e x86 (x86_64) sono supportate.
+
+## Utilizzo
+
+- [Istruzioni per l'installazione](https://kernelsu.org/guide/installation.html)
+- [Come compilare manualmente?](https://kernelsu.org/guide/how-to-build.html)
+- [Sito web ufficiale](https://kernelsu.org/)
+
+## Traduzioni
+
+Per aiutare a tradurre KernelSU o migliorare le traduzioni esistenti, si è pregati di utilizzare
+To help translate KernelSU or improve existing translations, please use [Weblate](https://hosted.weblate.org/engage/kernelsu/). Le richieste di pull delle traduzioni del manager non saranno più accettate perché sarebbero in conflitto con Weblate.
+
+## Discussione
+
+- Telegram: [@KernelSU](https://t.me/KernelSU)
+
+## Securezza
+
+Per informazioni riguardo la segnalazione di vulnerabilità di sicurezza per KernelSU, leggi [SECURITY.md](/SECURITY.md).
+
+## Licenza
+
+- I file nella cartella `kernel` sono forniti secondo la licenza [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
+- Tutte le altre parti, ad eccezione della certella `kernel`, seguono la licenza [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
+
+## Riconoscimenti e attribuzioni
+
+- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): l'idea alla base di KernelSU.
+- [Magisk](https://github.com/topjohnwu/Magisk): la potente utilità per il root.
+- [genuine](https://github.com/brevent/genuine/): verifica della firma apk v2.
+- [Diamorphine](https://github.com/m0nad/Diamorphine): alcune capacità di rootkit.
diff --git a/docs/README_IW.md b/docs/README_IW.md
index 5997487e2a08..233c3b61ce11 100644
--- a/docs/README_IW.md
+++ b/docs/README_IW.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_JP.md b/docs/README_JP.md
index 093618753775..04ec0cfc3873 100644
--- a/docs/README_JP.md
+++ b/docs/README_JP.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_KR.md b/docs/README_KR.md
index 3226008920a1..ccb8f8ac4dc2 100644
--- a/docs/README_KR.md
+++ b/docs/README_KR.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **한국어** | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **한국어** | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_PL.md b/docs/README_PL.md
index ab9066296dd9..f5cfc8defc7a 100644
--- a/docs/README_PL.md
+++ b/docs/README_PL.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | **Polski** | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | **Polski** | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_PT-BR.md b/docs/README_PT-BR.md
index b5421e7f9be0..c91737c864ae 100644
--- a/docs/README_PT-BR.md
+++ b/docs/README_PT-BR.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_RU.md b/docs/README_RU.md
index 7e50f47adfe5..f3b69643ad17 100644
--- a/docs/README_RU.md
+++ b/docs/README_RU.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_TR.md b/docs/README_TR.md
index bc3363e8b490..223fcadf978a 100644
--- a/docs/README_TR.md
+++ b/docs/README_TR.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/docs/README_TW.md b/docs/README_TW.md
index d025e1742a67..5ff1d613c3bc 100644
--- a/docs/README_TW.md
+++ b/docs/README_TW.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
@@ -36,7 +36,7 @@ WSA和ChromeOS和執行在容器中的 Android 也可以與 KernelSU 一同運
若要協助翻譯 KernelSU 或改進現有翻譯,請使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。 翻譯管理器的PR不再被接受,因為它會與Weblate衝突。
-### 討論
+## 討論
- Telegram:[@KernelSU](https://t.me/KernelSU)
diff --git a/docs/README_VI.md b/docs/README_VI.md
index 7dd3b4227aec..665e242b00ce 100644
--- a/docs/README_VI.md
+++ b/docs/README_VI.md
@@ -1,4 +1,4 @@
-[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
+[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
# KernelSU
diff --git a/js/README.md b/js/README.md
index 4af3a7185863..91de2b45b9c6 100644
--- a/js/README.md
+++ b/js/README.md
@@ -109,3 +109,12 @@ Show a toast message.
import { toast } from 'kernelsu';
toast('Hello, world!');
```
+
+### moduleInfo
+
+Get Module info.
+```javascript
+import { moduleInfo } from 'kernelsu';
+// print moduleId in console
+console.log(moduleInfo());
+```
\ No newline at end of file
diff --git a/js/index.d.ts b/js/index.d.ts
index b65248e378f7..c9278175c891 100644
--- a/js/index.d.ts
+++ b/js/index.d.ts
@@ -37,9 +37,12 @@ declare function fullScreen(isFullScreen: boolean);
declare function toast(message: string);
+declare function moduleInfo(): string;
+
export {
exec,
spawn,
fullScreen,
- toast
+ toast,
+ moduleInfo
}
diff --git a/js/index.js b/js/index.js
index 4b64e9c4c455..29b928acd6f1 100644
--- a/js/index.js
+++ b/js/index.js
@@ -113,3 +113,7 @@ export function fullScreen(isFullScreen) {
export function toast(message) {
ksu.toast(message);
}
+
+export function moduleInfo() {
+ return ksu.moduleInfo();
+}
diff --git a/js/package.json b/js/package.json
index 02b350f33c79..12002a05328e 100644
--- a/js/package.json
+++ b/js/package.json
@@ -1,6 +1,6 @@
{
"name": "kernelsu",
- "version": "1.0.6",
+ "version": "1.0.7",
"description": "Library for KernelSU's module WebUI",
"main": "index.js",
"types": "index.d.ts",
diff --git a/kernel/Makefile b/kernel/Makefile
index 669297563b1d..3c06d5ccca62 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -21,7 +21,7 @@ ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
$(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin [ -f ../.git/shallow ] && git fetch --unshallow)
KSU_GIT_VERSION := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git rev-list --count HEAD)
# ksu_version: major * 10000 + git version + 200 for historical reasons
-$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 200))
+$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 194))
$(info -- KernelSU version: $(KSU_VERSION))
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
else # If there is no .git file, the default version will be passed.
diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c
index ba8b73f2eb2b..f36adf7cf8cd 100644
--- a/kernel/apk_sign.c
+++ b/kernel/apk_sign.c
@@ -316,5 +316,7 @@ module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
bool is_manager_apk(char *path)
{
- return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
-}
\ No newline at end of file
+ return (check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH) // ksu official
+ || check_v2_signature(path, 0x363, "4359c171f32543394cbc23ef908c4bb94cad7c8087002ba164c8230948c21549") // dummy.keystore
+ );
+}
diff --git a/kernel/core_hook.c b/kernel/core_hook.c
index 429ba3306ea3..009216efa454 100644
--- a/kernel/core_hook.c
+++ b/kernel/core_hook.c
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -197,7 +198,7 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
return 0;
}
- if (strcmp(buf, "/system/packages.list")) {
+ if (!strstr(buf, "/system/packages.list")) {
return 0;
}
pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname,
diff --git a/manager/.gitignore b/manager/.gitignore
index dd42da43f547..a595ddf709dd 100644
--- a/manager/.gitignore
+++ b/manager/.gitignore
@@ -1,9 +1,10 @@
*.iml
.gradle
-local.properties
.idea
+.kotlin
.DS_Store
build
captures
.cxx
+local.properties
key.jks
diff --git a/manager/app/build.gradle.kts b/manager/app/build.gradle.kts
index 1c85d8af7e8a..1f98e4a1ba62 100644
--- a/manager/app/build.gradle.kts
+++ b/manager/app/build.gradle.kts
@@ -1,4 +1,7 @@
+@file:Suppress("UnstableApiUsage")
+
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
+import com.android.build.gradle.tasks.PackageAndroidArtifact
plugins {
alias(libs.plugins.agp.app)
@@ -34,6 +37,7 @@ android {
aidl = true
buildConfig = true
compose = true
+ prefab = true
}
kotlinOptions {
@@ -45,7 +49,13 @@ android {
useLegacyPackaging = true
}
resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ // https://stackoverflow.com/a/58956288
+ // It will break Layout Inspector, but it's unused for release build.
+ excludes += "META-INF/*.version"
+ // https://github.com/Kotlin/kotlinx.coroutines?tab=readme-ov-file#avoiding-including-the-debug-infrastructure-in-the-resulting-apk
+ excludes += "DebugProbesKt.bin"
+ // https://issueantenna.com/repo/kotlin/kotlinx.coroutines/issues/3158
+ excludes += "kotlin-tooling-metadata.json"
}
}
@@ -60,13 +70,26 @@ android {
val output = it as BaseVariantOutputImpl
output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk"
}
-
kotlin.sourceSets {
getByName(name) {
kotlin.srcDir("build/generated/ksp/$name/kotlin")
}
}
}
+
+ // https://stackoverflow.com/a/77745844
+ tasks.withType {
+ doFirst { appMetadata.asFile.orNull?.writeText("") }
+ }
+
+ dependenciesInfo {
+ includeInApk = false
+ includeInBundle = false
+ }
+
+ androidResources {
+ generateLocaleConfig = true
+ }
}
dependencies {
@@ -87,12 +110,7 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
- implementation(libs.com.google.accompanist.drawablepainter)
- implementation(libs.com.google.accompanist.navigation.animation)
- implementation(libs.com.google.accompanist.systemuicontroller)
- implementation(libs.com.google.accompanist.webview)
-
- implementation(libs.compose.destinations.animations.core)
+ implementation(libs.compose.destinations.core)
ksp(libs.compose.destinations.ksp)
implementation(libs.com.github.topjohnwu.libsu.core)
@@ -113,4 +131,6 @@ dependencies {
implementation(libs.markdown)
implementation(libs.androidx.webkit)
+
+ implementation(libs.lsposed.cxx)
}
\ No newline at end of file
diff --git a/manager/app/proguard-rules.pro b/manager/app/proguard-rules.pro
index dcaf39ce70fe..e69de29bb2d1 100644
--- a/manager/app/proguard-rules.pro
+++ b/manager/app/proguard-rules.pro
@@ -1,9 +0,0 @@
--dontwarn org.bouncycastle.jsse.BCSSLParameters
--dontwarn org.bouncycastle.jsse.BCSSLSocket
--dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
--dontwarn org.conscrypt.Conscrypt$Version
--dontwarn org.conscrypt.Conscrypt
--dontwarn org.conscrypt.ConscryptHostnameVerifier
--dontwarn org.openjsse.javax.net.ssl.SSLParameters
--dontwarn org.openjsse.javax.net.ssl.SSLSocket
--dontwarn org.openjsse.net.ssl.OpenJSSE
diff --git a/manager/app/src/main/AndroidManifest.xml b/manager/app/src/main/AndroidManifest.xml
index 32c920ab4c3b..11cda5f21cd1 100644
--- a/manager/app/src/main/AndroidManifest.xml
+++ b/manager/app/src/main/AndroidManifest.xml
@@ -12,8 +12,8 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
- android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
+ android:supportsRtl="true"
android:theme="@style/Theme.KernelSU"
tools:targetApi="34">
-
-
-
- = Build.VERSION_CODES.Q) {
+ window.isNavigationBarContrastEnforced = false
+ }
+
super.onCreate(savedInstanceState)
setContent {
KernelSUTheme {
val navController = rememberNavController()
- val snackbarHostState = remember { SnackbarHostState() }
+ val snackBarHostState = remember { SnackbarHostState() }
Scaffold(
bottomBar = { BottomBar(navController) },
- snackbarHost = { SnackbarHost(snackbarHostState) }
+ contentWindowInsets = WindowInsets(0, 0, 0, 0)
) { innerPadding ->
CompositionLocalProvider(
- LocalSnackbarHost provides snackbarHostState,
+ LocalSnackbarHost provides snackBarHostState,
) {
DestinationsNavHost(
modifier = Modifier.padding(innerPadding),
navGraph = NavGraphs.root,
- navController = navController
+ navController = navController,
+ defaultTransitions = object : NavHostAnimatedDestinationStyle() {
+ override val enterTransition: AnimatedContentTransitionScope.() -> EnterTransition
+ get() = { fadeIn(animationSpec = tween(340)) }
+ override val exitTransition: AnimatedContentTransitionScope.() -> ExitTransition
+ get() = { fadeOut(animationSpec = tween(340)) }
+ }
)
}
}
@@ -61,9 +89,15 @@ class MainActivity : ComponentActivity() {
@Composable
private fun BottomBar(navController: NavHostController) {
+ val navigator = navController.rememberDestinationsNavigator()
val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
- NavigationBar(tonalElevation = 8.dp) {
+ NavigationBar(
+ tonalElevation = 8.dp,
+ windowInsets = WindowInsets.systemBars.union(WindowInsets.displayCutout).only(
+ WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
+ )
+ ) {
BottomBarDestination.entries.forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
@@ -71,11 +105,10 @@ private fun BottomBar(navController: NavHostController) {
selected = isCurrentDestOnBackStack,
onClick = {
if (isCurrentDestOnBackStack) {
- navController.popBackStack(destination.direction, false)
+ navigator.popBackStack(destination.direction, false)
}
-
- navController.navigate(destination.direction.route) {
- popUpTo(NavGraphs.root.route) {
+ navigator.navigate(destination.direction) {
+ popUpTo(NavGraphs.root) {
saveState = true
}
launchSingleTop = true
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/AboutCard.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/AboutCard.kt
index 0807d0521dfe..803447391af3 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/AboutCard.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/AboutCard.kt
@@ -1,7 +1,5 @@
package me.weishu.kernelsu.ui.component
-import android.text.method.LinkMovementMethod
-import android.widget.TextView
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -11,24 +9,28 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ElevatedCard
-import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.draw.scale
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.TextLinkStyles
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.fromHtml
+import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Dialog
-import androidx.core.content.res.ResourcesCompat
-import androidx.core.text.HtmlCompat
-import com.google.accompanist.drawablepainter.rememberDrawablePainter
import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.R
@@ -36,9 +38,8 @@ import me.weishu.kernelsu.R
@Composable
fun AboutCard() {
ElevatedCard(
- modifier = Modifier
- .fillMaxWidth(),
- shape = RoundedCornerShape(8.dp),
+ modifier = Modifier.fillMaxWidth(),
+ shape = RoundedCornerShape(8.dp)
) {
Row(
modifier = Modifier
@@ -52,7 +53,9 @@ fun AboutCard() {
@Composable
fun AboutDialog(dismiss: () -> Unit) {
- Dialog(onDismissRequest = { dismiss() }) {
+ Dialog(
+ onDismissRequest = { dismiss() }
+ ) {
AboutCard()
}
}
@@ -60,21 +63,20 @@ fun AboutDialog(dismiss: () -> Unit) {
@Composable
private fun AboutCardContent() {
Column(
- modifier = Modifier
- .fillMaxWidth()
+ modifier = Modifier.fillMaxWidth()
) {
- val drawable = ResourcesCompat.getDrawable(
- LocalContext.current.resources,
- R.mipmap.ic_launcher,
- LocalContext.current.theme
- )
-
Row {
- Image(
- painter = rememberDrawablePainter(drawable),
- contentDescription = "icon",
- modifier = Modifier.size(40.dp)
- )
+ Surface(
+ modifier = Modifier.size(40.dp),
+ color = colorResource(id = R.color.ic_launcher_background),
+ shape = CircleShape
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.ic_launcher_foreground),
+ contentDescription = "icon",
+ modifier = Modifier.scale(1.4f)
+ )
+ }
Spacer(modifier = Modifier.width(12.dp))
@@ -93,31 +95,31 @@ private fun AboutCardContent() {
Spacer(modifier = Modifier.height(8.dp))
- HtmlText(
- html = stringResource(
+ val annotatedString = AnnotatedString.Companion.fromHtml(
+ htmlString = stringResource(
id = R.string.about_source_code,
"GitHub",
"Telegram"
+ ),
+ linkStyles = TextLinkStyles(
+ style = SpanStyle(
+ color = MaterialTheme.colorScheme.primary,
+ textDecoration = TextDecoration.Underline
+ ),
+ pressedStyle = SpanStyle(
+ color = MaterialTheme.colorScheme.primary,
+ background = MaterialTheme.colorScheme.secondaryContainer,
+ textDecoration = TextDecoration.Underline
+ )
+ )
+ )
+ Text(
+ text = annotatedString,
+ style = TextStyle(
+ fontSize = 14.sp
)
)
}
}
}
-}
-
-@Composable
-fun HtmlText(html: String, modifier: Modifier = Modifier) {
- val contentColor = LocalContentColor.current
- AndroidView(
- modifier = modifier,
- factory = { context ->
- TextView(context).also {
- it.movementMethod = LinkMovementMethod.getInstance()
- }
- },
- update = {
- it.text = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT)
- it.setTextColor(contentColor.toArgb())
- }
- )
}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt
index e2c3fa453e0d..27adc3f03ccc 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt
@@ -1,6 +1,7 @@
package me.weishu.kernelsu.ui.component
import android.graphics.text.LineBreaker
+import android.os.Build
import android.os.Parcelable
import android.text.Layout
import android.text.method.LinkMovementMethod
@@ -96,8 +97,8 @@ interface ConfirmDialogHandle : DialogHandle {
}
private abstract class DialogHandleBase(
- protected val visible: MutableState,
- protected val coroutineScope: CoroutineScope
+ val visible: MutableState,
+ val coroutineScope: CoroutineScope
) : DialogHandle {
override val isShown: Boolean
get() = visible.value
@@ -432,7 +433,9 @@ private fun MarkdownContent(content: String) {
TextView(context).apply {
movementMethod = LinkMovementMethod.getInstance()
setSpannableFactory(NoCopySpannableFactory.getInstance())
- breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE
+ }
hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt
index 8195cdddd40b..b388cb49d44a 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt
@@ -5,8 +5,12 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
@@ -19,6 +23,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -48,6 +53,7 @@ fun SearchAppBar(
onBackClick: (() -> Unit)? = null,
onConfirm: (() -> Unit)? = null,
dropdownContent: @Composable (() -> Unit)? = null,
+ scrollBehavior: TopAppBarScrollBehavior? = null
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
@@ -132,10 +138,13 @@ fun SearchAppBar(
dropdownContent()
}
- }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
)
}
+@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun SearchAppBarPreview() {
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SettingsItem.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SettingsItem.kt
index 6db20b163cde..e537175fd2c4 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SettingsItem.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SettingsItem.kt
@@ -1,14 +1,18 @@
package me.weishu.kernelsu.ui.component
-import androidx.compose.foundation.clickable
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.selection.toggleable
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.semantics.Role
@Composable
fun SwitchItem(
@@ -19,10 +23,18 @@ fun SwitchItem(
enabled: Boolean = true,
onCheckedChange: (Boolean) -> Unit
) {
+ val interactionSource = remember { MutableInteractionSource() }
+
ListItem(
- modifier = Modifier.clickable {
- onCheckedChange.invoke(!checked)
- },
+ modifier = Modifier
+ .toggleable(
+ value = checked,
+ interactionSource = interactionSource,
+ role = Role.Switch,
+ enabled = enabled,
+ indication = LocalIndication.current,
+ onValueChange = onCheckedChange
+ ),
headlineContent = {
Text(title)
},
@@ -30,7 +42,12 @@ fun SwitchItem(
{ Icon(icon, title) }
},
trailingContent = {
- Switch(checked = checked, enabled = enabled, onCheckedChange = onCheckedChange)
+ Switch(
+ checked = checked,
+ enabled = enabled,
+ onCheckedChange = onCheckedChange,
+ interactionSource = interactionSource
+ )
},
supportingContent = {
if (summary != null) {
@@ -52,6 +69,6 @@ fun RadioItem(
},
leadingContent = {
RadioButton(selected = selected, onClick = onClick)
- },
+ }
)
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt
index d2cb3f342e51..1a39dcc35ea5 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt
@@ -1,11 +1,10 @@
-@file:OptIn(ExperimentalMaterial3Api::class)
-
package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
@@ -20,12 +19,14 @@ import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -86,7 +87,7 @@ fun RootProfileConfig(
) {
OutlinedTextField(
modifier = Modifier
- .menuAnchor()
+ .menuAnchor(MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_namespace)) },
@@ -184,7 +185,7 @@ fun RootProfileConfig(
}
}
-@OptIn(ExperimentalLayoutApi::class)
+@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
@Composable
fun GroupsPanel(selected: List, closeSelection: (selection: Set) -> Unit) {
val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit ->
@@ -234,14 +235,20 @@ fun GroupsPanel(selected: List, closeSelection: (selection: Set)
)
}
- OutlinedCard(modifier = Modifier
- .fillMaxWidth()
- .padding(16.dp)
- .clickable {
- selectGroupsDialog.show()
- }) {
+ OutlinedCard(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ ) {
- Column(modifier = Modifier.padding(16.dp)) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .clickable {
+ selectGroupsDialog.show()
+ }
+ .padding(16.dp)
+ ) {
Text(stringResource(R.string.profile_groups))
FlowRow {
selected.forEach { group ->
@@ -256,7 +263,7 @@ fun GroupsPanel(selected: List, closeSelection: (selection: Set)
}
}
-@OptIn(ExperimentalLayoutApi::class)
+@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
@Composable
fun CapsPanel(
selected: Collection,
@@ -299,14 +306,20 @@ fun CapsPanel(
)
}
- OutlinedCard(modifier = Modifier
- .fillMaxWidth()
- .padding(16.dp)
- .clickable {
- selectCapabilitiesDialog.show()
- }) {
+ OutlinedCard(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ ) {
- Column(modifier = Modifier.padding(16.dp)) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .clickable {
+ selectCapabilitiesDialog.show()
+ }
+ .padding(16.dp)
+ ) {
Text(stringResource(R.string.profile_capabilities))
FlowRow {
selected.forEach { group ->
@@ -329,10 +342,10 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
mutableStateOf(false)
}
var lastValidUid by remember {
- mutableStateOf(uid)
+ mutableIntStateOf(uid)
}
-
val keyboardController = LocalSoftwareKeyboardController.current
+
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
@@ -365,6 +378,7 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
})
}
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SELinuxPanel(
profile: Natives.Profile,
@@ -452,7 +466,7 @@ private fun SELinuxPanel(
),
label = { Text(text = stringResource(R.string.profile_selinux_context)) },
value = profile.context,
- onValueChange = { },
+ onValueChange = { }
)
})
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt
index d09a23434f85..b60e8ea46495 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt
@@ -12,6 +12,7 @@ import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
+import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -54,7 +55,7 @@ fun TemplateConfig(
) {
OutlinedTextField(
modifier = Modifier
- .menuAnchor()
+ .menuAnchor(MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_template)) },
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt
index ca53388f8ea4..a9976700505a 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt
@@ -7,10 +7,14 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@@ -28,8 +32,11 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -39,6 +46,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
@@ -50,6 +58,9 @@ import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
@@ -58,8 +69,6 @@ import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.profile.AppProfileConfig
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
import me.weishu.kernelsu.ui.component.profile.TemplateConfig
-import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.TemplateEditorScreenDestination
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.forceStopApp
import me.weishu.kernelsu.ui.util.getSepolicy
@@ -73,19 +82,19 @@ import me.weishu.kernelsu.ui.viewmodel.getTemplateInfoById
* @author weishu
* @date 2023/5/16.
*/
-@Destination
+@OptIn(ExperimentalMaterial3Api::class)
+@Destination
@Composable
fun AppProfileScreen(
navigator: DestinationsNavigator,
appInfo: SuperUserViewModel.AppInfo,
) {
val context = LocalContext.current
- val snackbarHost = LocalSnackbarHost.current
+ val snackBarHost = LocalSnackbarHost.current
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
val scope = rememberCoroutineScope()
- val failToUpdateAppProfile =
- stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
- val failToUpdateSepolicy =
- stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
+ val failToUpdateAppProfile = stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
+ val failToUpdateSepolicy = stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
val packageName = appInfo.packageName
val initialProfile = Natives.getAppProfile(packageName, appInfo.uid)
@@ -97,18 +106,25 @@ fun AppProfileScreen(
}
Scaffold(
- topBar = { TopBar { navigator.popBackStack() } },
+ topBar = {
+ TopBar(
+ onBack = { navigator.popBackStack() },
+ scrollBehavior = scrollBehavior
+ )
+ },
+ snackbarHost = { SnackbarHost(hostState = snackBarHost) },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { paddingValues ->
AppProfileInner(
modifier = Modifier
.padding(paddingValues)
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState()),
packageName = appInfo.packageName,
appLabel = appInfo.label,
appIcon = {
AsyncImage(
- model = ImageRequest.Builder(context).data(appInfo.packageInfo).crossfade(true)
- .build(),
+ model = ImageRequest.Builder(context).data(appInfo.packageInfo).crossfade(true).build(),
contentDescription = appInfo.label,
modifier = Modifier
.padding(4.dp)
@@ -129,12 +145,12 @@ fun AppProfileScreen(
scope.launch {
if (it.allowSu && !it.rootUseDefault && it.rules.isNotEmpty()) {
if (!setSepolicy(profile.name, it.rules)) {
- snackbarHost.showSnackbar(failToUpdateSepolicy)
+ snackBarHost.showSnackbar(failToUpdateSepolicy)
return@launch
}
}
if (!Natives.setAppProfile(it)) {
- snackbarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
+ snackBarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
} else {
profile = it
}
@@ -174,7 +190,9 @@ private fun AppProfileInner(
)
Crossfade(targetState = isRootGranted, label = "") { current ->
- Column {
+ Column(
+ modifier = Modifier.padding(bottom = 6.dp + 48.dp + 6.dp /* SnackBar height */)
+ ) {
if (current) {
val initialMode = if (profile.rootUseDefault) {
Mode.Default
@@ -238,7 +256,10 @@ private enum class Mode(@StringRes private val res: Int) {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-private fun TopBar(onBack: () -> Unit) {
+private fun TopBar(
+ onBack: () -> Unit,
+ scrollBehavior: TopAppBarScrollBehavior? = null
+) {
TopAppBar(
title = {
Text(stringResource(R.string.profile))
@@ -248,6 +269,8 @@ private fun TopBar(onBack: () -> Unit) {
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
},
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
)
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt
index 9345ced52ff0..c9637ed2e979 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt
@@ -5,11 +5,11 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.*
import androidx.compose.ui.graphics.vector.ImageVector
+import com.ramcosta.composedestinations.generated.destinations.HomeScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.SuperUserScreenDestination
import com.ramcosta.composedestinations.spec.DirectionDestinationSpec
import me.weishu.kernelsu.R
-import me.weishu.kernelsu.ui.screen.destinations.HomeScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.SuperUserScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.ModuleScreenDestination
enum class BottomBarDestination(
val direction: DirectionDestinationSpec,
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/ExecuteModuleAction.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/ExecuteModuleAction.kt
new file mode 100644
index 000000000000..69480997d73f
--- /dev/null
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/ExecuteModuleAction.kt
@@ -0,0 +1,143 @@
+package me.weishu.kernelsu.ui.screen
+
+import android.os.Environment
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.filled.Save
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SnackbarHost
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.unit.dp
+import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.navigation.DestinationsNavigator
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import me.weishu.kernelsu.R
+import me.weishu.kernelsu.ui.component.KeyEventBlocker
+import me.weishu.kernelsu.ui.util.LocalSnackbarHost
+import me.weishu.kernelsu.ui.util.runModuleAction
+import java.io.File
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+@Composable
+@Destination
+fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String) {
+ var text by rememberSaveable { mutableStateOf("") }
+ val logContent = rememberSaveable { StringBuilder() }
+ val snackBarHost = LocalSnackbarHost.current
+ val scope = rememberCoroutineScope()
+ val scrollState = rememberScrollState()
+ var actionResult: Boolean
+
+ LaunchedEffect(Unit) {
+ if (text.isNotEmpty()) {
+ return@LaunchedEffect
+ }
+ withContext(Dispatchers.IO) {
+ runModuleAction(
+ moduleId = moduleId,
+ onStdout = {
+ text += "$it\n"
+ logContent.append(it).append("\n")
+ },
+ onStderr = {
+ logContent.append(it).append("\n")
+ }
+ ).let {
+ actionResult = it
+ }
+ }
+ if (actionResult) navigator.popBackStack()
+ }
+
+ Scaffold(
+ topBar = {
+ TopBar(
+ onBack = {
+ navigator.popBackStack()
+ },
+ onSave = {
+ scope.launch {
+ val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
+ val date = format.format(Date())
+ val file = File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
+ "KernelSU_module_action_log_${date}.log"
+ )
+ file.writeText(logContent.toString())
+ snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
+ }
+ }
+ )
+ },
+ snackbarHost = { SnackbarHost(snackBarHost) }
+ ) { innerPadding ->
+ KeyEventBlocker {
+ it.key == Key.VolumeDown || it.key == Key.VolumeUp
+ }
+ Column(
+ modifier = Modifier
+ .fillMaxSize(1f)
+ .padding(innerPadding)
+ .verticalScroll(scrollState),
+ ) {
+ LaunchedEffect(text) {
+ scrollState.animateScrollTo(scrollState.maxValue)
+ }
+ Text(
+ modifier = Modifier.padding(8.dp),
+ text = text,
+ fontSize = MaterialTheme.typography.bodySmall.fontSize,
+ fontFamily = FontFamily.Monospace,
+ lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
+ )
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
+ TopAppBar(
+ title = { Text(stringResource(R.string.action)) },
+ navigationIcon = {
+ IconButton(
+ onClick = onBack
+ ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
+ },
+ actions = {
+ IconButton(onClick = onSave) {
+ Icon(
+ imageVector = Icons.Filled.Save,
+ contentDescription = stringResource(id = R.string.save_log),
+ )
+ }
+ }
+ )
+}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt
index 1e3d48fdae05..a60767d045b2 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt
@@ -4,8 +4,12 @@ import android.net.Uri
import android.os.Environment
import android.os.Parcelable
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
@@ -18,8 +22,12 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -30,11 +38,13 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
@@ -65,8 +75,9 @@ enum class FlashingStatus {
* @author weishu
* @date 2023/1/1.
*/
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
-@Destination
+@Destination
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
var text by rememberSaveable { mutableStateOf("") }
@@ -76,6 +87,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val scrollState = rememberScrollState()
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
var flashing by rememberSaveable {
mutableStateOf(FlashingStatus.FLASHING)
}
@@ -121,7 +133,8 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
file.writeText(logContent.toString())
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
}
- }
+ },
+ scrollBehavior = scrollBehavior
)
},
floatingActionButton = {
@@ -139,8 +152,9 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
text = { Text(text = reboot) },
)
}
-
- }
+ },
+ snackbarHost = { SnackbarHost(hostState = snackBarHost) },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
KeyEventBlocker {
it.key == Key.VolumeDown || it.key == Key.VolumeUp
@@ -149,6 +163,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
modifier = Modifier
.fillMaxSize(1f)
.padding(innerPadding)
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(scrollState),
) {
LaunchedEffect(text) {
@@ -202,7 +217,12 @@ fun flashIt(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-private fun TopBar(status: FlashingStatus, onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
+private fun TopBar(
+ status: FlashingStatus,
+ onBack: () -> Unit = {},
+ onSave: () -> Unit = {},
+ scrollBehavior: TopAppBarScrollBehavior? = null
+) {
TopAppBar(
title = {
Text(
@@ -227,7 +247,9 @@ private fun TopBar(status: FlashingStatus, onBack: () -> Unit = {}, onSave: () -
contentDescription = "Localized description"
)
}
- }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
)
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt
index 6ecf53a8974e..15389fe37a45 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt
@@ -22,42 +22,54 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import androidx.core.content.pm.PackageInfoCompat
import com.ramcosta.composedestinations.annotation.Destination
-import com.ramcosta.composedestinations.annotation.RootNavGraph
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.SettingScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.*
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
-import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.SettingScreenDestination
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.util.module.LatestVersionInfo
-@RootNavGraph(start = true)
-@Destination
+@OptIn(ExperimentalMaterial3Api::class)
+@Destination(start = true)
@Composable
fun HomeScreen(navigator: DestinationsNavigator) {
val kernelVersion = getKernelVersion()
-
- Scaffold(topBar = {
- TopBar(kernelVersion, onSettingsClick = {
- navigator.navigate(SettingScreenDestination)
- }, onInstallClick = {
- navigator.navigate(InstallScreenDestination)
- })
- }) { innerPadding ->
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
+
+ Scaffold(
+ topBar = {
+ TopBar(
+ kernelVersion,
+ onSettingsClick = {
+ navigator.navigate(SettingScreenDestination)
+ },
+ onInstallClick = {
+ navigator.navigate(InstallScreenDestination)
+ },
+ scrollBehavior = scrollBehavior
+ )
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ ) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
- .padding(horizontal = 16.dp)
- .verticalScroll(rememberScrollState()),
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
+ .verticalScroll(rememberScrollState())
+ .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
val isManager = Natives.becomeManager(ksuApp.packageName)
@@ -84,12 +96,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
stringResource(id = R.string.grant_root_failed)
)
}
- val checkUpdate =
- LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE)
- .getBoolean("check_update", true)
- if (checkUpdate) {
- UpdateCard()
- }
+ Unofficial()
InfoCard()
DonateCard()
LearnMoreCard()
@@ -103,12 +110,11 @@ fun UpdateCard() {
val context = LocalContext.current
val latestVersionInfo = LatestVersionInfo()
val newVersion by produceState(initialValue = latestVersionInfo) {
- value = withContext(Dispatchers.IO){
+ value = withContext(Dispatchers.IO) {
checkNewVersion()
}
}
-
val currentVersionCode = getManagerVersion(context).second
val newVersionCode = newVersion.versionCode
val newVersionUrl = newVersion.downloadUrl
@@ -156,52 +162,58 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
private fun TopBar(
kernelVersion: KernelVersion,
onInstallClick: () -> Unit,
- onSettingsClick: () -> Unit
+ onSettingsClick: () -> Unit,
+ scrollBehavior: TopAppBarScrollBehavior? = null
) {
- TopAppBar(title = { Text(stringResource(R.string.app_name)) }, actions = {
- if (kernelVersion.isGKI()) {
- IconButton(onClick = onInstallClick) {
- Icon(
- imageVector = Icons.Filled.Archive,
- contentDescription = stringResource(id = R.string.install)
- )
+ TopAppBar(
+ title = { Text(stringResource(R.string.app_name)) },
+ actions = {
+ if (kernelVersion.isGKI()) {
+ IconButton(onClick = onInstallClick) {
+ Icon(
+ imageVector = Icons.Filled.Archive,
+ contentDescription = stringResource(id = R.string.install)
+ )
+ }
}
- }
-
- var showDropdown by remember { mutableStateOf(false) }
- IconButton(onClick = {
- showDropdown = true
- }) {
- Icon(
- imageVector = Icons.Filled.Refresh,
- contentDescription = stringResource(id = R.string.reboot)
- )
- DropdownMenu(expanded = showDropdown, onDismissRequest = {
- showDropdown = false
+ var showDropdown by remember { mutableStateOf(false) }
+ IconButton(onClick = {
+ showDropdown = true
}) {
+ Icon(
+ imageVector = Icons.Filled.Refresh,
+ contentDescription = stringResource(id = R.string.reboot)
+ )
+
+ DropdownMenu(expanded = showDropdown, onDismissRequest = {
+ showDropdown = false
+ }) {
- RebootDropdownItem(id = R.string.reboot)
+ RebootDropdownItem(id = R.string.reboot)
- val pm =
- LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) {
- RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace")
+ val pm = LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
+ @Suppress("DEPRECATION")
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) {
+ RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace")
+ }
+ RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery")
+ RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader")
+ RebootDropdownItem(id = R.string.reboot_download, reason = "download")
+ RebootDropdownItem(id = R.string.reboot_edl, reason = "edl")
}
- RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery")
- RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader")
- RebootDropdownItem(id = R.string.reboot_download, reason = "download")
- RebootDropdownItem(id = R.string.reboot_edl, reason = "edl")
}
- }
- IconButton(onClick = onSettingsClick) {
- Icon(
- imageVector = Icons.Filled.Settings,
- contentDescription = stringResource(id = R.string.settings)
- )
- }
- })
+ IconButton(onClick = onSettingsClick) {
+ Icon(
+ imageVector = Icons.Filled.Settings,
+ contentDescription = stringResource(id = R.string.settings)
+ )
+ }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
+ )
}
@Composable
@@ -415,9 +427,38 @@ private fun InfoCard() {
}
}
-fun getManagerVersion(context: Context): Pair {
- val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
- return Pair(packageInfo.versionName, packageInfo.versionCode)
+@Composable
+fun Unofficial() {
+ val uriHandler = LocalUriHandler.current
+ val url = stringResource(R.string.home_unofficial_kernelsu_announce)
+
+ ElevatedCard {
+
+ Row(modifier = Modifier
+ .fillMaxWidth()
+ .clickable {
+ uriHandler.openUri(url)
+ }
+ .padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
+ Column {
+ Text(
+ text = stringResource(R.string.home_unofficial_kernelsu),
+ style = MaterialTheme.typography.titleSmall
+ )
+ Spacer(Modifier.height(4.dp))
+ Text(
+ text = stringResource(R.string.home_unofficial_kernelsu_body),
+ style = MaterialTheme.typography.bodyMedium
+ )
+ }
+ }
+ }
+}
+
+fun getManagerVersion(context: Context): Pair {
+ val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)!!
+ val versionCode = PackageInfoCompat.getLongVersionCode(packageInfo)
+ return Pair(packageInfo.versionName!!, versionCode)
}
@Preview
@@ -441,4 +482,4 @@ private fun WarningCardPreview() {
MaterialTheme.colorScheme.outlineVariant,
onClick = {})
}
-}
\ No newline at end of file
+}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt
index 71b5c9756909..01f7ce3012d9 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt
@@ -6,11 +6,19 @@ import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
-import androidx.compose.foundation.clickable
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.selection.toggleable
+import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.FileUpload
@@ -23,6 +31,9 @@ import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -31,7 +42,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.maxkeppeker.sheets.core.models.base.Header
@@ -40,13 +53,14 @@ import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.DialogHandle
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
-import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.LkmSelection
import me.weishu.kernelsu.ui.util.getCurrentKmi
import me.weishu.kernelsu.ui.util.getSupportedKmis
@@ -58,7 +72,8 @@ import me.weishu.kernelsu.ui.util.rootAvailable
* @author weishu
* @date 2024/3/12.
*/
-@Destination
+@OptIn(ExperimentalMaterial3Api::class)
+@Destination
@Composable
fun InstallScreen(navigator: DestinationsNavigator) {
var installMethod by remember {
@@ -113,12 +128,24 @@ fun InstallScreen(navigator: DestinationsNavigator) {
})
}
- Scaffold(topBar = {
- TopBar(
- onBack = { navigator.popBackStack() }, onLkmUpload = onLkmUpload
- )
- }) {
- Column(modifier = Modifier.padding(it)) {
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
+
+ Scaffold(
+ topBar = {
+ TopBar(
+ onBack = { navigator.popBackStack() },
+ onLkmUpload = onLkmUpload,
+ scrollBehavior = scrollBehavior
+ )
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ ) { innerPadding ->
+ Column(
+ modifier = Modifier
+ .padding(innerPadding)
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
+ .verticalScroll(rememberScrollState())
+ ) {
SelectInstallMethod { method ->
installMethod = method
}
@@ -231,16 +258,31 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
Column {
radioOptions.forEach { option ->
- Row(verticalAlignment = Alignment.CenterVertically,
+ val interactionSource = remember { MutableInteractionSource() }
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
- .clickable {
+ .toggleable(
+ value = option.javaClass == selectedOption?.javaClass,
+ onValueChange = {
+ onClick(option)
+ },
+ role = Role.RadioButton,
+ indication = LocalIndication.current,
+ interactionSource = interactionSource
+ )
+ ) {
+ RadioButton(
+ selected = option.javaClass == selectedOption?.javaClass,
+ onClick = {
onClick(option)
- }) {
- RadioButton(selected = option.javaClass == selectedOption?.javaClass, onClick = {
- onClick(option)
- })
- Column {
+ },
+ interactionSource = interactionSource
+ )
+ Column(
+ modifier = Modifier.padding(vertical = 12.dp)
+ ) {
Text(
text = stringResource(id = option.label),
fontSize = MaterialTheme.typography.titleMedium.fontSize,
@@ -292,16 +334,24 @@ fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-private fun TopBar(onBack: () -> Unit = {}, onLkmUpload: () -> Unit = {}) {
- TopAppBar(title = { Text(stringResource(R.string.install)) }, navigationIcon = {
- IconButton(
- onClick = onBack
- ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
- }, actions = {
- IconButton(onClick = onLkmUpload) {
- Icon(Icons.Filled.FileUpload, contentDescription = null)
- }
- })
+private fun TopBar(
+ onBack: () -> Unit = {},
+ onLkmUpload: () -> Unit = {},
+ scrollBehavior: TopAppBarScrollBehavior? = null
+) {
+ TopAppBar(
+ title = { Text(stringResource(R.string.install)) }, navigationIcon = {
+ IconButton(
+ onClick = onBack
+ ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
+ }, actions = {
+ IconButton(onClick = onLkmUpload) {
+ Icon(Icons.Filled.FileUpload, contentDescription = null)
+ }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
+ )
}
@Composable
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt
index 9812e87ebba6..75bedce17fb7 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt
@@ -1,47 +1,58 @@
package me.weishu.kernelsu.ui.screen
import android.app.Activity.RESULT_OK
+import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.clickable
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.outlined.Wysiwyg
import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.pullrefresh.PullRefreshIndicator
-import androidx.compose.material.pullrefresh.pullRefresh
-import androidx.compose.material.pullrefresh.rememberPullRefreshState
+import androidx.compose.material.icons.outlined.PlayArrow
import androidx.compose.material3.Button
-import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
+import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SnackbarDuration
+import androidx.compose.material3.SnackbarHost
+import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.pulltorefresh.PullToRefreshBox
+import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -53,8 +64,10 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
@@ -64,7 +77,11 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
+import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -73,7 +90,6 @@ import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
-import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.DownloadListener
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.download
@@ -85,11 +101,13 @@ import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
import me.weishu.kernelsu.ui.webui.WebUIActivity
import okhttp3.OkHttpClient
-@Destination
+@OptIn(ExperimentalMaterial3Api::class)
+@Destination
@Composable
fun ModuleScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel()
val context = LocalContext.current
+ val snackBarHost = LocalSnackbarHost.current
LaunchedEffect(Unit) {
if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) {
@@ -102,42 +120,54 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val hideInstallButton = isSafeMode || hasMagisk
- Scaffold(topBar = {
- TopBar()
- }, floatingActionButton = if (hideInstallButton) {
- { /* Empty */ }
- } else {
- {
- val moduleInstall = stringResource(id = R.string.module_install)
- val selectZipLauncher = rememberLauncherForActivityResult(
- contract = ActivityResultContracts.StartActivityForResult()
- ) {
- if (it.resultCode != RESULT_OK) {
- return@rememberLauncherForActivityResult
- }
- val data = it.data ?: return@rememberLauncherForActivityResult
- val uri = data.data ?: return@rememberLauncherForActivityResult
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
- navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri)))
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ scrollBehavior = scrollBehavior,
+ title = { Text(stringResource(R.string.module)) },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ )
+ },
+ floatingActionButton = {
+ if (hideInstallButton) {
+ /* Empty */
+ } else {
+ val moduleInstall = stringResource(id = R.string.module_install)
+ val selectZipLauncher = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.StartActivityForResult()
+ ) {
+ if (it.resultCode != RESULT_OK) {
+ return@rememberLauncherForActivityResult
+ }
+ val data = it.data ?: return@rememberLauncherForActivityResult
+ val uri = data.data ?: return@rememberLauncherForActivityResult
- viewModel.markNeedRefresh()
+ navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri)))
- Log.i("ModuleScreen", "select zip result: ${it.data}")
- }
+ viewModel.markNeedRefresh()
- ExtendedFloatingActionButton(
- onClick = {
- // select the zip file to install
- val intent = Intent(Intent.ACTION_GET_CONTENT)
- intent.type = "application/zip"
- selectZipLauncher.launch(intent)
- },
- icon = { Icon(Icons.Filled.Add, moduleInstall) },
- text = { Text(text = moduleInstall) },
- )
- }
- }) { innerPadding ->
+ Log.i("ModuleScreen", "select zip result: ${it.data}")
+ }
+ ExtendedFloatingActionButton(
+ onClick = {
+ // select the zip file to install
+ val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
+ type = "application/zip"
+ }
+ selectZipLauncher.launch(intent)
+ },
+ icon = { Icon(Icons.Filled.Add, moduleInstall) },
+ text = { Text(text = moduleInstall) },
+ )
+
+ }
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ snackbarHost = { SnackbarHost(hostState = snackBarHost) }
+ ) { innerPadding ->
when {
hasMagisk -> {
Box(
@@ -155,53 +185,59 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
else -> {
ModuleList(
- viewModel = viewModel, modifier = Modifier
- .padding(innerPadding)
- .fillMaxSize(),
- onInstallModule =
- {
+ navigator,
+ viewModel = viewModel,
+ modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+ boxModifier = Modifier.padding(innerPadding),
+ onInstallModule = {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it)))
- }, onClickModule = { id, name, hasWebUi ->
+ },
+ onClickModule = { id, name, hasWebUi ->
if (hasWebUi) {
- context.startActivity(Intent(context, WebUIActivity::class.java)
- .setData(Uri.parse("kernelsu://webui/$id"))
- .putExtra("id", id)
- .putExtra("name", name)
+ context.startActivity(
+ Intent(context, WebUIActivity::class.java)
+ .setData(Uri.parse("kernelsu://webui/$id"))
+ .putExtra("id", id)
+ .putExtra("name", name)
)
}
- })
+ },
+ context = context,
+ snackBarHost = snackBarHost
+ )
}
}
}
}
-@OptIn(ExperimentalMaterialApi::class)
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ModuleList(
+ navigator: DestinationsNavigator,
viewModel: ModuleViewModel,
modifier: Modifier = Modifier,
+ boxModifier: Modifier = Modifier,
onInstallModule: (Uri) -> Unit,
- onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit
+ onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit,
+ context: Context,
+ snackBarHost: SnackbarHostState
) {
val failedEnable = stringResource(R.string.module_failed_to_enable)
val failedDisable = stringResource(R.string.module_failed_to_disable)
val failedUninstall = stringResource(R.string.module_uninstall_failed)
val successUninstall = stringResource(R.string.module_uninstall_success)
- val reboot = stringResource(id = R.string.reboot)
- val rebootToApply = stringResource(id = R.string.reboot_to_apply)
- val moduleStr = stringResource(id = R.string.module)
- val uninstall = stringResource(id = R.string.uninstall)
- val cancel = stringResource(id = android.R.string.cancel)
- val moduleUninstallConfirm = stringResource(id = R.string.module_uninstall_confirm)
+ val reboot = stringResource(R.string.reboot)
+ val rebootToApply = stringResource(R.string.reboot_to_apply)
+ val moduleStr = stringResource(R.string.module)
+ val uninstall = stringResource(R.string.uninstall)
+ val cancel = stringResource(android.R.string.cancel)
+ val moduleUninstallConfirm = stringResource(R.string.module_uninstall_confirm)
val updateText = stringResource(R.string.module_update)
val changelogText = stringResource(R.string.module_changelog)
val downloadingText = stringResource(R.string.module_downloading)
val startDownloadingText = stringResource(R.string.module_start_downloading)
val fetchChangeLogFailed = stringResource(R.string.module_changelog_failed)
- val snackBarHost = LocalSnackbarHost.current
- val context = LocalContext.current
-
val loadingDialog = rememberLoadingDialog()
val confirmDialog = rememberConfirmDialog()
@@ -300,26 +336,31 @@ private fun ModuleList(
} else {
null
}
- val result = snackBarHost.showSnackbar(message, actionLabel = actionLabel)
+ val result = snackBarHost.showSnackbar(
+ message = message,
+ actionLabel = actionLabel,
+ duration = SnackbarDuration.Long
+ )
if (result == SnackbarResult.ActionPerformed) {
reboot()
}
}
-
- val refreshState = rememberPullRefreshState(refreshing = viewModel.isRefreshing,
- onRefresh = { viewModel.fetchModuleList() })
- Box(modifier.pullRefresh(refreshState)) {
- val context = LocalContext.current
-
+ PullToRefreshBox(
+ modifier = boxModifier,
+ onRefresh = {
+ viewModel.fetchModuleList()
+ },
+ isRefreshing = viewModel.isRefreshing
+ ) {
LazyColumn(
- modifier = Modifier.fillMaxSize(),
+ modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = remember {
PaddingValues(
start = 16.dp,
top = 16.dp,
end = 16.dp,
- bottom = 16.dp + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */
+ bottom = 16.dp + 56.dp + 16.dp + 48.dp + 6.dp /* Scaffold Fab Spacing + Fab container height + SnackBar height */
)
},
) {
@@ -362,42 +403,53 @@ private fun ModuleList(
}
}
- ModuleItem(module, isChecked, updatedModule.first, onUninstall = {
- scope.launch { onModuleUninstall(module) }
- }, onCheckChanged = {
- scope.launch {
- val success = loadingDialog.withLoading {
- withContext(Dispatchers.IO) {
- toggleModule(module.id, !isChecked)
+ ModuleItem(
+ navigator = navigator,
+ module = module,
+ isChecked = isChecked,
+ updateUrl = updatedModule.first,
+ onUninstall = {
+ scope.launch { onModuleUninstall(module) }
+ },
+ onCheckChanged = {
+ scope.launch {
+ val success = loadingDialog.withLoading {
+ withContext(Dispatchers.IO) {
+ toggleModule(module.id, !isChecked)
+ }
+ }
+ if (success) {
+ isChecked = it
+ viewModel.fetchModuleList()
+
+ val result = snackBarHost.showSnackbar(
+ message = rebootToApply,
+ actionLabel = reboot,
+ duration = SnackbarDuration.Long
+ )
+ if (result == SnackbarResult.ActionPerformed) {
+ reboot()
+ }
+ } else {
+ val message = if (isChecked) failedDisable else failedEnable
+ snackBarHost.showSnackbar(message.format(module.name))
}
}
- if (success) {
- isChecked = it
- viewModel.fetchModuleList()
-
- val result = snackBarHost.showSnackbar(
- rebootToApply, actionLabel = reboot
+ },
+ onUpdate = {
+ scope.launch {
+ onModuleUpdate(
+ module,
+ updatedModule.third,
+ updatedModule.first,
+ "${module.name}-${updatedModule.second}.zip"
)
- if (result == SnackbarResult.ActionPerformed) {
- reboot()
- }
- } else {
- val message = if (isChecked) failedDisable else failedEnable
- snackBarHost.showSnackbar(message.format(module.name))
}
+ },
+ onClick = {
+ onClickModule(it.id, it.name, it.hasWebUi)
}
- }, onUpdate = {
- scope.launch {
- onModuleUpdate(
- module,
- updatedModule.third,
- updatedModule.first,
- "${module.name}-${updatedModule.second}.zip"
- )
- }
- }, onClick = {
- onClickModule(it.id, it.name, it.hasWebUi)
- })
+ )
// fix last item shadow incomplete in LazyColumn
Spacer(Modifier.height(1.dp))
@@ -408,22 +460,12 @@ private fun ModuleList(
DownloadListener(context, onInstallModule)
- PullRefreshIndicator(
- refreshing = viewModel.isRefreshing, state = refreshState, modifier = Modifier.align(
- Alignment.TopCenter
- )
- )
}
}
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-private fun TopBar() {
- TopAppBar(title = { Text(stringResource(R.string.module)) })
-}
-
@Composable
-private fun ModuleItem(
+fun ModuleItem(
+ navigator: DestinationsNavigator,
module: ModuleViewModel.ModuleInfo,
isChecked: Boolean,
updateUrl: String,
@@ -433,13 +475,36 @@ private fun ModuleItem(
onClick: (ModuleViewModel.ModuleInfo) -> Unit
) {
ElevatedCard(
- modifier = Modifier.fillMaxWidth(),
- colors = CardDefaults.elevatedCardColors(containerColor = MaterialTheme.colorScheme.surface)
+ modifier = Modifier.fillMaxWidth()
) {
-
val textDecoration = if (!module.remove) null else TextDecoration.LineThrough
-
- Column(modifier = Modifier.clickable { onClick(module) }.padding(24.dp, 16.dp, 24.dp, 0.dp)) {
+ val interactionSource = remember { MutableInteractionSource() }
+ val indication = LocalIndication.current
+
+ Column(
+ modifier = Modifier
+ .run {
+ if (module.hasWebUi) {
+ toggleable(
+ value = isChecked,
+ interactionSource = interactionSource,
+ role = Role.Button,
+ indication = indication,
+ onValueChange = { onClick(module) }
+ )
+ } else {
+ toggleable(
+ value = isChecked,
+ interactionSource = interactionSource,
+ role = Role.Switch,
+ indication = indication,
+ onValueChange = onCheckChanged,
+ enabled = !module.update
+ )
+ }
+ }
+ .padding(22.dp, 18.dp, 22.dp, 12.dp)
+ ) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
@@ -447,7 +512,9 @@ private fun ModuleItem(
val moduleVersion = stringResource(id = R.string.module_version)
val moduleAuthor = stringResource(id = R.string.module_author)
- Column(modifier = Modifier.fillMaxWidth(0.8f)) {
+ Column(
+ modifier = Modifier.fillMaxWidth(0.8f)
+ ) {
Text(
text = module.name,
fontSize = MaterialTheme.typography.titleMedium.fontSize,
@@ -483,7 +550,8 @@ private fun ModuleItem(
Switch(
enabled = !module.update,
checked = isChecked,
- onCheckedChange = onCheckChanged
+ onCheckedChange = onCheckChanged,
+ interactionSource = if (!module.hasWebUi) interactionSource else null
)
}
}
@@ -501,56 +569,95 @@ private fun ModuleItem(
textDecoration = textDecoration
)
-
Spacer(modifier = Modifier.height(16.dp))
HorizontalDivider(thickness = Dp.Hairline)
+ Spacer(modifier = Modifier.height(4.dp))
+
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
+
+ if (module.hasActionScript) {
+ FilledTonalButton(
+ modifier = Modifier.defaultMinSize(52.dp, 32.dp),
+ onClick = { navigator.navigate(ExecuteModuleActionScreenDestination(module.id)) },
+ contentPadding = ButtonDefaults.TextButtonContentPadding
+ ) {
+ Icon(
+ modifier = Modifier
+ .padding(end = 7.dp)
+ .size(20.dp),
+ imageVector = Icons.Outlined.PlayArrow,
+ contentDescription = null
+ )
+ Text(
+ text = stringResource(R.string.action),
+ fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
+ fontSize = MaterialTheme.typography.labelMedium.fontSize
+ )
+ }
+
+ Spacer(modifier = Modifier.weight(0.1f, true))
+ }
+
+ if (module.hasWebUi) {
+ FilledTonalButton(
+ modifier = Modifier.defaultMinSize(52.dp, 32.dp),
+ onClick = { onClick(module) },
+ interactionSource = interactionSource,
+ contentPadding = ButtonDefaults.TextButtonContentPadding
+ ) {
+ if (!module.hasActionScript) {
+ Icon(
+ modifier = Modifier
+ .padding(end = 7.dp)
+ .size(20.dp),
+ imageVector = Icons.AutoMirrored.Outlined.Wysiwyg,
+ contentDescription = null
+ )
+ }
+ Text(
+ fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
+ fontSize = MaterialTheme.typography.labelMedium.fontSize,
+ text = stringResource(R.string.open)
+ )
+ }
+ }
+
Spacer(modifier = Modifier.weight(1f, true))
if (updateUrl.isNotEmpty()) {
Button(
- modifier = Modifier
- .padding(0.dp)
- .defaultMinSize(52.dp, 32.dp),
+ modifier = Modifier.defaultMinSize(52.dp, 32.dp),
onClick = { onUpdate(module) },
- shape = RoundedCornerShape(6.dp),
- contentPadding = PaddingValues(0.dp)
+ shape = ButtonDefaults.textShape,
+ contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Text(
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
- text = stringResource(R.string.module_update),
+ text = stringResource(R.string.module_update)
)
}
+
+ Spacer(modifier = Modifier.weight(0.1f, true))
}
- TextButton(
+ FilledTonalButton(
+ modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove,
onClick = { onUninstall(module) },
+ contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Text(
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
- text = stringResource(R.string.uninstall),
+ text = stringResource(R.string.uninstall)
)
}
-
- if (module.hasWebUi) {
- TextButton(
- onClick = { onClick(module) },
- ) {
- Text(
- fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
- fontSize = MaterialTheme.typography.labelMedium.fontSize,
- text = stringResource(R.string.open),
- )
- }
- }
}
}
}
@@ -568,9 +675,10 @@ fun ModuleItemPreview() {
description = "I am a test module and i do nothing but show a very long description",
enabled = true,
update = true,
- remove = true,
+ remove = false,
updateJson = "",
hasWebUi = false,
+ hasActionScript = false
)
- ModuleItem(module, true, "", {}, {}, {}, {})
+ ModuleItem(EmptyDestinationsNavigator, module, true, "", {}, {}, {}, {})
}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
index 4f970f7ee331..eb02aafc37cc 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
@@ -1,18 +1,18 @@
package me.weishu.kernelsu.ui.screen
-import android.content.ContentResolver
import android.content.Context
import android.content.Intent
-import android.database.Cursor
import android.net.Uri
-import android.provider.OpenableColumns
-import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
@@ -29,7 +29,6 @@ import androidx.compose.material.icons.filled.RemoveModerator
import androidx.compose.material.icons.filled.Save
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Update
-import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -38,6 +37,9 @@ import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -48,6 +50,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.LineHeightStyle
@@ -62,6 +65,9 @@ import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
@@ -77,28 +83,30 @@ import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
-import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.getBugreportFile
import me.weishu.kernelsu.ui.util.getFileNameFromUri
import me.weishu.kernelsu.ui.util.shrinkModules
-import java.time.LocalDateTime
-import java.time.format.DateTimeFormatter
/**
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
-@Destination
+@Destination
@Composable
fun SettingScreen(navigator: DestinationsNavigator) {
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
+
Scaffold(
topBar = {
- TopBar(onBack = {
- navigator.popBackStack()
- })
- }
+ TopBar(
+ onBack = {
+ navigator.popBackStack()
+ },
+ scrollBehavior = scrollBehavior
+ )
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { paddingValues ->
val aboutDialog = rememberCustomDialog {
AboutDialog(it)
@@ -109,6 +117,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
Column(
modifier = Modifier
.padding(paddingValues)
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
) {
@@ -140,21 +149,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
- var checkUpdate by rememberSaveable {
- mutableStateOf(
- prefs.getBoolean("check_update", true)
- )
- }
- SwitchItem(
- icon = Icons.Filled.Update,
- title = stringResource(id = R.string.settings_check_update),
- summary = stringResource(id = R.string.settings_check_update_summary),
- checked = checkUpdate
- ) {
- prefs.edit().putBoolean("check_update", it).apply()
- checkUpdate = it
- }
-
var enableWebDebugging by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_web_debugging", false)
@@ -184,17 +178,20 @@ fun SettingScreen(navigator: DestinationsNavigator) {
showBottomsheet = true
}
)
- if (showBottomsheet){
+ if (showBottomsheet) {
ModalBottomSheet(
onDismissRequest = { showBottomsheet = false },
content = {
- Row(modifier = Modifier.padding(10.dp)
- .align(Alignment.CenterHorizontally)
+ Row(
+ modifier = Modifier
+ .padding(10.dp)
+ .align(Alignment.CenterHorizontally)
) {
- Box{
+ Box {
Column(
- modifier = Modifier.padding(16.dp)
+ modifier = Modifier
+ .padding(16.dp)
.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
@@ -209,14 +206,15 @@ fun SettingScreen(navigator: DestinationsNavigator) {
"${BuildConfig.APPLICATION_ID}.fileprovider",
bugreport
)
- val filename = getFileNameFromUri(context , uri)
- val savefile = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
- addCategory(Intent.CATEGORY_OPENABLE)
- type = "application/zip"
- putExtra(Intent.EXTRA_STREAM, uri)
- putExtra(Intent.EXTRA_TITLE, filename)
- flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- }
+ val filename = getFileNameFromUri(context, uri)
+ val savefile =
+ Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "application/zip"
+ putExtra(Intent.EXTRA_STREAM, uri)
+ putExtra(Intent.EXTRA_TITLE, filename)
+ flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ }
context.startActivity(
Intent.createChooser(
savefile,
@@ -245,9 +243,10 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
- Box{
+ Box {
Column(
- modifier = Modifier.padding(16.dp)
+ modifier = Modifier
+ .padding(16.dp)
.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
@@ -350,6 +349,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
}
+
@Composable
fun UninstallItem(
navigator: DestinationsNavigator,
@@ -374,11 +374,9 @@ fun UninstallItem(
UninstallType.PERMANENT -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashUninstall)
)
-
UninstallType.RESTORE_STOCK_IMAGE -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashRestore)
)
-
UninstallType.NONE -> Unit
}
}
@@ -456,14 +454,21 @@ fun rememberUninstallDialog(onSelected: (UninstallType) -> Unit): DialogHandle {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-private fun TopBar(onBack: () -> Unit = {}) {
+private fun TopBar(
+ onBack: () -> Unit = {},
+ scrollBehavior: TopAppBarScrollBehavior? = null
+) {
TopAppBar(
title = { Text(stringResource(R.string.settings)) },
navigationIcon = {
IconButton(
onClick = onBack
- ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
+ ) {
+ Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
+ }
},
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
)
}
@@ -471,4 +476,4 @@ private fun TopBar(onBack: () -> Unit = {}) {
@Composable
private fun SettingsPreview() {
SettingScreen(EmptyDestinationsNavigator)
-}
\ No newline at end of file
+}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt
index 2eb2e770bb9d..1a37d0110318 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt
@@ -9,14 +9,12 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
-import androidx.compose.material.pullrefresh.PullRefreshIndicator
-import androidx.compose.material.pullrefresh.pullRefresh
-import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.*
+import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.runtime.*
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
@@ -26,20 +24,22 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.AppProfileScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.SearchAppBar
-import me.weishu.kernelsu.ui.screen.destinations.AppProfileScreenDestination
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
-@OptIn(ExperimentalMaterialApi::class)
-@Destination
+@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
+@Destination
@Composable
fun SuperUserScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel()
val scope = rememberCoroutineScope()
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
LaunchedEffect(Unit) {
if (viewModel.appList.isEmpty()) {
@@ -91,32 +91,29 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
}
}
},
+ scrollBehavior = scrollBehavior
)
- }
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
- val refreshState = rememberPullRefreshState(
- refreshing = viewModel.isRefreshing,
- onRefresh = { scope.launch { viewModel.fetchAppList() } },
- )
- Box(
- modifier = Modifier
- .padding(innerPadding)
- .pullRefresh(refreshState)
+ PullToRefreshBox(
+ modifier = Modifier.padding(innerPadding),
+ onRefresh = {
+ scope.launch { viewModel.fetchAppList() }
+ },
+ isRefreshing = viewModel.isRefreshing
) {
- LazyColumn(Modifier.fillMaxSize()) {
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
+ ) {
items(viewModel.appList, key = { it.packageName + it.uid }) { app ->
AppItem(app) {
navigator.navigate(AppProfileScreenDestination(app))
}
-
}
}
-
- PullRefreshIndicator(
- refreshing = viewModel.isRefreshing,
- state = refreshState,
- modifier = Modifier.align(Alignment.TopCenter)
- )
}
}
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt
index bf353b0afa84..3074f4e19e0c 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt
@@ -2,13 +2,16 @@ package me.weishu.kernelsu.ui.screen
import android.widget.Toast
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi
@@ -17,9 +20,6 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ImportExport
import androidx.compose.material.icons.filled.Sync
-import androidx.compose.material.pullrefresh.PullRefreshIndicator
-import androidx.compose.material.pullrefresh.pullRefresh
-import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -31,6 +31,10 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.material3.pulltorefresh.PullToRefreshBox
+import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -38,8 +42,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@@ -47,13 +51,14 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import com.ramcosta.composedestinations.result.getOr
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.weishu.kernelsu.R
-import me.weishu.kernelsu.ui.screen.destinations.TemplateEditorScreenDestination
import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel
/**
@@ -61,8 +66,8 @@ import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel
* @date 2023/10/20.
*/
-@OptIn(ExperimentalMaterialApi::class)
-@Destination
+@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
+@Destination
@Composable
fun AppProfileTemplateScreen(
navigator: DestinationsNavigator,
@@ -70,6 +75,7 @@ fun AppProfileTemplateScreen(
) {
val viewModel = viewModel()
val scope = rememberCoroutineScope()
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
LaunchedEffect(Unit) {
if (viewModel.templateList.isEmpty()) {
@@ -93,7 +99,8 @@ fun AppProfileTemplateScreen(
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
}
}
- TopBar(onBack = { navigator.popBackStack() },
+ TopBar(
+ onBack = { navigator.popBackStack() },
onSync = {
scope.launch { viewModel.fetchTemplates(true) }
},
@@ -124,7 +131,8 @@ fun AppProfileTemplateScreen(
clipboardManager.setText(AnnotatedString(it))
}
}
- }
+ },
+ scrollBehavior = scrollBehavior
)
},
floatingActionButton = {
@@ -141,29 +149,27 @@ fun AppProfileTemplateScreen(
text = { Text(stringResource(id = R.string.app_profile_template_create)) },
)
},
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
- val refreshState = rememberPullRefreshState(
- refreshing = viewModel.isRefreshing,
- onRefresh = { scope.launch { viewModel.fetchTemplates() } },
- )
- Box(
- modifier = Modifier
- .padding(innerPadding)
- .pullRefresh(refreshState)
+ PullToRefreshBox(
+ modifier = Modifier.padding(innerPadding),
+ isRefreshing = viewModel.isRefreshing,
+ onRefresh = {
+ scope.launch { viewModel.fetchTemplates() }
+ }
) {
- LazyColumn(Modifier.fillMaxSize(), contentPadding = remember {
- PaddingValues(bottom = 16.dp + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */)
- }) {
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(scrollBehavior.nestedScrollConnection),
+ contentPadding = remember {
+ PaddingValues(bottom = 16.dp + 56.dp + 16.dp /* Scaffold Fab Spacing + Fab container height */)
+ }
+ ) {
items(viewModel.templateList, key = { it.id }) { app ->
TemplateItem(navigator, app)
}
}
-
- PullRefreshIndicator(
- refreshing = viewModel.isRefreshing,
- state = refreshState,
- modifier = Modifier.align(Alignment.TopCenter)
- )
}
}
}
@@ -209,7 +215,8 @@ private fun TopBar(
onBack: () -> Unit,
onSync: () -> Unit = {},
onImport: () -> Unit = {},
- onExport: () -> Unit = {}
+ onExport: () -> Unit = {},
+ scrollBehavior: TopAppBarScrollBehavior? = null
) {
TopAppBar(
title = {
@@ -254,6 +261,8 @@ private fun TopBar(
})
}
}
- }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
)
}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt
index b6b7cc8028ec..030320ba329a 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt
@@ -3,8 +3,12 @@ package me.weishu.kernelsu.ui.screen
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@@ -22,6 +26,9 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -30,6 +37,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
@@ -37,6 +45,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.result.ResultBackNavigator
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
@@ -51,8 +60,8 @@ import me.weishu.kernelsu.ui.viewmodel.toJSON
* @author weishu
* @date 2023/10/20.
*/
-@OptIn(ExperimentalComposeUiApi::class)
-@Destination
+@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
+@Destination
@Composable
fun TemplateEditorScreen(
navigator: ResultBackNavigator,
@@ -67,6 +76,8 @@ fun TemplateEditorScreen(
mutableStateOf(initialTemplate)
}
+ val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
+
BackHandler {
navigator.navigateBack(result = !readOnly)
}
@@ -106,12 +117,16 @@ fun TemplateEditorScreen(
} else {
Toast.makeText(context, saveTemplateFailed, Toast.LENGTH_SHORT).show()
}
- })
+ },
+ scrollBehavior = scrollBehavior
+ )
},
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
.pointerInteropFilter {
// disable click and ripple if readOnly
@@ -240,39 +255,44 @@ private fun TopBar(
summary: String = "",
onBack: () -> Unit,
onDelete: () -> Unit = {},
- onSave: () -> Unit = {}
+ onSave: () -> Unit = {},
+ scrollBehavior: TopAppBarScrollBehavior? = null
) {
- TopAppBar(title = {
- Column {
- Text(title)
- if (summary.isNotBlank()) {
- Text(
- text = summary,
- style = MaterialTheme.typography.bodyMedium,
+ TopAppBar(
+ title = {
+ Column {
+ Text(title)
+ if (summary.isNotBlank()) {
+ Text(
+ text = summary,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+ }
+ }, navigationIcon = {
+ IconButton(
+ onClick = onBack
+ ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
+ }, actions = {
+ if (readOnly) {
+ return@TopAppBar
+ }
+ IconButton(onClick = onDelete) {
+ Icon(
+ Icons.Filled.DeleteForever,
+ contentDescription = stringResource(id = R.string.app_profile_template_delete)
)
}
- }
- }, navigationIcon = {
- IconButton(
- onClick = onBack
- ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
- }, actions = {
- if (readOnly) {
- return@TopAppBar
- }
- IconButton(onClick = onDelete) {
- Icon(
- Icons.Filled.DeleteForever,
- contentDescription = stringResource(id = R.string.app_profile_template_delete)
- )
- }
- IconButton(onClick = onSave) {
- Icon(
- imageVector = Icons.Filled.Save,
- contentDescription = stringResource(id = R.string.app_profile_template_save)
- )
- }
- })
+ IconButton(onClick = onSave) {
+ Icon(
+ imageVector = Icons.Filled.Save,
+ contentDescription = stringResource(id = R.string.app_profile_template_save)
+ )
+ }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+ scrollBehavior = scrollBehavior
+ )
}
@Composable
@@ -289,17 +309,14 @@ private fun TextEdit(
value = text,
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
- suffix =
- if (errorHint.isNotBlank()) {
- {
+ suffix = {
+ if (errorHint.isNotBlank()) {
Text(
text = if (isError) errorHint else "",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error
)
}
- } else {
- null
},
isError = isError,
keyboardOptions = KeyboardOptions(
@@ -314,7 +331,7 @@ private fun TextEdit(
}
private fun isValidTemplateId(id: String): Boolean {
- return Regex("""^([A-Za-z]{1}[A-Za-z\d_]*\.)*[A-Za-z][A-Za-z\d_]*$""").matches(id)
+ return Regex("""^([A-Za-z][A-Za-z\d_]*\.)*[A-Za-z][A-Za-z\d_]*$""").matches(id)
}
private fun isTemplateExist(id: String): Boolean {
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt
index 3b3945d0cdc5..903ee94e0b54 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt
@@ -7,12 +7,8 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
-import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.SideEffect
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.unit.dp
-import com.google.accompanist.systemuicontroller.rememberSystemUiController
private val DarkColorScheme = darkColorScheme(
primary = YELLOW,
@@ -42,20 +38,6 @@ fun KernelSUTheme(
else -> LightColorScheme
}
- val systemUiController = rememberSystemUiController()
- SideEffect {
- systemUiController.setStatusBarColor(
- color = colorScheme.surface,
- darkIcons = !darkTheme
- )
-
- // To match the App Navbar color
- systemUiController.setNavigationBarColor(
- color = colorScheme.surfaceColorAtElevation(8.dp),
- darkIcons = !darkTheme,
- )
- }
-
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt
index 954cac50da30..5d85bc63d5fe 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt
@@ -63,7 +63,8 @@ fun download(
}
fun checkNewVersion(): LatestVersionInfo {
- val url = "https://api.github.com/repos/tiann/KernelSU/releases/latest"
+ // disable updates
+ val url = "https://127.0.0.1/repos/tiann/KernelSU/releases/latest"
// default null value if failed
val defaultValue = LatestVersionInfo()
runCatching {
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
index 108e08f2a139..32a94b7e1768 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
@@ -4,16 +4,15 @@ import android.content.ContentResolver
import android.content.Context
import android.database.Cursor
import android.net.Uri
-import android.os.Build
import android.os.Environment
import android.os.Parcelable
import android.os.SystemClock
import android.provider.OpenableColumns
+import android.system.Os
import android.util.Log
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
-import com.topjohnwu.superuser.io.SuFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
@@ -189,6 +188,30 @@ fun flashModule(
}
}
+fun runModuleAction(
+ moduleId: String, onStdout: (String) -> Unit, onStderr: (String) -> Unit
+): Boolean {
+ val shell = getRootShell()
+
+ val stdoutCallback: CallbackList = object : CallbackList() {
+ override fun onAddElement(s: String?) {
+ onStdout(s ?: "")
+ }
+ }
+
+ val stderrCallback: CallbackList = object : CallbackList() {
+ override fun onAddElement(s: String?) {
+ onStderr(s ?: "")
+ }
+ }
+
+ val result = shell.newJob().add("${getKsuDaemonPath()} module action $moduleId")
+ .to(stdoutCallback, stderrCallback).exec()
+ Log.i("KernelSU", "Module runAction result: $result")
+
+ return result.isSuccess
+}
+
fun restoreBoot(
onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean {
@@ -312,18 +335,7 @@ fun isAbDevice(): Boolean {
}
fun isInitBoot(): Boolean {
- val shell = getRootShell()
- if (shell.isRoot) {
- // if we have root, use /dev/block/by-name/init_boot to check
- val abDevice = isAbDevice()
- val initBootBlock = "/dev/block/by-name/init_boot${if (abDevice) "_a" else ""}"
- val file = SuFile(initBootBlock)
- file.shell = shell
- return file.exists()
- }
- // https://source.android.com/docs/core/architecture/partitions/generic-boot
- return ShellUtils.fastCmd(shell, "getprop ro.product.first_api_level").trim()
- .toInt() >= Build.VERSION_CODES.TIRAMISU
+ return !Os.uname().release.contains("android12-")
}
suspend fun getCurrentKmi(): String = withContext(Dispatchers.IO) {
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
index 19eb1df18991..a8363120c0fb 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
@@ -1,16 +1,12 @@
package me.weishu.kernelsu.ui.util
-import android.content.ContentResolver
import android.content.Context
-import android.net.Uri
import android.os.Build
-import android.os.ParcelFileDescriptor
import android.system.Os
import com.topjohnwu.superuser.ShellUtils
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ui.screen.getManagerVersion
import java.io.File
-import java.io.FileOutputStream
import java.io.FileWriter
import java.io.PrintWriter
import java.time.LocalDateTime
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
index 78346dd9412c..6b0d704ece67 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
@@ -1,7 +1,7 @@
package me.weishu.kernelsu.ui.util
-import androidx.compose.ui.res.stringResource
import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
import com.topjohnwu.superuser.Shell
import me.weishu.kernelsu.R
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt
index 013453fbfeed..4533e6e5ffc4 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt
@@ -36,6 +36,7 @@ class ModuleViewModel : ViewModel() {
val remove: Boolean,
val updateJson: String,
val hasWebUi: Boolean,
+ val hasActionScript: Boolean,
)
data class ModuleUpdateInfo(
@@ -87,7 +88,6 @@ class ModuleViewModel : ViewModel() {
.map { obj ->
ModuleInfo(
obj.getString("id"),
-
obj.optString("name"),
obj.optString("author", "Unknown"),
obj.optString("version", "Unknown"),
@@ -97,7 +97,8 @@ class ModuleViewModel : ViewModel() {
obj.getBoolean("update"),
obj.getBoolean("remove"),
obj.optString("updateJson"),
- obj.optBoolean("web")
+ obj.optBoolean("web"),
+ obj.optBoolean("action")
)
}.toList()
isNeedRefresh = false
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt
index 37e05aa82aff..ecb5024aaed0 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt
@@ -45,7 +45,7 @@ class SuperUserViewModel : ViewModel() {
val packageName: String
get() = packageInfo.packageName
val uid: Int
- get() = packageInfo.applicationInfo.uid
+ get() = packageInfo.applicationInfo!!.uid
val allowSu: Boolean
get() = profile != null && profile.allowSu
@@ -90,7 +90,7 @@ class SuperUserViewModel : ViewModel() {
.toPinyinString(it.label).contains(search, true)
}.filter {
it.uid == 2000 // Always show shell
- || showSystemApps || it.packageInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0
+ || showSystemApps || it.packageInfo.applicationInfo!!.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0
}
}
@@ -146,7 +146,7 @@ class SuperUserViewModel : ViewModel() {
apps = packages.map {
val appInfo = it.applicationInfo
- val uid = appInfo.uid
+ val uid = appInfo!!.uid
val profile = Natives.getAppProfile(it.packageName, uid)
AppInfo(
label = appInfo.loadLabel(pm).toString(),
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
index eccb002a1688..d926d7eada35 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
@@ -2,13 +2,18 @@ package me.weishu.kernelsu.ui.webui
import android.annotation.SuppressLint
import android.app.ActivityManager
-import android.content.Context
+import android.os.Build
import android.os.Bundle
+import android.view.ViewGroup.MarginLayoutParams
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.ComponentActivity
+import androidx.activity.enableEdgeToEdge
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updateLayoutParams
import androidx.webkit.WebViewAssetLoader
import com.topjohnwu.superuser.Shell
import me.weishu.kernelsu.ui.util.createRootShell
@@ -21,15 +26,30 @@ class WebUIActivity : ComponentActivity() {
private var rootShell: Shell? = null
override fun onCreate(savedInstanceState: Bundle?) {
+
+ // Enable edge to edge
+ enableEdgeToEdge()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ window.isNavigationBarContrastEnforced = false
+ }
+
super.onCreate(savedInstanceState)
+
val moduleId = intent.getStringExtra("id")!!
val name = intent.getStringExtra("name")!!
- setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+ @Suppress("DEPRECATION")
+ setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
+ } else {
+ val taskDescription = ActivityManager.TaskDescription.Builder().setLabel("KernelSU - $name").build()
+ setTaskDescription(taskDescription)
+ }
- val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
+ val prefs = getSharedPreferences("settings", MODE_PRIVATE)
WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", false))
- val webRoot = File("/data/adb/modules/${moduleId}/webroot")
+ val moduleDir = "/data/adb/modules/${moduleId}"
+ val webRoot = File("${moduleDir}/webroot")
val rootShell = createRootShell(true).also { this.rootShell = it }
val webViewAssetLoader = WebViewAssetLoader.Builder()
.setDomain("mui.kernelsu.org")
@@ -49,10 +69,20 @@ class WebUIActivity : ComponentActivity() {
}
val webView = WebView(this).apply {
+ ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
+ val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
+ view.updateLayoutParams {
+ leftMargin = inset.left
+ rightMargin = inset.right
+ topMargin = inset.top
+ bottomMargin = inset.bottom
+ }
+ return@setOnApplyWindowInsetsListener insets
+ }
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = false
- webviewInterface = WebViewInterface(this@WebUIActivity, this)
+ webviewInterface = WebViewInterface(this@WebUIActivity, this, moduleDir)
addJavascriptInterface(webviewInterface, "ksu")
setWebViewClient(webViewClient)
loadUrl("https://mui.kernelsu.org/index.html")
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
index 4b6a3c8f755d..00fcde653b60 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
@@ -9,18 +9,24 @@ import android.view.Window
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.Toast
-import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.ShellUtils
+import com.topjohnwu.superuser.internal.UiThreadHandler
import me.weishu.kernelsu.ui.util.createRootShell
+import me.weishu.kernelsu.ui.util.listModules
import me.weishu.kernelsu.ui.util.withNewRootShell
import org.json.JSONArray
import org.json.JSONObject
+import java.io.File
import java.util.concurrent.CompletableFuture
-class WebViewInterface(val context: Context, private val webView: WebView) {
+class WebViewInterface(
+ val context: Context,
+ private val webView: WebView,
+ private val modDir: String
+) {
@JavascriptInterface
fun exec(cmd: String): String {
@@ -108,13 +114,13 @@ class WebViewInterface(val context: Context, private val webView: WebView) {
}
}
- val stdout = object : CallbackList() {
+ val stdout = object : CallbackList(UiThreadHandler::runAndWait) {
override fun onAddElement(s: String) {
emitData("stdout", s)
}
}
- val stderr = object : CallbackList() {
+ val stderr = object : CallbackList(UiThreadHandler::runAndWait) {
override fun onAddElement(s: String) {
emitData("stderr", s)
}
@@ -170,21 +176,34 @@ class WebViewInterface(val context: Context, private val webView: WebView) {
}
}
+ @JavascriptInterface
+ fun moduleInfo(): String {
+ val moduleInfos = JSONArray(listModules())
+ var currentModuleInfo = JSONObject()
+ currentModuleInfo.put("moduleDir", modDir)
+ val moduleId = File(modDir).getName()
+ for (i in 0 until moduleInfos.length()) {
+ val currentInfo = moduleInfos.getJSONObject(i)
+
+ if (currentInfo.getString("id") != moduleId) {
+ continue
+ }
+
+ var keys = currentInfo.keys()
+ for (key in keys) {
+ currentModuleInfo.put(key, currentInfo.get(key))
+ }
+ break
+ }
+ return currentModuleInfo.toString()
+ }
}
-fun hideSystemUI(window: Window) {
- WindowCompat.setDecorFitsSystemWindows(window, false)
+fun hideSystemUI(window: Window) =
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
- controller.systemBarsBehavior =
- WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
-}
-fun showSystemUI(window: Window) {
- WindowCompat.setDecorFitsSystemWindows(window, true)
- WindowInsetsControllerCompat(
- window,
- window.decorView
- ).show(WindowInsetsCompat.Type.systemBars())
-}
\ No newline at end of file
+fun showSystemUI(window: Window) =
+ WindowInsetsControllerCompat(window, window.decorView).show(WindowInsetsCompat.Type.systemBars())
diff --git a/manager/app/src/main/res/drawable/ic_launcher_background.xml b/manager/app/src/main/res/drawable/ic_launcher_background.xml
deleted file mode 100644
index 900e2d8c829e..000000000000
--- a/manager/app/src/main/res/drawable/ic_launcher_background.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml
index b070c763da32..f30783b21028 100644
--- a/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml
+++ b/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/manager/app/src/main/res/resources.properties b/manager/app/src/main/res/resources.properties
new file mode 100644
index 000000000000..d5a3ddc92a9b
--- /dev/null
+++ b/manager/app/src/main/res/resources.properties
@@ -0,0 +1 @@
+unqualifiedResLocale=en-US
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ar/strings.xml b/manager/app/src/main/res/values-ar/strings.xml
index c38c4fc89464..36d1b26f2a9f 100644
--- a/manager/app/src/main/res/values-ar/strings.xml
+++ b/manager/app/src/main/res/values-ar/strings.xml
@@ -38,14 +38,14 @@
فشل إلغاء التثبيت: %s
الإصدار
المطور
- التراكبات غير متوفرة ، لا يمكن للإضافة أن تعمل!
+ الوحدات غير متوفرة حيث يتم تعطيل نظام الملفات المتراكب بواسطة النواة.
إنعاش
إظهار تطبيقات النظام
إخفاء تطبيقات النظام
إرسال السجلات
الوضع الآمن
إعادة التشغيل لتطبيق التغييرات
- تم تعطيل الإضافات لأنها تتعارض مع Magisk!
+ الوحدات غير متاحة بسبب تعارضها مع Magisk!
تعلم KernelSU
https://kernelsu.org/guide/what-is-kernelsu.html
تعرف على كيفية تثبيت KernelSU واستخدام الإضافات
@@ -56,7 +56,7 @@
تحديث
تحميل الإضافة: %s
ابدأ التنزيل: %s
- الإصدار الجديد: %s متاح ، انقر للتحديث
+ الإصدار الجديد: %s متاح ، انقر للتحديث.
تشغيل
الإفتراضي
نموذج
@@ -118,17 +118,18 @@
اختر KMI
يوصى باستخدام صورة القسم %1$s
تصغير الصورة المتفرقة
- قم بتغيير حجم الصورة المتفرقة حيث توجد الإضافة إلى حجمها الفعلي. لاحظ أن هذا قد يتسبب في عمل الإضافة بشكل غير طبيعي، لذا يرجى استخدامها فقط عند الضرورة (مثل النسخ الاحتياطي)
+ قم بتغيير حجم الصورة المتفرقة حيث توجد الإضافة إلى حجمها الفعلي. لاحظ أن هذا قد يتسبب في عمل الإضافة بشكل غير طبيعي، لذا يرجى استخدامها فقط عند الضرورة (مثل النسخ الاحتياطي).
إلغاء التثبيت
إلغاء التثبيت مؤقتًا
إلغاء التثبيت بشكل دائم
استعادة الصورة الاصلية
- إلغاء تثبيت KernelSU (الجذر وجميع الوحدات) بشكل كامل ودائم.
+ إلغاء تثبيت KernelSU .(الجذر وجميع الوحدات) بشكل كامل ودائم.
تركيب
نجح التركيب
فشل التركيب
- صورة lkm المحددة: %s
+ LKM المحددة: %s
استعادة صورة المصنع المخزنة (في حالة وجود نسخة احتياطية)، والتي تُستخدم عادة قبل OTA؛ إذا كنت بحاجة إلى إلغاء تثبيت KernelSU، فيرجى استخدام \"إلغاء التثبيت الدائم\".
قم بإلغاء تثبيت KernelSU مؤقتًا، واستعد إلى حالته الأصلية بعد إعادة التشغيل التالية.
حفظ السجلات
+ إجراء
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-de/strings.xml b/manager/app/src/main/res/values-de/strings.xml
index 047123467301..721dba59e8b5 100644
--- a/manager/app/src/main/res/values-de/strings.xml
+++ b/manager/app/src/main/res/values-de/strings.xml
@@ -5,117 +5,130 @@
Permissiv
Funktioniert
Version: %d
- SuperUser
- Tippen zum Installieren
+ Superuser
+ Tippe zum Installieren
Superuser: %d
Unbekannt
Erzwingen
- Neustart in Bootloader
- Neustart in Download-Modus
- Neustart mit EDL-Modus
+ In den Bootloader-Modus neustarten
+ In den Download-Modus neustarten
+ In den EDL-Modus neustarten
Autor
- overlayfs nicht verfügbar, Modul kann nicht funktionieren!
- Über
- Module sind deaktiviert, weil es einen Konflikt mit Magisk gibt!
+ Module sind nicht verfügbar, da OverlayFS vom Kernel deaktiviert ist.
+ Über KernelSU
+ Module sind aufgrund eines Konfliktes mit Magisk nicht verfügbar!
https://kernelsu.org/guide/what-is-kernelsu.html
- Erfahren, wie KernelSU installiert und Module verwendet werden
+ Erfahre, wie KernelSU installiert wird und wie Module verwendet werden
Unterstütze uns
KernelSU ist und wird immer frei und quelloffen sein. Du kannst uns jedoch deine Unterstützung zeigen, indem du eine Spende tätigst.
SELinux-Kontext
Module standardmäßig aushängen
- Globaler Standardwert für \'Module aushängen\' in App-Profilen. Falls aktiviert, werden alle Moduländerungen im System für alle Apps entfernt, für die kein Profil festgelegt ist.
+ Globaler Standardwert für \"Module aushängen\" im App-Profil. Falls er aktiviert ist, werden alle Moduländerungen im System für alle Apps entfernt, für die kein Profil festgelegt ist.
Standard
Vorlage
Benutzerdefiniert
App-Profilaktualisierung für %s fehlgeschlagen
- Vererbt
+ Geerbt
Global
Individuell
Domäne
Aktualisieren
Wenn du diese Option aktivierst, kann KernelSU alle von den Modulen für diese App geänderten Dateien wiederherstellen.
Regeln
- Herunterladen startet: %s
- Fehler beim Aktualisieren der SELinux-Regeln für: %s
+ Starte Download: %s
+ Aktualisieren der SELinux-Regeln schlug fehl für: %s
Starten
- Neue Version: %s verfügbar, tippen zum Aktualisieren
+ Neue Version %s verfügbar, tippen zum Aktualisieren.
Stopp erzwingen
- Neustart
+ Neustarten
Module: %d
Manager-Version
- SELinux-Status
+ SELinux Status
Deaktiviert
Modulaktivierung fehlgeschlagen: %s
Moduldeaktivierung fehlgeschlagen: %s
- Keine Module installiert
+ Keine Modul installiert
Modul
Deinstallieren
Installieren
Neustarten
Einstellungen
- Neustart in Recovery
+ In den Recovery-Modus neustarten
%s deinstalliert
Version
- Neu laden
+ Aktualisieren
System-Apps anzeigen
System-Apps ausblenden
Protokoll senden
KernelSU verstehen
Sicherer Modus
Neustarten, damit Änderungen wirksam werden
- Quellcode unter %1$s ansehen
Unserem %2$s-Kanal beitreten
+ Schau dir den Quellcode an auf %1$s
Trete unserem %2$s Kanal bei
Profilname
Namespace einhängen
Gruppen
Fähigkeiten
Module aushängen
- Modul herunterladen: %s
+ Lädt Modul %s herunter
Nicht unterstützt
KernelSU unterstützt derzeit nur GKI-Kernel
Kernel
Fingerabdruck
Installieren
Soft-Reboot
- Sicher, dass du das Modul %s deinstallieren möchtest\?
+ Möchtest du wirklich Modul %s deinstallieren?
Deinstallation fehlgeschlagen: %s
- Die aktuelle Kernel-Version %d ist zu alt für diese Manager-Version. Bitte auf Version %d oder höher upgraden!
+ Die aktuelle KernelSU-Version %d ist zu alt für diese Manager-Version. Bitte auf Version %d oder höher aktualisieren!
Änderungsprotokoll
Erfolgreich importiert
In Zwischenablage exportieren
Kann lokale Vorlage nicht finden!
Vorlagen-ID existiert bereits!
Aus Zwischenablage importieren
- Konnte Changelog nicht laden: %s
+ Konnte Veränderungs-Protokoll nicht laden: %s
Name
Ungültige Vorlagen-ID
Online-Vorlagen synchronisieren
Vorlage erstellen
Schreibgeschützt
Import/Export
- Fehler beim Speichern
+ Schlug beim Speichern der Vorlage fehl
Vorlage bearbeiten
ID
- App-Profil-Template
+ App-Profil-Vorlage
Beschreibung
Speichern
- verwalte lokale und online Profil Vorlagen
+ Verwalte die lokale und online Vorlage des App-Profils
Löschen
Zwischenablage ist leer!
Vorlage ansehen
WebView-Debugging aktivieren
- Kann verwendet werden zum Debugging von WebUI, bitte nur falls nötig aktivieren.
+ Kann zum Fehlerbeheben der WebUI verwendet werden, bitte nur im Notfall aktivieren.
%1$s Partitionsabbild empfohlen
KMI auswählen
Weiter
Direkte Installation (empfohlen)
Datei auswählen
In inaktiven Slot installieren (nach OTA)
- Nach einem Neustart wird dein Gerät **GEZWUNGEN** in den derzeit inaktiven Slot zu booten.
+ Nach einem Neustart wird dein Gerät **GEZWUNGEN** in den derzeit inaktiven Slot zu starten!
\nBenutze dies nur nach Fertigstellung des OTA.
\nFortfahren?
Root-Zugriff konnte nicht gewährt werden!
Öffnen
- Updates suchen
- Automatisch nach Updates suchen beim Öffnen der App
+ Auf Aktualisierung prüfen
+ Prüfe automatisch auf Aktualisierungen, wenn die App geöffnet wird
+ Temporär deinstallieren
+ Deinstallieren
+ KernelSU (Root und alle Module) vollständig und dauerhaft deinstallieren.
+ Ändert die Größe des Sparse-Images, in dem sich das Modul befindet, auf seine tatsächliche Größe. Beachten Sie, dass dies dazu führen kann, dass das Modul nicht ordnungsgemäß funktioniert; verwenden Sie es daher nur, wenn es notwendig ist (Wie für ein Backup).
Protokolle Speichern
+ Permanent deinstallieren
+ Standard-Abbild wiederherstellen
+ KernelSU temporär deinstallieren, originalen Status nach dem nächsten Neustart wiederherstellen.
+ Das Standard Werksabbild wiederherstellen (falls ein Backup existiert), normalerweise vor einem OTA zu verwenden; falls Sie KernelSU deinstallieren müssen, nutzen Sie bitte \"Permanent deinstallieren\".
+ Schreibt
+ Schreiben erfolgreich
+ Schreiben fehlgeschlagen
+ Wähle LKM: %s
+ Spärliches Bild minimieren
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-es/strings.xml b/manager/app/src/main/res/values-es/strings.xml
index 5623b47a2943..a630db99d132 100644
--- a/manager/app/src/main/res/values-es/strings.xml
+++ b/manager/app/src/main/res/values-es/strings.xml
@@ -2,57 +2,57 @@
Inicio
No instalado
- Toca para instalar
+ Haz clic para instalar
Funcionando
Versión: %d
Superusuarios: %d
Módulos: %d
- No soportado
- Por el momento, KernelSU solo es compatible con kernels genéricos (GKIs)
+ Sin soporte
+ KernelSU solo admite kernels GKI por ahora
Versión del kernel
Versión del gestor
Huella del dispositivo
Estado de SELinux
Desactivado
- Enforcing de SELinux
+ Estricto
Permisivo
Desconocido
Superusuario
- No se pudo habilitar el módulo \"%s\"
- No se pudo deshabilitar el módulo \"%s\"
- No hay ningún módulo instalado
+ Error al activar el módulo: %s
+ Error al desactivar el módulo: %s
+ Ningún módulo instalado
Módulo
Desinstalar
- Instalar módulo
+ Instalar
Instalar
Reiniciar
Ajustes
- Reinicio minimo
+ Reinicio suave
Reiniciar en modo de recuperación
Reiniciar en modo de arranque
Reiniciar en modo Download
Reiniciar en modo EDL
Acerca de
- ¿Estás seguro de que quieres desinstalar el módulo \"%s\"?
- \"%s\" esta desinstalado
- No se pudo desinstalar \"%s\"
+ ¿Está seguro de que desea desinstalar el módulo %s?
+ %s desinstalado
+ Fallo al desinstalar: %s
Versión
Autor
- El módulo no puede funcionar ya que OverlayFS no está disponible!
- Recargar
- Mostrar applicaciones del sistema
- Ocultar applicaciones del sistema
- Enviar registro de informe
+ Los módulos no están disponibles ya que OverlayFS está desactivado por el kernel.
+ Refrescar
+ Mostrar aplicaciones del sistema
+ Ocultar aplicaciones del sistema
+ Enviar registros
Modo seguro
Reinicia para aplicar cambios
- Se deshabilitaron los módulos ya que entran en conflicto con los de Magisk!
+ ¡Los módulos no están disponibles debido a un conflicto con Magisk!
Aprende KernelSU
https://kernelsu.org/guide/what-is-kernelsu.html
- Descubre cómo instalar KernelSU y utilizar módulos
+ Aprende a instalar KernelSU y a utilizar módulos
Apóyanos
- KernelSU es y siempre será, libre y de código abierto. De todas formas, puedes mostrarnos tu apoyo mediante una donación.
- Mirar el código en %1$s
Únete a nuestro canal de %2$s
+ KernelSU es, y siempre será, gratuito y de código abierto. Sin embargo, puedes demostrarnos que te importamos haciendo una donación.
+ Ver código fuente en %1$s
Únete a nuestro canal %2$s
Predeterminado
Plantilla
Personalizado
@@ -63,45 +63,70 @@
Individual
Grupos
Capacidades
- Contexto de SELinux
+ Contexto SELinux
Desmontar módulos
- No se pudo actualizar el perfil de la applicación para %s
+ Error al actualizar el perfil de la aplicación para %s
Desmontar módulos por defecto
- El valor global predeterminado para \"Desmontar módulos\" en los perfiles de las aplicaciones. Si la habilitas, se desharán todas las modificaciones al sistema hechas por el módulo para las applicaciones que no tengan un perfil establecido.
- Si habilitas esta opción, KernelSU podrá restaurar cualquier archivo modificado por los módulos para esta app.
+ El valor global predeterminado para \"Umount modules\" en App Profile. Si está activado, eliminará todas las modificaciones de módulos del sistema para las apps que no tengan un perfil establecido.
+ Activar esta opción permitirá a KernelSU restaurar cualquier archivo modificado por los módulos para esta aplicación.
Dominio
Reglas
Actualizar
- Descargando módulo: \"%s\"
+ Descargando módulo: %s
Iniciar descarga: %s
- Nueva versión: %s está disponible, toque para actualizar
- Abrir Aplicacion
- Forzar cierre de la aplicacion
- Reiniciar aplicacion
- Falló al actualizar reglas de SEpolicy por: %s
- La versión actual de KernelSU %d es demasiado baja para que el gestor funcione correctamente. ¡Por favor actualiza a la versión %d o superior!
+ La nueva versión %s está disponible, haga clic para actualizar.
+ Iniciar
+ Forzar detención
+ Reiniciar
+ Error al actualizar las reglas SELinux para: %s
+ La versión %d actual de KernelSU es demasiado baja para que el gestor funcione correctamente. Por favor, ¡actualice a la versión %d o superior!
Registro de cambios
- Importado con exíto
- Exportar a portapapeles
- No se puede encontrar plantilla local para exportar!
- Ya existe un ID de la plantilla!
- Importar desde portapapeles
- Error en obtener los registros de cambios: %s
+ Importado con éxito
+ Exportar al portapapeles
+ ¡No se encuentra la plantilla local para exportar!
+ ¡El ID de plantilla ya existe!
+ Importar desde el portapapeles
+ Fallo en la obtención del registro de cambios: %s
Nombre
- ID de la plantilla es invalido
- Sincronizar plantillas en linea
+ ID de plantilla no válida
+ Sincronizar plantillas en línea
Crear plantilla
- sololectura
+ Sólo lectura
Importar/Exportar
- Fallo en guardar plantilla
+ No se ha podido guardar la plantilla
Editar plantilla
- id
- Plantilla del perfil de la aplicacion
+ ID
+ Plantilla de perfil de aplicación
Descripción
Guardar
- Administrar las plantillas locales y de en linea del perfil de la aplicacion
+ Gestionar la plantilla local y en línea de App Profile
Eliminar
- El portapapeles esta vacio!
+ ¡El portapapeles está vacío!
Ver plantilla
- Guardar Registros
+ Guardar registros
+ Activar la depuración de WebView
+ Se recomienda la imagen de partición %1$s
+ Selecciona KMI
+ Siguiente
+ Instalación directa (Recomendada)
+ ¡Su dispositivo será **FORZADO** a arrancar en la ranura inactiva actual después de un reinicio!\nUtilice esta opción sólo después de que la OTA se haya realizado.\n¿Continuar?
+ Desinstalar
+ Restaurar imagen de archivo
+ Desinstalar temporalmente KernelSU, restaurar al estado original tras el siguiente reinicio.
+ LKM seleccionado: %s
+ Flash falló
+ Éxito de Flash
+ ¡No se ha podido conceder el acceso root!
+ Abrir
+ Seleccione un archivo
+ Instalar en ranura inactiva (Después de OTA)
+ Desinstalar temporalmente
+ Desinstalar permanentemente
+ Desinstalar KernelSU (Root y todos los módulos) completa y permanentemente.
+ Redimensiona la imagen dispersa donde se encuentra el módulo a su tamaño real. Tenga en cuenta que esto puede hacer que el módulo funcione de forma anormal, por lo que sólo debe utilizarlo cuando sea necesario (por ejemplo, para realizar copias de seguridad).
+ Comprobar actualización
+ Comprobación automática de actualizaciones al abrir la aplicación
+ Minimizar la imagen dispersa
+ Puede ser usado para depurar WebUI, por favor habilítalo sólo cuando sea necesario.
+ Restaurar la imagen de fábrica stock (Si existe una copia de seguridad), por lo general se utiliza antes de OTA; si necesita desinstalar KernelSU, por favor, utilice \"Desinstalar permanentemente\".
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-et/strings.xml b/manager/app/src/main/res/values-et/strings.xml
index d514fc6aea79..4f177ff884a7 100644
--- a/manager/app/src/main/res/values-et/strings.xml
+++ b/manager/app/src/main/res/values-et/strings.xml
@@ -12,8 +12,8 @@
Taaskäivita
Taaskäivita taastusesse
Kas soovid kindlasti eemaldada mooduli %s?
- %s on eemaldatud
- Raporteeri logi
+ %s eemaldatud
+ Saada logid
Turvarežiim
Muudatuste rakendamiseks taaskäivita
Õpi KernelSUd
@@ -28,8 +28,8 @@
Muuda malli
Rakenduseprofiili mall
ID
- vaid lugemiseks
- malli ID juba eksisteerib!
+ Vaid lugemiseks
+ Malli ID juba eksisteerib!
Ekspordi lõikelauale
Sünkrooni võrgumallid
Muudatuste logi hankimine ebaõnnestus: %s
@@ -59,10 +59,10 @@
Autor
Eemaldamine ebaõnnestus: %s
Versioon
- overlayfs pole saadaval, moodul ei saa töötada!
+ Moodulid pole saadaval, kuna OverlayFS on kernelis keelatud.
Kuva süsteemirakendused
Peida süsteemirakendused
- Moodulid on keelatud, kuna need lähevad konflikti Magiski omadega!
+ Moodulid pole saadaval Magiski konflikti tõttu!
Õpi KernelSUd paigaldama ja mooduleid kasutama
Toeta meid
Grupid
@@ -77,14 +77,14 @@
Võimekused
Sobimatu malli ID
SELinux kontekst
- Praegune KernelSU versioon %d on liiga madal, haldur ei saa konkreetselt toimida. Palun täienda versioonile %d või kõrgem!
+ Praegune KernelSU versioon %d on liiga madal, haldur ei saa korrektselt töötada. Palun täienda versioonile %d või kõrgem!
Domeen
Käivita
Sundpeata
Reeglid
Uuenda
Mooduli allalaadimine: %s
- Uus versioon: %s on saadaval, klõpsa täiendamiseks
+ Uus versioon %s on saadaval, klõpsa täiendamiseks.
Taaskäivita
Muudatuste logi
Nimi
@@ -100,8 +100,8 @@
Loo mall
Halda kohalikke ja võrgusolevaid rakenduseprofiili malle
Selle valiku lubamine lubab KernelSU-l taastada selle rakenduse moodulite poolt mistahes muudetud faile.
- Eksportimiseks kohalikku malli ei leitud!
- Globaalne vaikeväärtus \"Lahtihaagitud moodulitele\" rakenduseprofiilides. Lubamisel eemaldab see kõik moodulite süsteemimuudatused rakendustele, millel ei ole profiili määratud.
+ Ei saa eksportida, kohalikku malli ei leitud!
+ Globaalne vaikeväärtus \"Lahtihaagitud moodulitele\" rakenduseprofiilis. Lubamisel eemaldab see kõik moodulite süsteemimuudatused rakendustele, millel ei ole profiili määratud.
Saab kasutada WebUI silumiseks, palun luba ainult vajadusel.
Juurkasutaja andmine ebaõnnestus!
Kontrolli uuendusi
@@ -109,4 +109,22 @@
Ava
Luba WebView silumine
Salvesta Logid
+ Vali KMI
+ %1$s partitsioonitõmmis on soovitatud
+ Edasi
+ Sinu seade **SUNNITAKSE** pärast taaskäivitust ebaaktiivsesse lahtrisse käivituma!\nKasuta seda valikut vaid siis, kui tegid üle-õhu uuenduse.\nJätkad?
+ Eemalda
+ Eemalda KernelSU ajutiselt, taasta pärast taaskäivitust algseisu.
+ KernelSU eemaldamine (juurkasutaja ja kõik moodulid) täielikult ja püsivalt.
+ Taasta tehase-vaiketõmmis (kui varundus eksisteerib), tavaliselt kasutatakse enne üle-õhu uuendust; kui soovid KernelSU-d eemaldada, palun kasuta \"Eemalda püsivalt\".
+ Välgutamine
+ Välgutamine õnnestus
+ Välgutamine ebaõnnestus
+ Valitud LKM: %s
+ Otsene paigaldus (soovitatud)
+ Vali fail
+ Paigalda ebaaktiivsesse lahtrisse (pärast üle-õhu uuendust)
+ Eemalda ajutiselt
+ Eemalda püsivalt
+ Taasta vaikimisi tõmmis
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-fa/strings.xml b/manager/app/src/main/res/values-fa/strings.xml
index a5cdb2f7ff58..17469cc8a892 100644
--- a/manager/app/src/main/res/values-fa/strings.xml
+++ b/manager/app/src/main/res/values-fa/strings.xml
@@ -1,67 +1,68 @@
+
-خانه
-نصب نشده است
-برای نصب ضربه بزنید
-به درستی کار میکند
-نسخه: %d
-برنامه های با دسترسی روت: %d
-ماژولها: %d
-پشتیبانی نشده
-کرنل اس یو فقط هسته های gki را پشتیبانی میکند
+ خانه
+ نصب نشده است
+ برای نصب ضربه بزنید
+ به درستی کار میکند
+ نسخه: %d
+ برنامه های با دسترسی روت: %d
+ ماژولها: %d
+ پشتیبانی نشده
+ کرنل اس یو فقط هسته های gki را پشتیبانی میکند
هسته
نسخه برنامه
اثرانگشت
وضعیت SELinux
-غیرفعال
-قانونمند
-آزاد
-ناشناخته
-دسترسی روت
+ غیرفعال
+ قانونمند
+ آزاد
+ ناشناخته
+ دسترسی روت
فعال کردن ماژول ناموفق بود: %s
-غیرفعال کردن ماژول ناموفق بود: %s
-هیچ ماژولی نصب نشده است
-ماژول
-لغو نصب
-نصب
-نصب
-راه اندازی دوباره
-تنظیمات
-راه اندازی نرم
-راه اندازی به ریکاوری
-راه اندازی به بوتلودر
-راه اندازی به حالت دانلود
-راه اندازی به EDL
-درباره
+ غیرفعال کردن ماژول ناموفق بود: %s
+ هیچ ماژولی نصب نشده است
+ ماژول
+ لغو نصب
+ نصب
+ نصب
+ راه اندازی دوباره
+ تنظیمات
+ راه اندازی نرم
+ راه اندازی به ریکاوری
+ راه اندازی به بوتلودر
+ راه اندازی به حالت دانلود
+ راه اندازی به EDL
+ درباره
آیا مطمئنید که میخواهید ماژول %s را پاک کنید؟
-%s پاک شد
-پاک کردن ناموفق بود: %s
-نسخه
-سازنده
-overlayfs موجود نیست. مازول کار نمیکند!!
-تازهسازی
-نمایش برنامه های سیستمی
-مخفی کردن برنامه های سیستمی
-ارسال وقایع
-حالت امن
-راهاندازی مجدد برای تاثیرگذاری
-مازول به دلیل تعارض با مجیسک غیرفعال شده اند\'s!
-یادگیری کرنل اس یو
-https://kernelsu.org/guide/what-is-kernelsu.html
-یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید
-از ما حمایت کنید
-KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است.
-
+ %s پاک شد
+ پاک کردن ناموفق بود: %s
+ نسخه
+ سازنده
+ overlayfs موجود نیست. مازول کار نمیکند!!
+ تازهسازی
+ نمایش برنامه های سیستمی
+ مخفی کردن برنامه های سیستمی
+ ارسال وقایع
+ حالت امن
+ راهاندازی مجدد برای تاثیرگذاری
+ مازول به دلیل تعارض با مجیسک غیرفعال شده اند\'s!
+ یادگیری کرنل اس یو
+ https://kernelsu.org/guide/what-is-kernelsu.html
+ یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید
+ از ما حمایت کنید
+ KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است.
+
Join our %2$s channel ]]>
-پروفایل برنامه
-پیشفرض
-قالب
-شخصی سازی شده
-اسم پروفایل
-Mount namespace
-اثر گرفته
-گلوبال
-تکی
-جداکردن ماژول ها
+ پروفایل برنامه
+ پیشفرض
+ قالب
+ شخصی سازی شده
+ اسم پروفایل
+ Mount namespace
+ اثر گرفته
+ گلوبال
+ تکی
+ جداکردن ماژول ها
ذخیره گزارشها
-
+
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-fr/strings.xml b/manager/app/src/main/res/values-fr/strings.xml
index 01c0672b87a6..a5de872319e1 100644
--- a/manager/app/src/main/res/values-fr/strings.xml
+++ b/manager/app/src/main/res/values-fr/strings.xml
@@ -5,7 +5,7 @@
Version : %d
Super-utilisateurs : %d
Modules : %d
- Actuellement, KernelSU ne supporte que les noyaux GKI
+ KernelSU ne prend désormais en charge que les noyaux GKI
Noyau
Empreinte digitale
Mode SELinux
@@ -16,12 +16,12 @@
Aucun module installé
Accueil
Appuyez ici pour installer
- Non supporté
- Échec de la désinstallation : %s
+ Non pris en charge
+ Échec de la désinstallation : %s
Version
Version du gestionnaire
Enforcing
- Échec de l\'activation du module : %s
+ Échec de l\'activation du module : %s
Modules
Désinstaller
Installer
@@ -39,20 +39,19 @@
Auteur
Êtes-vous sûr(e) de vouloir désinstaller le module %s \?
Découvrir KernelSU
- OverlayFS est indisponible, impossible de faire fonctionner les modules !
+ Les modules sont indisponibles car OverlayFS est désactivé par le noyau.
Rafraîchir
Afficher les applications système
Masquer les applications système
Mode sans échec
- Rapport de journal
+ Envoyer les journaux
Redémarrez pour appliquer les modifications
- Les modules sont désactivés car ils sont en conflit avec ceux de Magisk !
+ Les modules sont indisponibles en raison d\'un conflit avec Magisk !
https://kernelsu.org/guide/what-is-kernelsu.html
Soutenez-nous
Découvrez comment installer KernelSU et utiliser les modules
KernelSU est, et restera toujours, gratuit et open source. Vous pouvez cependant nous témoigner de votre soutien en nous faisant un don.
- Voir le code source sur %1$s
-\nRejoindre notre canal %2$s
+ Voir le code source sur %1$s
\nRejoindre notre canal %2$s
Modèle
Par défaut
Personnalisé
@@ -66,7 +65,7 @@
Capacités
Démonter les modules
Échec de la modification du profil d\'application de %s
- L\'activation de cette option permettra à KernelSU de restaurer tous les fichiers modifiés par les modules de cette application.
+ L\'activation de cette option permettra à KernelSU de restaurer tous les fichiers modifiés par les modules pour cette application.
Démonter les modules par défaut
Valeur globale par défaut pour l\'option « Démonter les modules » dans les profils d\'application. Lorsqu\'elle est activée, les modifications apportées au système par les modules seront supprimées pour les applications qui n\'ont pas de profil défini.
Domaine
@@ -74,7 +73,7 @@
Mettre à jour
Téléchargement du module : %s
Lancer
- La version %s est disponible, appuyez ici pour mettre à jour
+ La nouvelle version %s est disponible, appuyez ici pour mettre à jour.
Début du téléchargement de : %s
Forcer l\'arrêt
Relancer l\'application
@@ -82,20 +81,20 @@
La version actuelle de KernelSU (%d) est trop ancienne pour que le gestionnaire fonctionne correctement. Veuillez passer à la version %d ou à une version supérieure !
Importation réussie
Exporter vers le presse-papiers
- Impossible de trouver un modèle local à exporter !
- L\'id du modèle existe déjà !
+ Impossible de trouver un modèle local à exporter !
+ L\'ID du modèle existe déjà !
Journal des modifications
Importer à partir du presse-papiers
Échec de récupération du journal des modifications : %s
Nom
- id de modèle invalide
+ ID de modèle invalide
Synchroniser les modèles en ligne
Créer un modèle
- lecture seule
+ Lecture seule
Importer/exporter
Échec de l\'enregistrement du modèle
Modifier le modèle
- id
+ ID
Modèles de profils d\'application
Description
Enregistrer
@@ -105,7 +104,7 @@
Voir le modèle
Vérifier automatiquement les mises à jour à l\'ouverture de l\'application
Vérifier les mises à jour
- Activer le débogage de WebView
+ Activer le débogage WebView
Peut être utilisé pour déboguer WebUI, n\'activez cette option que si nécessaire.
Échec de l\'octroi des privilèges root !
Ouvrir
@@ -118,18 +117,18 @@
Suivant
L\'image de la partition %1$s est recommandée
Sélectionner une KMI
- Minimiser l\'image clairsemée
- Redimensionne l\'image clairsemée où se trouve le module à sa taille réelle. Notez que cela peut entraîner un dysfonctionnement du module, alors utilisez cette fonctionnalité uniquement lorsque nécessaire (pour la sauvegarde, par exemple)
+ Minimiser la taille de l\'image creuse
+ Redimensionne l\'image creuse où le module est situé à sa taille réelle. Notez que cela peut entraîner un dysfonctionnement du module, veuillez utiliser cette option uniquement lorsque cela est nécessaire (par exemple pour la sauvegarde de l\'appareil).
Désinstaller
Désinstaller temporairement
Désinstaller définitivement
- Restaurer l\'image stock
- Restaurer l\'image stock d\'usine (s\'il en existe une sauvegarde), option généralement utilisée avant une mise à jour OTA ; si vous avez besoin de désinstaller KernelSU, utilisez plutôt l\'option « Désinstaller définitivement ».
+ Restaurer l\'image d\'origine
+ Restaurer l\'image d\'origine d\'usine (s\'il en existe une sauvegarde), option généralement utilisée avant une mise à jour OTA ; si vous avez besoin de désinstaller KernelSU, utilisez plutôt l\'option « Désinstaller définitivement ».
Flash en cours
Flash réussi
Échec du flash
- lkm sélectionné : %s
+ LKM sélectionné : %s
Désinstallation complète et permanente de KernelSU (root et tous les modules).
Désinstaller KernelSU temporairement et rétablir l\'état original au redémarrage suivant.
- Enregistrer les Journaux
+ Enregistrer les journaux
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-gl/strings.xml b/manager/app/src/main/res/values-gl/strings.xml
new file mode 100644
index 000000000000..89956f2306d6
--- /dev/null
+++ b/manager/app/src/main/res/values-gl/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Inicio
+
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-in/strings.xml b/manager/app/src/main/res/values-in/strings.xml
index 98698f529aa9..f2223e06ca8f 100644
--- a/manager/app/src/main/res/values-in/strings.xml
+++ b/manager/app/src/main/res/values-in/strings.xml
@@ -10,7 +10,7 @@
Tidak didukung
KernelSU saat ini hanya mendukung kernel GKI
Kernel
- Versi Manager
+ Versi manager
Identitas
Status SELinux
Nonaktif
@@ -38,11 +38,11 @@
Gagal menghapus: %s
Versi
Oleh
- OverlayFS tidak tersedia, modul tidak berfungsi!
+ Kernel tidak mendukung OverlayFS, modul tidak berfungsi.
Muat ulang
Tampilkan aplikasi sistem
Sembunyikan aplikasi sistem
- Laporkan Log
+ Kirim Log
Mode aman
Reboot agar berfungsi
Konflik dengan Magisk, fungsi modul ditiadakan!
@@ -67,16 +67,16 @@
Umount Modul
Gagal membarui Profil pada %s
Melepas Modul secara bawaan
- Menggunakan \"Umount Modul\" secara universal pada Profil aplikasi. Jika diaktifkan, akan menghapus semua modifikasi sistem untuk aplikasi yang tidak memiliki set Profil.
+ Menggunakan \"Umount Modul\" secara universal pada Profil Aplikasi. Jika diaktifkan, akan menghapus semua modifikasi sistem untuk aplikasi yang tidak memiliki set profil.
Aktifkan opsi ini agar KernelSU dapat memulihkan kembali berkas termodifikasi oleh modul pada aplikasi ini.
Domain
Aturan
Membarui
Mengunduh modul: %s
Mulai mengunduh: %s
- Tersedia versi terbaru: %s, Klik untuk membarui
+ Tersedia versi terbaru %s, Klik untuk membarui.
Jalankan
- Paksa Berhenti
+ Paksa berhenti
Mulai ulang
Gagal membarui aturan SELinux pada: %s
Versi KernelSU %d terlalu rendah agar manajer berfungsi normal. Harap membarui ke versi %d atau di atasnya!
@@ -84,25 +84,25 @@
Berhasil diimpor
Ekspor ke papan klip
Tidak ditemukan templat lokal untuk diekspor!
- Id templat sudah ada!
+ ID templat sudah ada!
Impor dari papan klip
Gagal mengambil Changelog: %s
Nama
Id templat tidak valid
Sinkronkan templat daring
- Buat Templat
+ Buat templat
Impor/Ekspor
Gagal menyimpan templat
- Edit Templat
- id
+ Edit templat
+ ID
Templat Profil Aplikasi
Deskripsi
Simpan
Atur templat Profil yang lokal dan daring
Hapus
Papan klip kosong!
- Lihat Templat
- ReadOnly
+ Lihat templat
+ readonly
Pengawakutuan WebView
Dapat mengawakutu WebView, hanya aktifkan jika butuh.
%1$s image partisi terekomendasi
@@ -111,7 +111,7 @@
Gawai akan **DIPAKSA** untuk but ke slot nonaktif!
\nHANYA gunakan setelah proses OTA selesai.
\nLanjutkan?
- Instal Langsung (rekomendasi)
+ Instal langsung (rekomendasi)
Pilih berkas
Instal ke slot nonaktif (setelah OTA)
Gagal memberikan akses root!
@@ -119,14 +119,14 @@
Cek terbaru
Cek terbaru setiap membuka aplikasi
Meminimalkan sparse image
- Mengembalikan sparse image, lokasi modul disimpan, ke ukuran sebenarnya. Dapat menyebabkan modul bekerja abnormal, maka gunakan saat dibutuhkan saja (mis. untuk pencadangan)
+ Mengembalikan sparse image, lokasi modul disimpan, ke ukuran sebenarnya. Dapat menyebabkan modul bekerja abnormal, maka gunakan saat dibutuhkan saja (mis. untuk pencadangan).
Hapus permanen KernelSU (root dan modul).
- Hapus Temporer
- Pulihkan Image Asal
+ Hapus temporer
+ Pulihkan image asal
Hapus
Hapus Temporer KernelSU, pulihkan ke kondisi asali setelah but berikutnya.
- Hapus Permanen
- Pulihkan image bawaan ROM (jika cadangan tersedia), umumnya dilakukan sebelum OTA; jika ingin menghapus KernelSU, gunakan fungsi \"Hapus Permanen\".
+ Hapus permanen
+ Pulihkan image bawaan ROM (jika cadangan tersedia), umumnya dilakukan sebelum OTA; jika ingin menghapus KernelSU, gunakan fungsi \"Hapus permanen\".
Pemasangan Berhasil
LKM dipilih: %s
Pasang
diff --git a/manager/app/src/main/res/values-it/strings.xml b/manager/app/src/main/res/values-it/strings.xml
index 7bd3f9247356..642640b3cff4 100644
--- a/manager/app/src/main/res/values-it/strings.xml
+++ b/manager/app/src/main/res/values-it/strings.xml
@@ -45,7 +45,7 @@
Invia log
Modalità provvisoria
Riavvia per applicare la modifica
- I moduli sono disabilitati perché in conflitto con quelli di Magisk!
+ I moduli sono disabilitati perché in conflitto con Magisk!
Scopri KernelSU
https://kernelsu.org/guide/what-is-kernelsu.html
Scopri come installare KernelSU e utilizzare i moduli
@@ -82,16 +82,16 @@
Registro aggiornamenti
Crea modello
Modifica modello
- identificativo
+ identificatore
Identificativo modello non valido
Nome
Visualizza modello
Sola lettura
- L\'identificativo del modello esiste già!
+ L\'identificatore del modello è già in uso!
Importa/Esporta
Importa dagli appunti
Esporta negli appunti
- Impossibile trovare modello locale da esportare!
+ Impossibile trovare un modello locale da esportare!
Importato con successo
Sincronizza i modelli remoti
Gli appunti sono vuoti!
@@ -106,29 +106,29 @@
Impossibile reperire il changelog: %s
Controlla aggiornamenti
Controlla automaticamente la disponibilità di aggiornamenti all\'apertura dell\'applicazione
- Abilita il Debug di WebView
+ Abilita il debug di WebView
Può essere usato per svolgere il debug di WebUI, è consigliato attivarlo solo quando necessario.
È consigliato usare immagine della partizione %1$s
Scegli il KMI
Avanti
Installazione diretta (Raccomandata)
- Scegli un File
- Installa nello Slot Inattivo (Dopo OTA)
+ Scegli un file
+ Installa nello slot inattivo (dopo OTA)
Il tuo dispositivo sarà **FORZATO** ad avviarsi nello slot inattivo dopo il riavvio!
\nUsa questa opzione solo quando l\'applicazione dell\'aggiornamento OTA è terminata.
\nProcedere?
Riduci la dimensione dell\'immagine moduli sparse al minimo
- Riduci la dimensione dell\'immagine sparse dei moduli alla sua reale dimenzione. Nota che questo potrebbe causare malfunzionamenti dei moduli quindi utilizzala solo quando necessario (ad esempio in caso di backup)
+ Riduci la dimensione dell\'immagine sparse dei moduli alla sua reale dimensione. Nota che questo potrebbe causare malfunzionamenti dei moduli quindi utilizzala solo quando necessario (ad esempio in caso di backup)
Disinstalla
- Disinstalla Temporaneamente
- Disinstalla Permanentemente
+ Disinstalla temporaneamente
+ Disinstalla permanentemente
Ripristina immagine originale del produttore
Disinstalla temporaneamente KernelSU, ripristina lo stato originale dopo il prossimo riavvio.
- Disinstalla KernelSU (Root e tutti i moduli) completamente e permanentemente.
+ Disinstalla KernelSU (root e tutti i moduli) completamente e permanentemente.
Installazione
Installazione completata
Installazione fallita
LKM selezionato: %s
- Ripristina l\'immagine di fabbrica del produttore (se il backup è presente), solitamente usato prima di applicare l\'OTA; se devi disinstallare KernelSU, utilizza invece \"Disinstalla Permanentemente\".
+ Ripristina l\'immagine di fabbrica del produttore (se il backup è presente), solitamente usato prima di applicare l\'OTA; se devi disinstallare KernelSU, utilizza invece \"Disinstalla permanentemente\".
Salva Registri
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ja/strings.xml b/manager/app/src/main/res/values-ja/strings.xml
index 4ecf7420447a..bf2108a85a16 100644
--- a/manager/app/src/main/res/values-ja/strings.xml
+++ b/manager/app/src/main/res/values-ja/strings.xml
@@ -20,7 +20,7 @@
スーパーユーザー
モジュールの有効化に失敗: %s
モジュールの無効化に失敗: %s
- モジュールをインストールしていません
+ モジュールがインストールされていません
モジュール
アンインストール
インストール
@@ -38,19 +38,19 @@
アンインストールに失敗: %s
バージョン
制作者
- OverlayFS が有効でないためモジュールは動作しません!
+ カーネルによって OverlayFS が無効になっているため、モジュールが利用できません。
更新
システムアプリを表示
システムアプリを非表示
ログを送信
セーフモード
再起動すると有効化されます
- Magisk と競合しているためモジュールは無効になっています!
+ モジュールが Magisk との競合により利用できません!
KernelSU について
https://kernelsu.org/ja_JP/guide/what-is-kernelsu.html
KernelSU のインストール方法やモジュールの使い方はこちら
支援する
- KernelSU はこれからもずっとフリーでオープンソースです。寄付をすることで私たちを気にかけていることを示せます。
+ KernelSU はこれからもずっと無料でオープンソースです。寄付をして頂くことで、開発を支援していただけます。
%2$s チャンネルに参加]]>
アプリのプロファイル
既定
@@ -67,7 +67,7 @@
%s のアプリのプロファイルの更新をできませでした
ドメイン
ルール
- 新しいバージョン: %s が利用可能です。タップしてダウンロード
+ 新しいバージョン %s が利用可能です。タップしてダウンロード。
アップデート
ダウンロードを開始: %s
起動
@@ -84,7 +84,7 @@
インポート成功
クリップボードからエクスポート
エクスポートするローカル テンプレートが見つかりません!
- テンプレート id はすでに存在します!
+ テンプレート ID はすでに存在します!
クリップボードからインポート
変更ログの取得に失敗しました: %s
名前
@@ -95,7 +95,7 @@
インポート/エクスポート
テンプレートの保存に失敗しました
テンプレートの編集
- id
+ ID
アプリプロファイルのテンプレート
説明
保存
@@ -119,7 +119,7 @@
直接インストール (推奨)
ファイルを選択してください
スパースイメージを最小化
- モジュールが配置されているスパースイメージのサイズを実際のサイズに変更します。 モジュールが正常に動作しなくなる可能性がありますので、必要な場合にのみご使用ください
+ モジュールが配置されているスパースイメージのサイズを実際のサイズに変更します。 モジュールが正常に動作しなくなる可能性がありますので、必要な場合にのみご使用ください。
完全にアンインストールする
ストックイメージを復元
一時的にアンインストールする
@@ -130,6 +130,6 @@
フラッシュ
フラッシュ成功
フラッシュ失敗
- 選択された lkm: %s
+ 選択された LKM: %s
ログを保存
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-night-v27/themes.xml b/manager/app/src/main/res/values-night-v27/themes.xml
deleted file mode 100644
index 10a773b16f28..000000000000
--- a/manager/app/src/main/res/values-night-v27/themes.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-night/themes.xml b/manager/app/src/main/res/values-night/themes.xml
index 91abf657bfdc..d76ba8e6852b 100644
--- a/manager/app/src/main/res/values-night/themes.xml
+++ b/manager/app/src/main/res/values-night/themes.xml
@@ -1,10 +1,10 @@
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-nl/strings.xml b/manager/app/src/main/res/values-nl/strings.xml
index bebf37890eb2..19031425e6a3 100644
--- a/manager/app/src/main/res/values-nl/strings.xml
+++ b/manager/app/src/main/res/values-nl/strings.xml
@@ -10,17 +10,17 @@
Niet ondersteund
KernelSU ondersteunt alleen GKI kernels
Kernel
- Manager Versie
+ Manager versie
Fingerprint
SELinux status
Uitgeschakeld
Afgedwongen
Permissief
Niet gekend
- SupergeBruiker
+ Supergebruiker
Mislukt om module in te schakelen: %s
Mislukt om module uit te schakelen: %s
- Geen geïnstalleerde modules
+ Geen module geïnstalleerde
Module
Verwijderen
Installeren
@@ -34,18 +34,18 @@
Herstart naar EDL
Over
Zeker van het verwijderen van module %s?
- %s is verwijderd
+ %s verwijderd
Mislukt om te verwijderen: %s
Versie
Auteur
- overlayfs is niet beschikbaar, module kan niet werken!
+ Modules zijn niet beschikbaar omdat OverlayFS door de kernel is uitgeschakeld.
Vernieuwen
Toon systeem apps
Verberg systeem apps
- Rapport Log
+ Verzenden Logs
Safe mode
Herstart om effect te hebben
- Modules zijn uitgeschakeld omdat ze in conflict zijn met magisk!
+ Modules zijn niet beschikbaar vanwege een conflict met Magisk!
Leer KernelSU
https://kernelsu.org/guide/what-is-kernelsu.html
Leer hoe KernelSU te installeren en modules te gebruiken
@@ -67,33 +67,33 @@
Ontkoppel modules
Mislukt om App Profiel te updaten voor %s
Ontkoppel standaard de modules
- De globale standaard waarde voor \"Ontkoppel modules\" in App Profielen. Indien geactiveerd, zal het alle module wijzigingen tot het systeem verwijderen voor applicaties die geen Profiel ingesteld hebben.
- Met deze optie ingeschakeld zal KernelSU toelaten om alle gewijzigde bestanden door de modules voor deze applicatie te herstellen.
+ De globale standaardwaarde voor \"Umount modules\" in App Profile. Als dit is ingeschakeld, worden alle modulewijzigingen in het systeem verwijderd voor apps waarvoor geen profiel is ingesteld.
+ Met deze optie ingeschakeld zal KernelSU toelaten om alle gewijzigde bestanden door de modules voor deze app te herstellen.
Domein
Regels
Update
Downloaden van module: %s
- Nieuwe versie: %s is beschikbaar,klik om te upgraden
+ Nieuwe versie %s is beschikbaar,klik om te upgraden.
Start
- Forceer Stop
+ Forceer stop
Herstart
Begin met downloaden: %s
Kan SELinux-regels niet bijwerken voor: %s
- De huidige KernelSU-versie %d is te laag om de manager correct te laten functioneren. Upgrade naar versie %d of hoger!
+ De huidige KernelSU-versie %d is te laag voor de manager om goed te werken. Upgrade naar versie %d of hoger!
wijzigings logboek
App-profiel Sjabloon
- Maken Sjabloon
- Bewerkin Sjabloon
- id
+ Maken sjabloon
+ Bewerkin sjabloon
+ ID
Ongeldige sjabloon id
Naam
Redde
- Bekijken Sjabloon
+ Bekijken sjabloon
Beschrijving
Beheer lokale en online sjabloon van app-profiel
Verwijderen
- alleen lezen
- sjabloon id bestaat al!
+ Alleen lezen
+ Sjabloon ID bestaat al!
Synchroniseer online-sjablonen
Mislukt naar opslaan sjabloon
Klembord is leeg!
@@ -104,7 +104,7 @@
Controleer update
Schakel WebView-foutopsporing
Kan worden gebruikt om WebUI te debuggen. Schakel dit alleen in als dat nodig is.
- Kan geen lokale sjabloon vinden om te exporteren!
+ Kan niet geen lokale sjabloon vinden om te exporteren!
Succesvol geïmporteerd
Open
Controleer automatisch op updates bij het openen van de app
@@ -112,7 +112,7 @@
Selecteer een bestand
Kan geen root verlenen!
Minimaliseer schaarse afbeeldingen
- Wijzig het formaat van de beperkte afbeelding waar de module zich bevindt naar de werkelijke grootte. Houd er rekening mee dat dit ervoor kan zorgen dat de module abnormaal werkt, dus gebruik deze alleen wanneer dit nodig is (zoals voor back-up)
+ Wijzig het formaat van de beperkte afbeelding waar de module zich bevindt naar de werkelijke grootte. Houd er rekening mee dat dit ervoor kan zorgen dat de module abnormaal werkt, dus gebruik deze alleen wanneer dit nodig is (zoals voor back-up).
%1$s partitie-image wordt aanbevolen
Naast
Uw apparaat wordt **GEFORCEERD** om na een herstart op te starten naar het huidige inactieve slot!
@@ -125,5 +125,11 @@
Permanent verwijderen
Herstel stockafbeelding
Verwijder KernelSU tijdelijk en herstel het naar de oorspronkelijke staat na de volgende herstart.
+ Het verwijderen van KernelSU (Root en alle modules) volledig en permanent.
+ Herstel de standaard fabrieksimage (als er een back-up bestaat), die normaal gesproken vóór OTA wordt gebruikt. Als u KernelSU moet verwijderen, gebruikt u \'Permanent verwijderen\'.
+ Knipperen
Logboeken Opslaan
+ Flash-succes
+ Flash is mislukt
+ Geselecteerde LKM: %s
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-pl/strings.xml b/manager/app/src/main/res/values-pl/strings.xml
index b4fe83f3dc8f..61250420804a 100644
--- a/manager/app/src/main/res/values-pl/strings.xml
+++ b/manager/app/src/main/res/values-pl/strings.xml
@@ -39,14 +39,14 @@
Nie udało się odinstalować:: %s
Wersja
Autor
- overlayfs jest niedostępny, moduł nie zadziała!
+ Moduły są niedostępne, ponieważ OverlayFS jest wyłączony przez jądro.
Odśwież
Pokaż aplikacje systemowe
Ukryj aplikacje systemowe
- Raportuj log
+ Wyślij logi
Tryb bezpieczny
Uruchom ponownie, aby zastosować zmiany
- Moduły są wyłączone, ponieważ są w konflikcie z modułami Magiska!
+ Moduły są niedostępne z powodu konfliktu z Magiskiem!
Poznaj KernelSU
https://kernelsu.org/guide/what-is-kernelsu.html
Dowiedz się jak zainstalować KernelSU i jak korzystać z modułów
@@ -68,14 +68,14 @@
Odmontuj moduły
Nie udało się zaktualizować profilu aplikacji dla %s
Domyślnie odmontuj moduły
- Globalna wartość domyślna opcji \"Odmontuj moduły\" w profilach aplikacji. Jeśli jest włączona, wycofuje wszystkie modyfikacje dokonane przez moduły dla aplikacji, które nie mają ustawionego profilu.
+ Globalna wartość domyślna opcji \"Odmontuj moduły\" w profilu aplikacji. Jeśli jest włączona, wycofuje wszystkie modyfikacje dokonane przez moduły dla aplikacji, które nie mają ustawionego profilu.
Włączenie tej opcji umożliwi KernelSU przywrócenie wszelkich zmodyfikowanych plików przez moduły dla tej aplikacji.
Domena
Reguły
Zaktualizuj
Pobieranie modułu: %s
Rozpocznij pobieranie: %s
- Nowa wersja: %s jest dostępna. Kliknij, aby zaktualizować
+ Nowa wersja %s jest dostępna. Kliknij, aby zaktualizować.
Uruchom
Wymuś zatrzymanie
Restartuj
@@ -99,7 +99,7 @@
Opis
Zapisz
Usuń
- tylko do odczytu
+ Tylko do odczytu
Importuj/Eksportuj
Importuj ze schowka
Eksportuj do schowka
@@ -120,17 +120,18 @@
Wyszukaj aktualizacje
Wyszukuj aktualizacje automatycznie przy otwieraniu aplikacji
Minimalizuj rozrzedzony (sparse) obraz
- Zmienia rozmiar obrazu rozrzedzonego(sparse), w którym znajduje się moduł, do jego rzeczywistego rozmiaru. Należy pamiętać, że może to spowodować nieprawidłowe działanie modułu, więc należy go używać tylko wtedy, gdy jest to konieczne (np. do tworzenia kopii zapasowych)
+ Zmienia rozmiar obrazu rozrzedzonego(sparse), w którym znajduje się moduł, do jego rzeczywistego rozmiaru. Należy pamiętać, że może to spowodować nieprawidłowe działanie modułu, więc należy go używać tylko wtedy, gdy jest to konieczne (np. do tworzenia kopii zapasowych).
Odinstaluj zupełnie
Przywróć obraz fabryczny
Odinstaluj tymczasowo
Odinstaluj
Tymczasowo odinstaluj KernelSU, przywróć do oryginalnego stanu po następnym ponownym uruchomieniu.
- Całkowite i trwałe odinstalowanie KernelSU(Root i wszystkich modułów).
- Przywróć obraz fabryczny (jeśli istnieje kopia zapasowa), zwykle używany przed OTA; jeśli chcesz odinstalować KernelSU, użyj opcji \"Odinstaluj zupełnie\".
+ Całkowite i trwałe odinstalowanie KernelSU (Root i wszystkich modułów).
+ Przywróć obraz fabryczny (jeśli istnieje kopia zapasowa), zwykle używany przed OTA; jeśli chcesz odinstalować KernelSU, użyj opcji \"Odinstaluj całkowicie\".
Flashowanie
Flashowanie ukończone pomyślnie
Flashowanie nieudane
- Wybrano lkm: %s
- Zapisz Dzienniki
+ Wybrano LKM: %s
+ Zapisz dzienniki
+ Akcja
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-pt-rBR/strings.xml b/manager/app/src/main/res/values-pt-rBR/strings.xml
index f092a45128fd..4d69f8a758f3 100644
--- a/manager/app/src/main/res/values-pt-rBR/strings.xml
+++ b/manager/app/src/main/res/values-pt-rBR/strings.xml
@@ -42,7 +42,7 @@
Atualizar
Mostrar apps do sistema
Ocultar apps do sistema
- Reportar registro
+ Reportar registros
Modo de segurança
Reinicie para entrar em vigor
Os módulos estão indisponíveis devido a um conflito com Magisk!
@@ -126,10 +126,11 @@
Restaurar imagem de fábrica
Restaure a imagem de fábrica (se existir um backup), geralmente usada antes do OTA. Se você precisar desinstalar o KernelSU, use \"Desinstalar permanentemente\".
Desinstale temporariamente o KernelSU e restaure ao estado original após a próxima reinicialização
- Desinstale o KernelSU (Root e todos os módulos) completamente e permanentemente
+ Desinstale o KernelSU (root e todos os módulos) completamente e permanentemente
LKM selecionado: %s
Flash falhou
Flashando
Flash bem-sucedido
- Salvar Logs
+ Salvar registros
+ Ação
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ru/strings.xml b/manager/app/src/main/res/values-ru/strings.xml
index 91dd276ff0a5..885d6bccce8c 100644
--- a/manager/app/src/main/res/values-ru/strings.xml
+++ b/manager/app/src/main/res/values-ru/strings.xml
@@ -36,18 +36,18 @@
Перезагрузить в EDL
О приложении
Вы уверены, что хотите удалить модуль %s?
- %s удален
+ %s удалён
Не удалось удалить: %s
Версия
Автор
- overlayfs недоступен, модуль не может работать!
+ Модули недоступны, так как OverlayFS отключен ядром.
Обновить страницу
Показать системные приложения
Скрыть системные приложения
- Отправить лог
+ Отправить логи
Безопасный режим
Перезагрузите, чтобы изменения вступили в силу
- Модули отключены, потому что они конфликтуют с Magisk!
+ Модули недоступны из-за конфликта с Magisk!
Узнайте о KernelSU
https://kernelsu.org/ru_RU/guide/what-is-kernelsu.html
Узнайте, как установить KernelSU и использовать модули
@@ -77,7 +77,7 @@
Обновить
Скачивание модуля: %s
Начало скачивания: %s
- Новая версия: %s доступна, нажмите, чтобы скачать
+ Новая версия: %s доступна, нажмите чтобы скачать.
Принудительно остановить
Не удалось обновить правила SELinux для %s
Запустить
@@ -87,14 +87,14 @@
Успешный импорт
Экспортировать в буфер обмена
Нет локальных шаблонов для экспорта!
- Шаблон с таким id уже существует!
+ Шаблон с таким ID уже существует!
Импортировать из буфера обмена
Не удалось получить список изменений: %s
Название
Неверный id шаблона
Синхронизировать онлайн-шаблоны
Создать шаблон
- только чтение
+ Только чтение
Импорт/Экспорт
Не удалось сохранить шаблон
Редактирование шаблона
@@ -123,16 +123,16 @@
%1$s образ раздела рекомендуется
Минимизировать разреженный образ
Изменить размер разреженного образа в котором находятся модули, до его фактического размера. Обратите внимание, что это может вызвать ненормальную работу модулей, поэтому используйте это только при необходимости (например, для резервного копирования)
- Удалить Временно
- Удалить KernelSU (Root и все модули) полностью и навсегда.
- Удалить Навсегда
+ Удалить на время
+ Удалить KernelSU (Root и все модули) полностью.
+ Удалить полностью
Временно удалить KernelSU, восстановить исходное состояние после следующей перезагрузки.
Удалить
- Восстановить Сток образ
- Восстановить стоковый заводской образ (если существует резервная копия), обычно используется перед OTA; если вам нужно удалить KernelSU, используйте «Удалить Навсегда».
+ Восстановить сток образ
+ Восстановить исходный заводской образ (если существует резервная копия), обычно используется перед OTA; если вам нужно удалить KernelSU, используйте «Удалить полностью».
Установка выполнена
Установка
Установка не выполнена
- Выбран lkm: %s
- Сохранить Журналы
+ Выбран LKM: %s
+ Сохранить логи
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-th/strings.xml b/manager/app/src/main/res/values-th/strings.xml
index 50bb145e5b0a..d903b62bc113 100644
--- a/manager/app/src/main/res/values-th/strings.xml
+++ b/manager/app/src/main/res/values-th/strings.xml
@@ -4,8 +4,8 @@
ยังไม่ได้ติดตั้ง
กดเพื่อติดตั้ง
กำลังทำงาน
- เวอร์ชั่น: %d
- เวอร์ชั่นตัวจัดการ
+ เวอร์ชัน: %d
+ เวอร์ชันตัวจัดการ
สิทธิ์ผู้ใช้ขั้นสูง: %d
โมดูล: %d
ไม่รองรับ
@@ -35,17 +35,17 @@
รีบูตเข้าสู่โหมด EDL
%s ถอนการติดตั้งสำเร็จ
ล้มเหลวในการถอนการติดตั้ง: %s
- overlayfs ไม่สามารถใช้งานได้ โมดูลหยุดทำงาน!
+ โมดูลไม่สามารถใช้งานได้เนื่องจาก OverlayFS ถูกปิดใช้งานโดยเคอร์เนล
คุณแน่ใจว่าจะถอนการติดตั้งโมดูล %s หรือไม่\?
ผู้สร้าง
- เวอร์ชั่น
+ เวอร์ชัน
แสดงแอประบบ
ซ่อนแอประบบ
รีเฟรช
- ส่งรายงาน Log
+ ส่ง logs
โหมดปลอดภัย
รีบูตเพื่อให้มีผล
- โมดูลถูกปิดใช้งานเนื่องจากขัดแย้งกับ Magisk!
+ โมดูลไม่สามารถใช้งานได้ เนื่องจากขัดแย้งกับ Magisk!
เรียนรู้เกี่ยวกับ KernelSU
https://kernelsu.org/guide/what-is-kernelsu.html
เรียนรู้วิธีการติดตั้ง KernelSU และวิธีใช้งานโมดูลต่าง ๆ
@@ -62,7 +62,7 @@
ส่วนบุคคล
หมวดหมู่
ความสามารถของแอป
- การเปิดใช้งานตัวเลือกนี้จะทำให้ KernelSU สามารถกู้คืนไฟล์ที่แก้ไขโดยโมดูลสำหรับแอปพลิเคชั่นนี้ได้
+ การเปิดใช้งานตัวเลือกนี้จะทำให้ KernelSU สามารถกู้คืนไฟล์ที่แก้ไขโดยโมดูลสำหรับแอปนี้ได้
บริบท SELinux
Umount โมดูล
ไม่สามารถอัปเดตโปรไฟล์แอปสำหรับ %s ได้
@@ -72,13 +72,13 @@
กฎ
กำลังดาวน์โหลดโมดูล: %s
กำลังเริ่มดาวน์โหลด: %s
- เวอร์ชั่นใหม่: %s พร้อมใช้งาน โปรดคลิกเพื่ออัปเกรด
+ เวอร์ชันใหม่: %s พร้อมใช้งาน คลิกเพื่ออัปเกรด
บังคับหยุด
รีสตาร์ท
- หากเปิดใช้งานค่าเริ่มต้นโดยทั่วไปสำหรับ \"Umount โมดูล\" ในโปรไฟล์แอป จะเป็นการลบการแก้ไขโมดูลทั้งหมดในระบบสำหรับแอปพลิเคชั่นที่ไม่มีการตั้งค่าโปรไฟล์
+ หากเปิดใช้งานค่าเริ่มต้นโดยทั่วไปสำหรับ \"Umount โมดูล\" ในโปรไฟล์แอป จะเป็นการลบการแก้ไขโมดูลทั้งหมดในระบบสำหรับแอปพลิเคชันที่ไม่มีการตั้งค่าโปรไฟล์
เปิด
ไม่สามารถอัปเดตกฎ SElinux สำหรับ: %s ได้
- KernelSU เวอร์ชั่น %d ต่ำเกินไป ทำให้ตัวจัดการไม่สามารถใช้งานได้อย่างถูกต้อง โปรดอัปเกรดเป็นเวอร์ชั่น %d หรือที่สูงกว่า!
+ KernelSU เวอร์ชัน %d ต่ำเกินไป ทำให้ตัวจัดการไม่สามารถทำงานได้อย่างถูกต้อง โปรดอัปเกรดเป็นเวอร์ชัน %d หรือสูงกว่า!
บันทึกการเปลี่ยนแปลง
นำเข้าเสร็จสิ้น
ส่งออกไปยังคลิปบอร์ด
@@ -125,7 +125,7 @@
กำลังแฟลช
แฟลชสำเร็จ
แฟลชล้มเหลว
- เลือก lkm: %s
+ เลือก LKM: %s
ถอนการติดตั้ง
ถอนการติดตั้งชั่วคราว
การถอนการติดตั้ง KernelSU (การรูทและโมดูลทั้งหมด) อย่างสมบูรณ์โดยถาวร
diff --git a/manager/app/src/main/res/values-tr/strings.xml b/manager/app/src/main/res/values-tr/strings.xml
index ed0bcd0f0d40..7d87c4feab90 100644
--- a/manager/app/src/main/res/values-tr/strings.xml
+++ b/manager/app/src/main/res/values-tr/strings.xml
@@ -39,14 +39,14 @@
Kaldırma başarısız: %s
Sürüm
Geliştirici
- overlayfs mevcut değil, modül çalışamaz!
+ OverlayFS çekirdek tarafından devre dışı bırakıldığı için modüller kullanılamıyor.
Yenile
Sistem uygulamalarını göster
Sistem uygulamalarını gizle
- Günlük raporu gönder
+ Günlükleri gönder
Güvenli mod
Değişikliklerin uygulanması için cihazı yeniden başlat
- Modüller, Magisk\'tekiler ile çakıştığı için devre dışı bırakıldı!
+ Magisk ile çakışma nedeniyle modüller kullanılamıyor!
KernelSU\'yu öğrenin
https://kernelsu.org/guide/what-is-kernelsu.html
KernelSU\'nun nasıl kurulacağını ve modüllerin nasıl kullanılacağını öğrenin
@@ -76,7 +76,7 @@
Güncelle
Modül indiriliyor: %s
İndirme başladı: %s
- Yeni sürüm: %s mevcut, güncellemek için tıklayın
+ Yeni sürüm: %s var, güncellemek için tıklayın.
Uygulamayı başlat
Uygulamayı durmaya zorla
Uygulamayı yeniden başlat
@@ -93,8 +93,8 @@
Kaydet
Sil
Şablonu görüntüle
- salt okunur
- Şablon kimliği zaten mevcut!
+ Salt okunur
+ Şablon kimliği zaten var!
İçe aktar/Dışa aktar
Panodan içe aktar
Panodan dışa aktar
@@ -108,11 +108,11 @@
Uygulamayı açarken güncellemeleri otomatik denetle
Root izni verilemedi!
Aç
- Web Görünümü Hata Ayıklamasını Etkinleştir
+ Web görünümü hata ayıklamasını etkinleştir
Web kullanıcı arayüzünde hata ayıklamak için kullanılabilir, lütfen yalnızca gerektiğinde etkinleştirin.
- Doğrudan Kur (Tavsiye Edilen)
- Bir Dosya Seçin
- Etkin Olmayan Yuvaya Kur (OTA\'dan Sonra)
+ Doğrudan kur (Tavsiye edilen)
+ Bir dosya seçin
+ Etkin olmayan yuvaya kur (OTA\'dan sonra)
Cihazınız geçerli etkin olmayan yuvaya **ZORLA** yeniden başlatılacaktır!
\nBu seçeneği yalnızca OTA tamamlandıktan sonra kullanın.
\nDevam edilsin mi?
@@ -120,16 +120,16 @@
KMI seçin
%1$s bölüm imajı önerilir
Sparse imajını küçültün
- Modülün bulunduğu sparse imajını gerçek boyutuna yeniden boyutlandırın. Bunun modülün anormal çalışmasına neden olabileceğini unutmayın, bu nedenle lütfen yalnızca gerekli olduğunda kullanın (yedekleme gibi)
- Geçici Olarak Kaldır
- Kalıcı Olarak Kaldır
- Stok İmajı Geri Yükle
+ Modülün bulunduğu sparse imajını gerçek boyutuna yeniden boyutlandırın. Bunun modülün anormal çalışmasına neden olabileceğini unutmayın, bu nedenle lütfen yalnızca gerekli olduğunda kullanın (yedekleme gibi).
+ Geçici olarak kaldır
+ Kalıcı olarak kaldır
+ Stok imajı geri yükle
KernelSU\'yu geçici olarak kaldır, bir sonraki yeniden başlatmadan sonra orijinal durumuna geri yükle.
Kaldır
KernelSU (Root ve tüm modüller) tamamen ve kalıcı olarak kaldırılıyor.
- Stok fabrika imajını geri yükler (eğer yedek varsa), genellikle OTA\'dan önce kullanılır; KernelSU\'yu kaldırmanız gerekiyorsa, lütfen \"Kalıcı Olarak Kaldır\" seçeneğini kullanın.
+ Stok fabrika imajını geri yükler (eğer yedek varsa), genellikle OTA\'dan önce kullanılır; KernelSU\'yu kaldırmanız gerekiyorsa, lütfen \"Kalıcı olarak kaldır\" seçeneğini kullanın.
Flaşlama başarılı
- Seçili lkm: %s
+ Seçili LKM: %s
Flaşlanıyor
Flaşlama başarısız
Günlükleri Kaydet
diff --git a/manager/app/src/main/res/values-v27/themes.xml b/manager/app/src/main/res/values-v27/themes.xml
deleted file mode 100644
index 325416c0d9c2..000000000000
--- a/manager/app/src/main/res/values-v27/themes.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml
index e854fb60bcd1..950c69e5c257 100644
--- a/manager/app/src/main/res/values-zh-rCN/strings.xml
+++ b/manager/app/src/main/res/values-zh-rCN/strings.xml
@@ -37,14 +37,14 @@
卸载失败: %s
版本
作者
- 内核不支持 overlayfs,模块功能无法运作!
+ OverlayFS被内核禁用,模块不可用。
刷新
显示系统应用
隐藏系统应用
发送日志
安全模式
重启生效
- 所有模块已被禁用,因为它与 Magisk 的模块系统有冲突!
+ 因与Magisk有冲突,所有模块不可用!
模块数:%d
了解 KernelSU
https://kernelsu.org/zh_CN/guide/what-is-kernelsu.html
@@ -74,7 +74,7 @@
更新
正在下载模块:%s
开始下载:%s
- 发现新版本:%s,点击升级
+ 发现新版本:%s,点击升级。
启动
强制停止
重新启动
@@ -105,6 +105,7 @@
检查更新
在应用启动后自动检查是否有最新版
获取 root 失败!
+ 执行
打开
启用 WebView 调试
可用于调试 WebUI ,请仅在需要时启用。
diff --git a/manager/app/src/main/res/values/colors.xml b/manager/app/src/main/res/values/colors.xml
new file mode 100644
index 000000000000..a5b623aa4885
--- /dev/null
+++ b/manager/app/src/main/res/values/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml
index d094969af1a2..2df83a821ead 100644
--- a/manager/app/src/main/res/values/strings.xml
+++ b/manager/app/src/main/res/values/strings.xml
@@ -11,17 +11,17 @@
Unsupported
KernelSU only supports GKI kernels now
Kernel
- Manager Version
+ Manager version
Fingerprint
SELinux status
Disabled
Enforcing
Permissive
Unknown
- SuperUser
+ Superuser
Failed to enable module: %s
Failed to disable module: %s
- No installed modules
+ No module installed
Module
Uninstall
Install
@@ -35,18 +35,21 @@
Reboot to EDL
About
Are you sure you want to uninstall module %s?
- %s is uninstalled
+ %s uninstalled
Failed to uninstall: %s
Version
Author
- overlayfs is not available, module cannot work!
+ Modules are unavailable as OverlayFS is disabled by the kernel.
Refresh
Show system apps
Hide system apps
- Report Log
+ Send logs
Safe mode
Reboot to take effect
- Modules are disabled because it is conflict with Magisk\'s!
+ Modules are unavailable due to a conflict with Magisk!
+ 🚨 Unofficial Build ⁽ˣˣ⁾
+ https://github.com/tiann/KernelSU/issues/1705
+ Non-GKI support ended; see announcement.
Learn KernelSU
https://kernelsu.org/guide/what-is-kernelsu.html
Learn how to install KernelSU and use modules
@@ -67,38 +70,38 @@
SELinux context
Umount modules
Failed to update App Profile for %s
- The current KernelSU version %d is too low for the manager to function properly. Please upgrade to version %d or higher!
+ The current KernelSU version %d is too low for the manager to work properly. Please upgrade to version %d or higher!
Umount modules by default
- The global default value for \"Umount modules\" in App Profiles. If enabled, it will remove all module modifications to the system for applications that do not have a Profile set.
- Enabling this option will allow KernelSU to restore any modified files by the modules for this application.
+ The global default value for \"Umount modules\" in App Profile. If enabled, it will remove all module modifications to the system for apps that don\'t have a profile set.
+ Enabling this option will allow KernelSU to restore any modified files by the modules for this app.
Domain
Rules
Update
Downloading module: %s
Start downloading: %s
- New version: %s is available, click to upgrade
+ New version %s is available, click to upgrade.
Launch
- Force Stop
+ Force stop
Restart
Failed to update SELinux rules for: %s
Changelog
App Profile Template
Manage local and online template of App Profile
- Create Template
- Edit Template
- id
+ Create template
+ Edit template
+ ID
Invalid template id
Name
Description
Save
Delete
- View Template
- readonly
- template id already exists!
+ View template
+ Read only
+ Template ID already exists!
Import/Export
Import from clipboard
Export to clipboard
- Can not find local template to export!
+ Cannot find local template to export!
Imported successfully
Sync online templates
Failed to save template
@@ -107,28 +110,29 @@
Check update
Automatically check for updates when opening the app
Failed to grant root!
+ Action
Open
- Enable WebView Debugging
+ Enable WebView debugging
Can be used to debug WebUI, please enable only when needed.
- Direct Install (Recommended)
- Select a File
- Install to Inactive Slot (After OTA)
+ Direct install (Recommended)
+ Select a file
+ Install to inactive slot (After OTA)
Your device will be **FORCED** to boot to the current inactive slot after a reboot!\nOnly use this option after OTA is done.\nContinue?
Next
%1$s partition image is recommended
Select KMI
Minimize sparse image
- Resize the sparse image where the module is located to its actual size. Note that this may cause the module to work abnormally, so please only use when necessary (such as for backup)
+ Resize the sparse image where the module is located to its actual size. Note that this may cause the module to work abnormally, so please only use when necessary (Such as for backup).
Uninstall
- Uninstall Temporarily
- Uninstall Permanently
- Restore Stock Image
+ Uninstall temporarily
+ Uninstall permanently
+ Restore stock image
Temporarily uninstall KernelSU, restore to original state after next reboot.
- Uninstalling KernelSU(Root and all modules) completely and permanently.
- Restore the stock factory image (if a backup exists), usually used before OTA; if you need to uninstall KernelSU, please use \"Permanent Uninstall\".
+ Uninstalling KernelSU (Root and all modules) completely and permanently.
+ Restore the stock factory image (If a backup exists), usually used before OTA; if you need to uninstall KernelSU, please use \"Uninstall permanently\".
Flashing
Flash success
Flash failed
- Selected lkm: %s
- Save Logs
-
\ No newline at end of file
+ Selected LKM: %s
+ Save logs
+
diff --git a/manager/app/src/main/res/values/themes.xml b/manager/app/src/main/res/values/themes.xml
index 7d41d8ec77fc..31721d39e182 100644
--- a/manager/app/src/main/res/values/themes.xml
+++ b/manager/app/src/main/res/values/themes.xml
@@ -1,10 +1,13 @@
-
+
-
+
+
\ No newline at end of file
diff --git a/manager/build.gradle.kts b/manager/build.gradle.kts
index 0e503df3b636..a370a941d5ab 100644
--- a/manager/build.gradle.kts
+++ b/manager/build.gradle.kts
@@ -15,29 +15,23 @@ cmaker {
default {
arguments.addAll(
arrayOf(
- "-DANDROID_STL=c++_static",
+ "-DANDROID_STL=none",
)
)
- val flags = arrayOf(
- "-Wno-gnu-string-literal-operator-template",
- "-Wno-c++2b-extensions",
- )
- cFlags.addAll(flags)
- cppFlags.addAll(flags)
- abiFilters("arm64-v8a", "x86_64")
+ abiFilters("arm64-v8a", "x86_64", "riscv64")
}
buildTypes {
if (it.name == "release") {
- arguments += "-DDEBUG_SYMBOLS_PATH=${buildDir.absolutePath}/symbols"
+ arguments += "-DDEBUG_SYMBOLS_PATH=${layout.buildDirectory.asFile.get().absolutePath}/symbols"
}
}
}
val androidMinSdkVersion = 26
-val androidTargetSdkVersion = 34
-val androidCompileSdkVersion = 34
-val androidBuildToolsVersion = "34.0.0"
-val androidCompileNdkVersion = "26.3.11579264"
+val androidTargetSdkVersion = 35
+val androidCompileSdkVersion = 35
+val androidBuildToolsVersion = "35.0.0"
+val androidCompileNdkVersion = "27.0.12077973"
val androidSourceCompatibility = JavaVersion.VERSION_21
val androidTargetCompatibility = JavaVersion.VERSION_21
val managerVersionCode by extra(getVersionCode())
@@ -64,7 +58,7 @@ fun getGitDescribe(): String {
fun getVersionCode(): Int {
val commitCount = getGitCommitCount()
val major = 1
- return major * 10000 + commitCount + 200
+ return major * 10000 + commitCount + 194
}
fun getVersionName(): String {
@@ -85,6 +79,9 @@ subprojects {
versionCode = managerVersionCode
versionName = managerVersionName
}
+ ndk {
+ abiFilters += listOf("arm64-v8a", "x86_64", "riscv64")
+ }
}
lint {
@@ -98,4 +95,4 @@ subprojects {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/manager/dummy.keystore b/manager/dummy.keystore
new file mode 100644
index 000000000000..157df17e5f05
Binary files /dev/null and b/manager/dummy.keystore differ
diff --git a/manager/gradle/libs.versions.toml b/manager/gradle/libs.versions.toml
index 6ec08d63e90b..42e9ce44741d 100644
--- a/manager/gradle/libs.versions.toml
+++ b/manager/gradle/libs.versions.toml
@@ -1,21 +1,20 @@
[versions]
-agp = "8.4.1"
-kotlin = "2.0.0"
-ksp = "2.0.0-1.0.21"
-compose-bom = "2024.05.00"
-lifecycle = "2.8.0"
-accompanist = "0.34.0"
-navigation = "2.7.7"
-activity-compose = "1.9.0"
-kotlinx-coroutines = "1.8.1"
-coil-compose = "2.6.0"
-compose-destination = "1.10.2"
+agp = "8.7.1"
+kotlin = "2.0.21"
+ksp = "2.0.21-1.0.25"
+compose-bom = "2024.10.00"
+lifecycle = "2.8.6"
+navigation = "2.8.3"
+activity-compose = "1.9.3"
+kotlinx-coroutines = "1.9.0"
+coil-compose = "2.7.0"
+compose-destination = "2.1.0-beta14"
sheets-compose-dialogs = "1.3.0"
markdown = "4.6.2"
-webkit = "1.11.0"
+webkit = "1.12.1"
appiconloader-coil = "1.5.0"
parcelablelist = "2.0.1"
-libsu = "5.2.2"
+libsu = "6.0.0"
apksign = "1.4"
cmaker = "1.2"
@@ -51,14 +50,9 @@ androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "l
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
-com-google-accompanist-drawablepainter = { group = "com.google.accompanist", name = "accompanist-drawablepainter", version.ref = "accompanist" }
-com-google-accompanist-navigation-animation = { group = "com.google.accompanist", name = "accompanist-navigation-animation", version.ref = "accompanist" }
-com-google-accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanist" }
-com-google-accompanist-webview = { group = "com.google.accompanist", name = "accompanist-webview", version.ref = "accompanist" }
-
com-github-topjohnwu-libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref = "libsu" }
com-github-topjohnwu-libsu-service = { group = "com.github.topjohnwu.libsu", name = "service", version.ref = "libsu" }
-com-github-topjohnwu-libsu-io= { group = "com.github.topjohnwu.libsu", name = "io", version.ref = "libsu" }
+com-github-topjohnwu-libsu-io = { group = "com.github.topjohnwu.libsu", name = "io", version.ref = "libsu" }
dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:parcelablelist", version.ref = "parcelablelist" }
@@ -68,11 +62,13 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c
me-zhanghai-android-appiconloader-coil = { group = "me.zhanghai.android.appiconloader", name = "appiconloader-coil", version.ref = "appiconloader-coil" }
-compose-destinations-animations-core = { group = "io.github.raamcosta.compose-destinations", name = "animations-core", version.ref = "compose-destination" }
+compose-destinations-core = { group = "io.github.raamcosta.compose-destinations", name = "core", version.ref = "compose-destination" }
compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destination" }
sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets-compose-dialogs" }
sheet-compose-dialogs-list = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "list", version.ref = "sheets-compose-dialogs" }
sheet-compose-dialogs-input = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "input", version.ref = "sheets-compose-dialogs" }
-markdown = { group = "io.noties.markwon", name = "core", version.ref = "markdown" }
\ No newline at end of file
+markdown = { group = "io.noties.markwon", name = "core", version.ref = "markdown" }
+
+lsposed-cxx = { module = "org.lsposed.libcxx:libcxx", version = "27.0.12077973" }
\ No newline at end of file
diff --git a/manager/gradle/wrapper/gradle-wrapper.jar b/manager/gradle/wrapper/gradle-wrapper.jar
index e6441136f3d4..2c3521197d7c 100644
Binary files a/manager/gradle/wrapper/gradle-wrapper.jar and b/manager/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/manager/gradle/wrapper/gradle-wrapper.properties b/manager/gradle/wrapper/gradle-wrapper.properties
index b82aa23a4f05..df97d72b8b91 100644
--- a/manager/gradle/wrapper/gradle-wrapper.properties
+++ b/manager/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/manager/gradlew b/manager/gradlew
index 4b6a9cfc46fa..f5feea6d6b11 100755
--- a/manager/gradlew
+++ b/manager/gradlew
@@ -1,4 +1,5 @@
#!/bin/sh
+
#
# Copyright © 2015-2021 the original authors.
#
@@ -14,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -54,7 +57,7 @@
# 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
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -83,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/manager/gradlew.bat b/manager/gradlew.bat
index 25da30dbdeee..9d21a21834d5 100644
--- a/manager/gradlew.bat
+++ b/manager/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock
index 4e0b195fb99d..d8ad1fdfb2b0 100644
--- a/userspace/ksud/Cargo.lock
+++ b/userspace/ksud/Cargo.lock
@@ -4,18 +4,18 @@ version = 3
[[package]]
name = "addr2line"
-version = "0.21.0"
+version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
-name = "adler"
-version = "1.0.2"
+name = "adler2"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "adler32"
@@ -24,24 +24,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
-name = "aes"
-version = "0.8.4"
+name = "ahash"
+version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if 1.0.0",
- "cipher",
- "cpufeatures",
+ "once_cell",
+ "version_check",
+ "zerocopy",
]
[[package]]
-name = "aho-corasick"
-version = "1.1.3"
+name = "allocator-api2"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]]
name = "android-properties"
@@ -63,14 +61,13 @@ checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
[[package]]
name = "android_logger"
-version = "0.13.3"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f"
+checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826"
dependencies = [
"android_log-sys",
- "env_logger 0.10.2",
+ "env_filter",
"log",
- "once_cell",
]
[[package]]
@@ -84,9 +81,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.14"
+version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
+checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -99,43 +96,43 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.7"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
+checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
[[package]]
name = "anstyle-parse"
-version = "0.2.4"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
-version = "1.0.3"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
-version = "3.0.3"
+version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
-version = "1.0.86"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
[[package]]
name = "arbitrary"
@@ -148,42 +145,36 @@ dependencies = [
[[package]]
name = "async-trait"
-version = "0.1.80"
+version = "0.1.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
+checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
]
[[package]]
name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "backtrace"
-version = "0.3.71"
+version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
- "cc",
"cfg-if 1.0.0",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
+ "windows-targets",
]
-[[package]]
-name = "base64ct"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
-
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -192,9 +183,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "block-buffer"
@@ -219,40 +210,17 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
-version = "1.6.0"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
-
-[[package]]
-name = "bzip2"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
-dependencies = [
- "bzip2-sys",
- "libc",
-]
-
-[[package]]
-name = "bzip2-sys"
-version = "0.1.11+1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
-]
+checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
[[package]]
name = "cc"
-version = "1.0.98"
+version = "1.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
+checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f"
dependencies = [
- "jobserver",
- "libc",
- "once_cell",
+ "shlex",
]
[[package]]
@@ -281,21 +249,11 @@ dependencies = [
"windows-targets",
]
-[[package]]
-name = "cipher"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
-dependencies = [
- "crypto-common",
- "inout",
-]
-
[[package]]
name = "clap"
-version = "4.5.4"
+version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
+checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [
"clap_builder",
"clap_derive",
@@ -303,9 +261,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.2"
+version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
+checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"anstream",
"anstyle",
@@ -315,42 +273,42 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.4"
+version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
]
[[package]]
name = "clap_lex"
-version = "0.7.0"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
+checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
-version = "1.0.1"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "const_format"
-version = "0.2.32"
+version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673"
+checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
-version = "0.2.32"
+version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500"
+checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1"
dependencies = [
"proc-macro2",
"quote",
@@ -358,26 +316,44 @@ dependencies = [
]
[[package]]
-name = "constant_time_eq"
-version = "0.1.5"
+name = "core-foundation-sys"
+version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
-name = "core-foundation-sys"
-version = "0.8.6"
+name = "core2"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
+dependencies = [
+ "memchr",
+]
[[package]]
name = "cpufeatures"
-version = "0.2.12"
+version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [
"libc",
]
+[[package]]
+name = "crc"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
[[package]]
name = "crc32fast"
version = "1.4.2"
@@ -453,11 +429,17 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "dary_heap"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728"
+
[[package]]
name = "deflate64"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d"
+checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
[[package]]
name = "deranged"
@@ -470,13 +452,13 @@ dependencies = [
[[package]]
name = "derive-new"
-version = "0.6.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad"
+checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
]
[[package]]
@@ -487,7 +469,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
]
[[package]]
@@ -498,59 +480,48 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
- "subtle",
]
[[package]]
name = "displaydoc"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
]
[[package]]
name = "either"
-version = "1.12.0"
+version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "encoding_rs"
-version = "0.8.34"
+version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "env_filter"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
-dependencies = [
- "log",
-]
-
-[[package]]
-name = "env_logger"
-version = "0.10.2"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
+checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
dependencies = [
"log",
- "regex",
]
[[package]]
name = "env_logger"
-version = "0.11.3"
+version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
+checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
dependencies = [
"env_filter",
"log",
@@ -580,7 +551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
- "windows-sys",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -604,22 +575,22 @@ dependencies = [
"libc",
]
+[[package]]
+name = "fastrand"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+
[[package]]
name = "flate2"
-version = "1.0.30"
+version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
+checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
dependencies = [
"crc32fast",
"miniz_oxide",
]
-[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -652,15 +623,25 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.28.1"
+version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
[[package]]
name = "heck"
@@ -674,15 +655,6 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-[[package]]
-name = "hmac"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
-dependencies = [
- "digest",
-]
-
[[package]]
name = "hole-punch"
version = "0.0.4-alpha.0"
@@ -702,7 +674,7 @@ version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
- "windows-sys",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -716,9 +688,9 @@ dependencies = [
[[package]]
name = "iana-time-zone"
-version = "0.1.60"
+version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
@@ -739,71 +711,51 @@ dependencies = [
[[package]]
name = "include-flate"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2e11569346406931d20276cc460215ee2826e7cad43aa986999cb244dd7adb0"
+checksum = "df49c16750695486c1f34de05da5b7438096156466e7f76c38fcdf285cf0113e"
dependencies = [
- "include-flate-codegen-exports",
+ "include-flate-codegen",
"lazy_static",
"libflate",
]
[[package]]
name = "include-flate-codegen"
-version = "0.1.4"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a7d6e1419fa3129eb0802b4c99603c0d425c79fb5d76191d5a20d0ab0d664e8"
+checksum = "8c5b246c6261be723b85c61ecf87804e8ea4a35cb68be0ff282ed84b95ffe7d7"
dependencies = [
"libflate",
- "proc-macro-hack",
"proc-macro2",
"quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "include-flate-codegen-exports"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75657043ffe3d8280f1cb8aef0f505532b392ed7758e0baeac22edadcee31a03"
-dependencies = [
- "include-flate-codegen",
- "proc-macro-hack",
+ "syn",
]
[[package]]
name = "indexmap"
-version = "2.2.6"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
- "hashbrown",
-]
-
-[[package]]
-name = "inout"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
-dependencies = [
- "generic-array",
+ "hashbrown 0.15.0",
]
[[package]]
name = "is_executable"
-version = "1.0.1"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8"
+checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2"
dependencies = [
"winapi",
]
[[package]]
name = "is_terminal_polyfill"
-version = "1.70.0"
+version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
@@ -814,28 +766,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "java-properties"
version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37bf6f484471c451f2b51eabd9e66b3fa7274550c5ec4b6c3d6070840945117f"
+source = "git+https://github.com/Kernel-SU/java-properties.git?branch=master#42a4aa941b70ded2dd3be9e9f892471023e70229"
dependencies = [
"encoding_rs",
"lazy_static",
- "regex",
-]
-
-[[package]]
-name = "jobserver"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
-dependencies = [
- "libc",
+ "regex-lite",
]
[[package]]
name = "js-sys"
-version = "0.3.69"
+version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
@@ -862,7 +804,7 @@ dependencies = [
"const_format",
"derive-new",
"encoding_rs",
- "env_logger 0.11.3",
+ "env_logger",
"extattr",
"getopts",
"hole-punch",
@@ -875,57 +817,61 @@ dependencies = [
"loopdev",
"nom",
"procfs",
- "regex",
+ "regex-lite",
"retry",
"rust-embed",
- "rustix 0.38.30",
+ "rustix 0.38.34",
"serde",
"serde_json",
"sha1",
"sha256",
- "tempdir",
+ "tempfile",
"which",
- "zip 2.1.0",
+ "zip",
"zip-extensions",
]
[[package]]
name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
-version = "0.2.155"
+version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "libflate"
-version = "1.4.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18"
+checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e"
dependencies = [
"adler32",
+ "core2",
"crc32fast",
+ "dary_heap",
"libflate_lz77",
]
[[package]]
name = "libflate_lz77"
-version = "1.2.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf"
+checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d"
dependencies = [
+ "core2",
+ "hashbrown 0.14.5",
"rle-decode-fast",
]
[[package]]
name = "libm"
-version = "0.2.8"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
+checksum = "a00419de735aac21d53b0de5ce2c03bd3627277cf471300f27ebc89f7d828047"
[[package]]
name = "linux-raw-sys"
@@ -941,9 +887,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
[[package]]
name = "log"
-version = "0.4.21"
+version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "loopdev"
@@ -954,11 +900,21 @@ dependencies = [
"libc",
]
+[[package]]
+name = "lzma-rs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
+dependencies = [
+ "byteorder",
+ "crc",
+]
+
[[package]]
name = "memchr"
-version = "2.7.2"
+version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memmap"
@@ -978,11 +934,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
-version = "0.7.3"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
dependencies = [
- "adler",
+ "adler2",
]
[[package]]
@@ -1012,53 +968,24 @@ dependencies = [
[[package]]
name = "object"
-version = "0.32.2"
+version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
-version = "1.19.0"
+version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
-name = "password-hash"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
-dependencies = [
- "base64ct",
- "rand_core 0.6.4",
- "subtle",
-]
-
-[[package]]
-name = "pbkdf2"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
-dependencies = [
- "digest",
- "hmac",
- "password-hash",
- "sha2",
-]
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "pin-project-lite"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.30"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]]
name = "powerfmt"
@@ -1068,73 +995,56 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
-version = "0.2.17"
+version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.20+deprecated"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
[[package]]
name = "proc-macro2"
-version = "1.0.83"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
+checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "procfs"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
+checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
dependencies = [
- "bitflags 2.5.0",
+ "bitflags 2.6.0",
"chrono",
"flate2",
"hex",
- "lazy_static",
"procfs-core",
- "rustix 0.38.34",
+ "rustix 0.38.38",
]
[[package]]
name = "procfs-core"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
+checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
dependencies = [
- "bitflags 2.5.0",
+ "bitflags 2.6.0",
"chrono",
"hex",
]
[[package]]
name = "quote"
-version = "1.0.36"
+version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
-[[package]]
-name = "rand"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
-dependencies = [
- "fuchsia-cprng",
- "libc",
- "rand_core 0.3.1",
- "rdrand",
- "winapi",
-]
-
[[package]]
name = "rand"
version = "0.8.5"
@@ -1143,7 +1053,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
- "rand_core 0.6.4",
+ "rand_core",
]
[[package]]
@@ -1153,24 +1063,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
- "rand_core 0.6.4",
+ "rand_core",
]
-[[package]]
-name = "rand_core"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
-dependencies = [
- "rand_core 0.4.2",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
-
[[package]]
name = "rand_core"
version = "0.6.4"
@@ -1201,51 +1096,10 @@ dependencies = [
]
[[package]]
-name = "rdrand"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
-dependencies = [
- "rand_core 0.3.1",
-]
-
-[[package]]
-name = "regex"
-version = "1.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
-
-[[package]]
-name = "remove_dir_all"
-version = "0.5.3"
+name = "regex-lite"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
-dependencies = [
- "winapi",
-]
+checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
[[package]]
name = "retry"
@@ -1253,7 +1107,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4"
dependencies = [
- "rand 0.8.5",
+ "rand",
]
[[package]]
@@ -1264,9 +1118,9 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
[[package]]
name = "rust-embed"
-version = "8.4.0"
+version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a"
+checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
dependencies = [
"include-flate",
"rust-embed-impl",
@@ -1276,22 +1130,22 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
-version = "8.4.0"
+version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4"
+checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
- "syn 2.0.65",
+ "syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
-version = "8.4.0"
+version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32"
+checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
dependencies = [
"sha2",
"walkdir",
@@ -1305,29 +1159,29 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustix"
-version = "0.38.30"
-source = "git+https://github.com/Kernel-SU/rustix.git?branch=main#0e270bce2d97466be6b987bb5f7ea5b1e8d84969"
+version = "0.38.34"
+source = "git+https://github.com/Kernel-SU/rustix.git?branch=main#4a53fbc7cb7a07cabe87125cc21dbc27db316259"
dependencies = [
- "bitflags 2.5.0",
+ "bitflags 2.6.0",
"errno 0.3.9",
"itoa",
"libc",
"linux-raw-sys",
"once_cell",
- "windows-sys",
+ "windows-sys 0.52.0",
]
[[package]]
name = "rustix"
-version = "0.38.34"
+version = "0.38.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
dependencies = [
- "bitflags 2.5.0",
+ "bitflags 2.6.0",
"errno 0.3.9",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -1347,31 +1201,32 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.202"
+version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
+checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.202"
+version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
+checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
]
[[package]]
name = "serde_json"
-version = "1.0.117"
+version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
+checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [
"itoa",
+ "memchr",
"ryu",
"serde",
]
@@ -1411,6 +1266,12 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
[[package]]
name = "simd-adler32"
version = "0.3.7"
@@ -1423,17 +1284,11 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-[[package]]
-name = "subtle"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
-
[[package]]
name = "syn"
-version = "1.0.109"
+version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [
"proc-macro2",
"quote",
@@ -1441,44 +1296,36 @@ dependencies = [
]
[[package]]
-name = "syn"
-version = "2.0.65"
+name = "tempfile"
+version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "tempdir"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-dependencies = [
- "rand 0.4.6",
- "remove_dir_all",
+ "cfg-if 1.0.0",
+ "fastrand",
+ "once_cell",
+ "rustix 0.38.38",
+ "windows-sys 0.59.0",
]
[[package]]
name = "thiserror"
-version = "1.0.61"
+version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
+checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.61"
+version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
+checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
]
[[package]]
@@ -1502,9 +1349,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "tokio"
-version = "1.37.0"
+version = "1.41.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
+checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
dependencies = [
"backtrace",
"bytes",
@@ -1519,33 +1366,33 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-width"
-version = "0.1.12"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-xid"
-version = "0.2.4"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "utf8parse"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "version_check"
-version = "0.9.4"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
@@ -1565,34 +1412,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.92"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
dependencies = [
"cfg-if 1.0.0",
+ "once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.92"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.92"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1600,32 +1448,32 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.92"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.65",
+ "syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.92"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
[[package]]
name = "which"
-version = "6.0.1"
+version = "6.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7"
+checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
dependencies = [
"either",
"home",
- "rustix 0.38.34",
+ "rustix 0.38.38",
"winsafe",
]
@@ -1647,11 +1495,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -1678,11 +1526,20 @@ dependencies = [
"windows-targets",
]
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
[[package]]
name = "windows-targets"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
@@ -1696,51 +1553,51 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winsafe"
@@ -1749,53 +1606,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
-name = "zip"
-version = "0.6.6"
+name = "zerocopy"
+version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
- "aes",
"byteorder",
- "bzip2",
- "constant_time_eq",
- "crc32fast",
- "crossbeam-utils",
- "flate2",
- "hmac",
- "pbkdf2",
- "sha1",
- "time",
- "zstd 0.11.2+zstd.1.5.2",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
name = "zip"
-version = "2.1.0"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2568cd0f20e86cd9a7349fe05178f7bd22f22724678448ae5a9bac266df2689"
+checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494"
dependencies = [
"arbitrary",
- "bzip2",
"crc32fast",
"crossbeam-utils",
"deflate64",
"displaydoc",
"flate2",
"indexmap",
+ "lzma-rs",
"memchr",
"thiserror",
"time",
"zopfli",
- "zstd 0.13.1",
]
[[package]]
name = "zip-extensions"
-version = "0.6.2"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cecf62554c4ff96bce01a7ef123d160c3ffe9180638820f8b4d545c65b221b8c"
+checksum = "386508a00aae1d8218b9252a41f59bba739ccee3f8e420bb90bcb1c30d960d4a"
dependencies = [
- "zip 0.6.6",
+ "zip",
]
[[package]]
@@ -1811,50 +1668,3 @@ dependencies = [
"once_cell",
"simd-adler32",
]
-
-[[package]]
-name = "zstd"
-version = "0.11.2+zstd.1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
-dependencies = [
- "zstd-safe 5.0.2+zstd.1.5.2",
-]
-
-[[package]]
-name = "zstd"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
-dependencies = [
- "zstd-safe 7.1.0",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "5.0.2+zstd.1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
-dependencies = [
- "libc",
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "7.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
-dependencies = [
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-sys"
-version = "2.0.10+zstd.1.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
-dependencies = [
- "cc",
- "pkg-config",
-]
diff --git a/userspace/ksud/Cargo.toml b/userspace/ksud/Cargo.toml
index d031660307dc..b0b00a7e1e46 100644
--- a/userspace/ksud/Cargo.toml
+++ b/userspace/ksud/Cargo.toml
@@ -2,48 +2,47 @@
name = "ksud"
version = "0.1.0"
edition = "2021"
-rust-version = "1.77.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-anyhow = "1"
-clap = { version = "4", features = ["derive"] }
+anyhow = "1.0"
+clap = { version = "4.5", features = ["derive"] }
const_format = "0.2"
-zip = { version = "2", features = [
+zip = { version = "2.2", default-features = false }
+zip-extensions = { version = "0.8", features = [
"deflate",
"deflate64",
- "bzip2",
"time",
- "zstd",
+ "lzma",
+ "xz",
], default-features = false }
-zip-extensions = "0.6"
-java-properties = "2"
+java-properties = { git = "https://github.com/Kernel-SU/java-properties.git", branch = "master", default-features = false }
log = "0.4"
env_logger = { version = "0.11", default-features = false }
-serde = { version = "1" }
-serde_json = "1"
-regex = "1"
+serde = { version = "1.0" }
+serde_json = "1.0"
encoding_rs = "0.8"
-retry = "2"
-humansize = "2"
+retry = "2.0"
+humansize = "2.1"
libc = "0.2"
-extattr = "1"
+extattr = "1.0"
jwalk = "0.8"
-is_executable = "1"
-nom = "7"
-derive-new = "0.6"
-rust-embed = { version = "8", features = [
+is_executable = "1.0"
+nom = "7.1"
+derive-new = "0.7"
+rust-embed = { version = "8.5", features = [
"debug-embed",
"compression", # must clean build after updating binaries
] }
-which = "6"
+which = "6.0"
getopts = "0.2"
sha256 = "1"
sha1 = "0.10"
-tempdir = "0.3"
+tempfile = "3.13"
chrono = "0.4"
hole-punch = { git = "https://github.com/tiann/hole-punch" }
+regex-lite = "0.1"
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies]
rustix = { git = "https://github.com/Kernel-SU/rustix.git", branch = "main", features = [
@@ -51,13 +50,14 @@ rustix = { git = "https://github.com/Kernel-SU/rustix.git", branch = "main", fea
] }
# some android specific dependencies which compiles under unix are also listed here for convenience of coding
android-properties = { version = "0.2", features = ["bionic-deprecated"] }
-procfs = "0.16"
+procfs = "0.17"
loopdev = { git = "https://github.com/Kernel-SU/loopdev" }
[target.'cfg(target_os = "android")'.dependencies]
-android_logger = "0.13"
+android_logger = { version = "0.14", default-features = false }
[profile.release]
strip = true
opt-level = "z"
-lto = true
\ No newline at end of file
+lto = true
+codegen-units = 1
diff --git a/userspace/ksud/bin/aarch64/resetprop b/userspace/ksud/bin/aarch64/resetprop
index 1155e5f49a3e..305032c90dc9 100644
Binary files a/userspace/ksud/bin/aarch64/resetprop and b/userspace/ksud/bin/aarch64/resetprop differ
diff --git a/userspace/ksud/bin/x86_64/resetprop b/userspace/ksud/bin/x86_64/resetprop
index dc4d9910e9ed..80030612649b 100644
Binary files a/userspace/ksud/bin/x86_64/resetprop and b/userspace/ksud/bin/x86_64/resetprop differ
diff --git a/userspace/ksud/build.rs b/userspace/ksud/build.rs
index 021418acf722..a7db4b140504 100644
--- a/userspace/ksud/build.rs
+++ b/userspace/ksud/build.rs
@@ -15,7 +15,7 @@ fn get_git_version() -> Result<(u32, String), std::io::Error> {
.trim()
.parse()
.map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Failed to parse git count"))?;
- let version_code = 10000 + 200 + version_code; // For historical reasons
+ let version_code = 10000 + 194 + version_code; // For historical reasons
let version_name = String::from_utf8(
Command::new("git")
diff --git a/userspace/ksud/src/boot_patch.rs b/userspace/ksud/src/boot_patch.rs
index c2661c68fc76..8ce6ee73a186 100644
--- a/userspace/ksud/src/boot_patch.rs
+++ b/userspace/ksud/src/boot_patch.rs
@@ -10,6 +10,7 @@ use anyhow::bail;
use anyhow::ensure;
use anyhow::Context;
use anyhow::Result;
+use regex_lite::Regex;
use which::which;
use crate::defs;
@@ -27,7 +28,6 @@ fn ensure_gki_kernel() -> Result<()> {
#[cfg(target_os = "android")]
pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
- use regex::Regex;
let uname = rustix::system::uname();
let version = uname.release().to_string_lossy();
let re = Regex::new(r"(\d+)\.(\d+)\.(\d+)")?;
@@ -52,7 +52,6 @@ pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
#[cfg(target_os = "android")]
fn parse_kmi(version: &str) -> Result {
- use regex::Regex;
let re = Regex::new(r"(.* )?(\d+\.\d+)(\S+)?(android\d+)(.*)")?;
let cap = re
.captures(version)
@@ -97,6 +96,63 @@ pub fn get_current_kmi() -> Result {
bail!("Unsupported platform")
}
+fn parse_kmi_from_kernel(kernel: &PathBuf, workdir: &Path) -> Result {
+ use std::fs::{copy, File};
+ use std::io::{BufReader, Read};
+ let kernel_path = workdir.join("kernel");
+ copy(kernel, &kernel_path).context("Failed to copy kernel")?;
+
+ let file = File::open(&kernel_path).context("Failed to open kernel file")?;
+ let mut reader = BufReader::new(file);
+ let mut buffer = Vec::new();
+ reader
+ .read_to_end(&mut buffer)
+ .context("Failed to read kernel file")?;
+
+ let printable_strings: Vec<&str> = buffer
+ .split(|&b| b == 0)
+ .filter_map(|slice| std::str::from_utf8(slice).ok())
+ .filter(|s| s.chars().all(|c| c.is_ascii_graphic() || c == ' '))
+ .collect();
+
+ let re =
+ Regex::new(r"(?:.* )?(\d+\.\d+)(?:\S+)?(android\d+)").context("Failed to compile regex")?;
+ for s in printable_strings {
+ if let Some(caps) = re.captures(s) {
+ if let (Some(kernel_version), Some(android_version)) = (caps.get(1), caps.get(2)) {
+ let kmi = format!("{}-{}", android_version.as_str(), kernel_version.as_str());
+ return Ok(kmi);
+ }
+ }
+ }
+ println!("- Failed to get KMI version");
+ bail!("Try to choose LKM manually")
+}
+
+fn parse_kmi_from_boot(magiskboot: &Path, image: &PathBuf, workdir: &Path) -> Result {
+ let image_path = workdir.join("image");
+
+ std::fs::copy(image, &image_path).context("Failed to copy image")?;
+
+ let status = Command::new(magiskboot)
+ .current_dir(workdir)
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .arg("unpack")
+ .arg(&image_path)
+ .status()
+ .context("Failed to execute magiskboot command")?;
+
+ if !status.success() {
+ bail!(
+ "magiskboot unpack failed with status: {:?}",
+ status.code().unwrap()
+ );
+ }
+
+ parse_kmi_from_kernel(&image_path, workdir)
+}
+
fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -155,7 +211,10 @@ pub fn restore(
magiskboot_path: Option,
flash: bool,
) -> Result<()> {
- let tmpdir = tempdir::TempDir::new("KernelSU").context("create temp dir failed")?;
+ let tmpdir = tempfile::Builder::new()
+ .prefix("KernelSU")
+ .tempdir()
+ .context("create temp dir failed")?;
let workdir = tmpdir.path();
let magiskboot = find_magiskboot(magiskboot_path, workdir)?;
@@ -310,13 +369,39 @@ fn do_patch(
);
}
- let tmpdir = tempdir::TempDir::new("KernelSU").context("create temp dir failed")?;
+ let tmpdir = tempfile::Builder::new()
+ .prefix("KernelSU")
+ .tempdir()
+ .context("create temp dir failed")?;
let workdir = tmpdir.path();
+ // extract magiskboot
+ let magiskboot = find_magiskboot(magiskboot_path, workdir)?;
+
let kmi = if let Some(kmi) = kmi {
kmi
} else {
- get_current_kmi().context("Unknown KMI, please choose LKM manually")?
+ match get_current_kmi() {
+ Ok(value) => value,
+ Err(e) => {
+ println!("- {}", e);
+ if let Some(image_path) = &image {
+ println!(
+ "- Trying to auto detect KMI version for {}",
+ image_path.to_str().unwrap()
+ );
+ parse_kmi_from_boot(&magiskboot, image_path, tmpdir.path())?
+ } else if let Some(kernel_path) = &kernel {
+ println!(
+ "- Trying to auto detect KMI version for {}",
+ kernel_path.to_str().unwrap()
+ );
+ parse_kmi_from_kernel(kernel_path, tmpdir.path())?
+ } else {
+ "".to_string()
+ }
+ }
+ }
};
let skip_init = kmi.starts_with("android12-");
@@ -329,9 +414,6 @@ fn do_patch(
// try extract magiskboot/bootctl
let _ = assets::ensure_binaries(false);
- // extract magiskboot
- let magiskboot = find_magiskboot(magiskboot_path, workdir)?;
-
if let Some(kernel) = kernel {
std::fs::copy(kernel, workdir.join("kernel")).context("copy kernel from failed")?;
}
@@ -558,7 +640,7 @@ fn find_boot_image(
} else {
if cfg!(not(target_os = "android")) {
println!("- Current OS is not android, refusing auto bootimage/bootdevice detection");
- bail!("please specify a boot image");
+ bail!("Please specify a boot image");
}
let mut slot_suffix =
utils::getprop("ro.boot.slot_suffix").unwrap_or_else(|| String::from(""));
diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs
index cd96a360f346..14717e62df78 100644
--- a/userspace/ksud/src/cli.rs
+++ b/userspace/ksud/src/cli.rs
@@ -223,6 +223,12 @@ enum Module {
id: String,
},
+ /// run action for module
+ Action {
+ // module id
+ id: String,
+ },
+
/// list all modules
List,
@@ -306,6 +312,7 @@ pub fn run() -> Result<()> {
Module::Uninstall { id } => module::uninstall_module(&id),
Module::Enable { id } => module::enable_module(&id),
Module::Disable { id } => module::disable_module(&id),
+ Module::Action { id } => module::run_action(&id),
Module::List => module::list_modules(),
Module::Shrink => module::shrink_ksu_images(),
}
diff --git a/userspace/ksud/src/defs.rs b/userspace/ksud/src/defs.rs
index c4b9fc3f989b..ae9dfaa53218 100644
--- a/userspace/ksud/src/defs.rs
+++ b/userspace/ksud/src/defs.rs
@@ -32,6 +32,7 @@ pub const TEMP_DIR: &str = "/debug_ramdisk";
pub const TEMP_DIR_LEGACY: &str = "/sbin";
pub const MODULE_WEB_DIR: &str = "webroot";
+pub const MODULE_ACTION_SH: &str = "action.sh";
pub const DISABLE_FILE_NAME: &str = "disable";
pub const UPDATE_FILE_NAME: &str = "update";
pub const REMOVE_FILE_NAME: &str = "remove";
diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs
index ac3ff213b62f..28c5df405795 100644
--- a/userspace/ksud/src/module.rs
+++ b/userspace/ksud/src/module.rs
@@ -570,6 +570,11 @@ pub fn uninstall_module(id: &str) -> Result<()> {
})
}
+pub fn run_action(id: &str) -> Result<()> {
+ let action_script_path = format!("/data/adb/modules/{}/action.sh", id);
+ exec_script(&action_script_path, true)
+}
+
fn _enable_module(module_dir: &str, mid: &str, enable: bool) -> Result<()> {
let src_module_path = format!("{module_dir}/{mid}");
let src_module = Path::new(&src_module_path);
@@ -668,11 +673,13 @@ fn _list_modules(path: &str) -> Vec> {
let update = path.join(defs::UPDATE_FILE_NAME).exists();
let remove = path.join(defs::REMOVE_FILE_NAME).exists();
let web = path.join(defs::MODULE_WEB_DIR).exists();
+ let action = path.join(defs::MODULE_ACTION_SH).exists();
module_prop_map.insert("enabled".to_owned(), enabled.to_string());
module_prop_map.insert("update".to_owned(), update.to_string());
module_prop_map.insert("remove".to_owned(), remove.to_string());
module_prop_map.insert("web".to_owned(), web.to_string());
+ module_prop_map.insert("action".to_owned(), action.to_string());
if result.is_err() {
warn!("Failed to parse module.prop: {}", module_prop.display());
diff --git a/userspace/ksud/src/sepolicy.rs b/userspace/ksud/src/sepolicy.rs
index 581c416a8185..b7286a06a769 100644
--- a/userspace/ksud/src/sepolicy.rs
+++ b/userspace/ksud/src/sepolicy.rs
@@ -11,7 +11,7 @@ use nom::{
sequence::Tuple,
IResult, Parser,
};
-use std::{path::Path, vec};
+use std::{ffi, path::Path, vec};
type SeObject<'a> = Vec<&'a str>;
@@ -352,10 +352,11 @@ where
let mut statements = vec![];
for line in input.split(['\n', ';']) {
- if line.trim().is_empty() {
+ let trimmed_line = line.trim();
+ if trimmed_line.is_empty() || trimmed_line.starts_with('#') {
continue;
}
- if let Ok((_, statement)) = PolicyStatement::parse(line.trim()) {
+ if let Ok((_, statement)) = PolicyStatement::parse(trimmed_line) {
statements.push(statement);
} else if strict {
bail!("Failed to parse policy statement: {}", line)
@@ -659,19 +660,19 @@ impl<'a> TryFrom<&'a PolicyStatement<'a>> for Vec {
struct FfiPolicy {
cmd: u32,
subcmd: u32,
- sepol1: *const libc::c_char,
- sepol2: *const libc::c_char,
- sepol3: *const libc::c_char,
- sepol4: *const libc::c_char,
- sepol5: *const libc::c_char,
- sepol6: *const libc::c_char,
- sepol7: *const libc::c_char,
+ sepol1: *const ffi::c_char,
+ sepol2: *const ffi::c_char,
+ sepol3: *const ffi::c_char,
+ sepol4: *const ffi::c_char,
+ sepol5: *const ffi::c_char,
+ sepol6: *const ffi::c_char,
+ sepol7: *const ffi::c_char,
}
-fn to_c_ptr(pol: &PolicyObject) -> *const libc::c_char {
+fn to_c_ptr(pol: &PolicyObject) -> *const ffi::c_char {
match pol {
PolicyObject::None | PolicyObject::All => std::ptr::null(),
- PolicyObject::One(s) => s.as_ptr().cast::(),
+ PolicyObject::One(s) => s.as_ptr().cast::(),
}
}
diff --git a/userspace/ksud/src/su.rs b/userspace/ksud/src/su.rs
index b19bf7a21ca1..7884137e7ef2 100644
--- a/userspace/ksud/src/su.rs
+++ b/userspace/ksud/src/su.rs
@@ -19,30 +19,16 @@ use rustix::{
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn grant_root(global_mnt: bool) -> Result<()> {
- const KERNEL_SU_OPTION: u32 = 0xDEAD_BEEF;
- const CMD_GRANT_ROOT: u64 = 0;
-
- let mut result: u32 = 0;
- unsafe {
- #[allow(clippy::cast_possible_wrap)]
- libc::prctl(
- KERNEL_SU_OPTION as i32, // supposed to overflow
- CMD_GRANT_ROOT,
- 0,
- 0,
- std::ptr::addr_of_mut!(result).cast::(),
- );
- }
+ rustix::process::ksu_grant_root()?;
- anyhow::ensure!(result == KERNEL_SU_OPTION, "grant root failed");
- let mut command = std::process::Command::new("sh");
+ let mut command = Command::new("sh");
let command = unsafe {
command.pre_exec(move || {
if global_mnt {
let _ = utils::switch_mnt_ns(1);
let _ = utils::unshare_mnt_ns();
}
- std::result::Result::Ok(())
+ Result::Ok(())
})
};
// add /data/adb/ksu/bin to PATH
@@ -64,7 +50,7 @@ fn print_usage(program: &str, opts: Options) {
fn set_identity(uid: u32, gid: u32, groups: &[u32]) {
#[cfg(any(target_os = "linux", target_os = "android"))]
{
- rustix::process::set_groups(
+ rustix::thread::set_thread_groups(
groups
.iter()
.map(|g| unsafe { Gid::from_raw(*g) })
@@ -89,7 +75,7 @@ pub fn root_shell() -> Result<()> {
// we are root now, this was set in kernel!
use anyhow::anyhow;
- let env_args: Vec = std::env::args().collect();
+ let env_args: Vec = env::args().collect();
let program = env_args[0].clone();
let args = env_args
.iter()
@@ -154,7 +140,7 @@ pub fn root_shell() -> Result<()> {
.collect::>();
let matches = match opts.parse(&args[1..]) {
- std::result::Result::Ok(m) => m,
+ Result::Ok(m) => m,
Err(f) => {
println!("{f}");
print_usage(&program, opts);
@@ -282,7 +268,7 @@ pub fn root_shell() -> Result<()> {
set_identity(uid, gid, &groups);
- std::result::Result::Ok(())
+ Result::Ok(())
})
};
diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs
index 9bacfa366496..f7e695507be1 100644
--- a/userspace/ksud/src/utils.rs
+++ b/userspace/ksud/src/utils.rs
@@ -206,7 +206,7 @@ fn find_temp_path() -> String {
}
// Try to create a random directory in /dev/
- let r = tempdir::TempDir::new_in("/dev/", "");
+ let r = tempfile::tempdir_in("/dev/");
match r {
Ok(tmp_dir) => {
if let Some(path) = tmp_dir.into_path().to_str() {
diff --git a/website/docs/.vitepress/locales/zh_TW.ts b/website/docs/.vitepress/locales/zh_TW.ts
index 3a92d45b2cf7..5d6fd9e8f14e 100644
--- a/website/docs/.vitepress/locales/zh_TW.ts
+++ b/website/docs/.vitepress/locales/zh_TW.ts
@@ -6,7 +6,7 @@ const pkg = require('vitepress/package.json')
export default defineConfig({
lang: 'zh-TW',
- description: '一個以核心為基礎,適用於 Android GKI 的 Root 解決方案。',
+ description: '一個基於核心,適用於 Android GKI 的 Root 解決方案。',
themeConfig: {
nav: nav(),
diff --git a/website/docs/guide/how-to-integrate-for-non-gki.md b/website/docs/guide/how-to-integrate-for-non-gki.md
index 242246a5c360..b4e6c80253f6 100644
--- a/website/docs/guide/how-to-integrate-for-non-gki.md
+++ b/website/docs/guide/how-to-integrate-for-non-gki.md
@@ -22,7 +22,7 @@ curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh
```
:::info
-[KernelSU 1.0 no longer supports non-GKI kernels](https://github.com/tiann/KernelSU/issues/1705). The last supported version is `v0.9.5`, please make sure to use the correct branch.
+[KernelSU 1.0 and later versions no longer support non-GKI kernels](https://github.com/tiann/KernelSU/issues/1705). The last supported version is `v0.9.5`, please make sure to use the correct version.
:::
Then, you should check if *kprobe* is enabled in your kernel config, if it is not, please add these configs to it:
@@ -55,22 +55,10 @@ If kprobe does not work in your kernel (may be an upstream or kernel bug below 4
First, add KernelSU to your kernel source tree:
-::: code-group
-
-```sh[Latest tag(stable)]
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
-```
-
-```sh[ main branch(dev)]
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
-```
-
-```sh[Select tag(Such as v0.5.2)]
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
+```sh
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
```
-:::
-
Keep in mind that on some devices, your defconfig may be in `arch/arm64/configs` or in other cases `arch/arm64/configs/vendor/your_defconfig`. For whichever defconfig you're using, make sure to enable `CONFIG_KSU` with `y` to enable or `n` to disable it. For example, in case you chose to enable it, you defconfig should contain the following string:
```txt
diff --git a/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md b/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md
index 11bd7905e9ba..d26d3c62ceea 100644
--- a/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md
+++ b/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md
@@ -17,23 +17,13 @@ KernelSU menggunakan kprobe untuk melakukan hook kernel, jika *kprobe* berjalan
Pertama, tambahkan KernelSU ke dalam berkas kernel source tree:
-- Latest tag(stable)
-
-```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
-```
-
-- main branch(dev)
-
```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
```
-- Select tag(Such as v0.5.2)
-
-```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
-```
+:::info
+[KernelSU 1.0 dan versi yang lebih baru tidak lagi mendukung kernel non-GKI](https://github.com/tiann/KernelSU/issues/1705). Versi terakhir yang didukung adalah `v0.9.5`, pastikan untuk menggunakan versi yang benar.
+:::
Kemudian, Anda harus memeriksa apakah *kprobe* diaktifkan dalam konfigurasi kernel Anda, jika tidak, tambahkan konfigurasi ini ke dalamnya:
@@ -56,7 +46,7 @@ Jika kprobe tidak dapat bekerja pada kernel Anda (mungkin karena bug di upstream
Pertama, tambahkan KernelSU ke dalam direktori kernel source tree:
```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
```
Kemudian, tambahkan panggilan KernelSU ke source kernel, berikut ini adalah patch yang dapat dirujuk:
diff --git a/website/docs/pt_BR/guide/how-to-integrate-for-non-gki.md b/website/docs/pt_BR/guide/how-to-integrate-for-non-gki.md
index e880f99b1ea2..1652a00d1a72 100644
--- a/website/docs/pt_BR/guide/how-to-integrate-for-non-gki.md
+++ b/website/docs/pt_BR/guide/how-to-integrate-for-non-gki.md
@@ -18,9 +18,13 @@ O KernelSU usa kprobe para fazer ganchos do kernel, se o kprobe funcionar bem em
Primeiro, adicione o KernelSU à árvore de origem do kernel:
```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
```
+:::info INFORMAÇÕES
+[KernelSU 1.0 e versões posteriores não suportam mais kernels não GKI](https://github.com/tiann/KernelSU/issues/1705). A última versão suportada é a `v0.9.5`, por favor, certifique-se de usar a versão correta.
+:::
+
Então, você deve verificar se o kprobe está ativado na configuração do seu kernel, se não estiver, adicione estas configurações a ele:
```txt
@@ -51,22 +55,10 @@ Se o kprobe não funcionar no seu kernel (pode ser um bug do upstream ou do kern
Primeiro, adicione o KernelSU à árvore de origem do kernel:
-::: code-group
-
-```sh[Tag mais recente (estável)]
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
-```
-
-```sh[Branch principal (dev)]
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
-```
-
-```sh[Selecionar tag (como v0.5.2)]
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
+```sh
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
```
-:::
-
Tenha em mente que em alguns dispositivos, seu defconfig pode estar em `arch/arm64/configs` ou em outros casos `arch/arm64/configs/vendor/your_defconfig`. Para qualquer defconfig que você estiver usando, certifique-se de ativar `CONFIG_KSU` com `y` para ativa-lo ou `n` para desativa-lo. Por exemplo, caso você opte por ativa-lo, seu defconfig deverá conter a seguinte string:
```txt
diff --git a/website/docs/public/templates/kernelmanager.root b/website/docs/public/templates/kernelmanager.root
index 899e0d64e05d..3973dd1d5972 100644
--- a/website/docs/public/templates/kernelmanager.root
+++ b/website/docs/public/templates/kernelmanager.root
@@ -10,13 +10,10 @@
"READPROC"
],
"capabilities":[
- "CAP_SYS_MODULE",
- "CAP_SYS_NICE",
- "CAP_SYS_RESOURCE",
"CAP_KILL",
"CAP_SYSLOG",
- "CAP_PERFMON",
- "CAP_SYS_BOOT"
+ "CAP_SYS_BOOT",
+ "CAP_DAC_OVERRIDE"
],
"context":"u:r:su:s0",
"namespace":"INHERITED",
diff --git a/website/docs/repos.json b/website/docs/repos.json
index 6ae95b901627..aabacea7420e 100644
--- a/website/docs/repos.json
+++ b/website/docs/repos.json
@@ -54,7 +54,7 @@
"kernel_name": "android_kernel_xiaomi_onc",
"kernel_link": "https://github.com/hadadarjt/android_kernel_xiaomi_onc/tree/los21-KSU/local-non-gerrit-review",
"devices": "Redmi 7: onclite | Redmi Y3: onc"
- },
+ },
{
"maintainer": "HMTheBoy154",
"maintainer_link": "https://github.com/hmtheboy154",
@@ -691,5 +691,40 @@
"kernel_name": "kernel_xiaomi_chopin",
"kernel_link": "https://github.com/ChopinKernels/kernel_xiaomi_chopin_android_S",
"devices": "Redmi Note 10 Pro 5G (chopin) / Poco X3 GT (choping)"
+ },
+ {
+ "maintainer": "Fede2782",
+ "maintainer_link": "https://github.com/Fede2782",
+ "kernel_name": "android_kernel_motorola_sdm632",
+ "kernel_link": "https://github.com/Fede2782/android_kernel_motorola_sdm632",
+ "devices": "Motorola Moto G7 (river)"
+ },
+ {
+ "maintainer": "EmanuelCN",
+ "maintainer_link": "https://github.com/EmanuelCN",
+ "kernel_name": "N0Kernel",
+ "kernel_link": "https://github.com/EmanuelCN/kernel_xiaomi_sm8250",
+ "devices": "Poco F3 (alioth) | Mi 10T/Pro (apollo) | Poco F4 (munch)"
+ },
+ {
+ "maintainer": "kvsnr113",
+ "maintainer_link": "https://github.com/kvsnr113",
+ "kernel_name": "NOVA Kernel",
+ "kernel_link": "https://github.com/kvsnr113/xiaomi_sm8250_kernel",
+ "devices": "Poco F3 (alioth) | Mi 10T/Pro (apollo) | Poco F4 (munch)"
+ },
+ {
+ "maintainer": "anVzdGFtb25",
+ "maintainer_link": "https://github.com/anVzdGFtb25",
+ "kernel_name": "android_kernel_xiaomi_mt6768",
+ "kernel_link": "https://github.com/anVzdGFtb25/android_kernel_xiaomi_mt6768",
+ "devices": "Redmi 9 ( lancelot )"
+ },
+ {
+ "maintainer": "rifsxd",
+ "maintainer_link": "https://github.com/rifsxd",
+ "kernel_name": "android_kernel_realme_RMX3511",
+ "kernel_link": "https://github.com/rifsxd/android_kernel_realme_RMX3511",
+ "devices": "Realme C35 (RMX3511)"
}
]
diff --git a/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md b/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md
index 60668221bef1..5f20068259fd 100644
--- a/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md
+++ b/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md
@@ -22,7 +22,7 @@ curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh
```
:::info
-[KernelSU 1.0 已经不再支持非 GKI 内核](https://github.com/tiann/KernelSU/issues/1705),最后的支持版本为 `v0.9.5`,请注意使用正确的分支。
+[KernelSU 1.0 及更高版本已经不再支持非 GKI 内核](https://github.com/tiann/KernelSU/issues/1705),最后的支持版本为 `v0.9.5`,请注意使用正确的版本。
:::
然后,你需要检查你的内核是否开启了 *kprobe* 相关的配置,如果没有开启,需要添加以下配置:
@@ -51,7 +51,7 @@ CONFIG_KPROBE_EVENTS=y
首先,把 KernelSU 添加到你的内核源码树,在内核的根目录执行以下命令:
```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
```
请注意,某些设备的defconfig文件可能在`arch/arm64/configs/设备代号_defconfig`或位于`arch/arm64/configs/vendor/设备代号_defconfig`。在您的defconfig文件中,将 `CONFIG_KSU`设置为`y`以启用KernelSU,或设置为`n`以禁用。比如在某个defconfig中:
diff --git a/website/docs/zh_CN/guide/module.md b/website/docs/zh_CN/guide/module.md
index 3690ed02915b..89dcc8e5988a 100644
--- a/website/docs/zh_CN/guide/module.md
+++ b/website/docs/zh_CN/guide/module.md
@@ -72,9 +72,9 @@ KernelSU 模块就是一个放置在 `/data/adb/modules` 内且满足如下结
│ │
│ │ *** 自动生成的目录,不要手动创建或者修改! ***
│ │
-│ ├── vendor <--- A symlink to $MODID/system/vendor
-│ ├── product <--- A symlink to $MODID/system/product
-│ ├── system_ext <--- A symlink to $MODID/system/system_ext
+│ ├── vendor <--- 如果 /system/vendor 是符号链接且存在,从 $MODID/system/vendor 移动到模块根目录
+│ ├── product <--- 如果 /system/product 是符号链接且存在,从 $MODID/system/product 移动到模块根目录
+│ ├── system_ext <--- 如果 /system/system_ext 是符号链接且存在,从 $MODID/system/system_ext 移动到模块根目录
│ │
│ │ *** Any additional files / folders are allowed ***
│ │
diff --git a/website/docs/zh_TW/guide/app-profile.md b/website/docs/zh_TW/guide/app-profile.md
index 659c5660164b..993857702927 100644
--- a/website/docs/zh_TW/guide/app-profile.md
+++ b/website/docs/zh_TW/guide/app-profile.md
@@ -2,7 +2,8 @@
App Profile 是 KernelSU 提供的一種針對各種應用程式自訂其使用配置的機制。
-對於授予了root 權限(也即可以使用 `su`)的應用程式來說,App Profile 也可以稱為Root Profile,它可以自訂 `su` 的 `uid`, `gid` , `groups` , ` capabilities` 以及 `SELinux context` 規則,從而限制 root 使用者的權限;例如可以針對防火牆應用程式僅授予網路權限,而不授予檔案存取權限,針對凍結類別應用程式僅授予 shell 權限而不是直接給 root ;透過最小化權限原則**把權力關進籠子裡**。
+對於授予了 root 權限(即可以使用 `su`)的應用程式來說,App Profile 也可以稱為 Root Profile,它可以自訂 `su` 的 `uid`、`gid`、`groups`、` capabilities` 以及 `SELinux context` 規則,從而限制 root 使用者的權限。
+例如可以針對防火牆應用程式僅授予網路權限,而不授予檔案存取權限,針對凍結類別應用程式僅授予 shell 權限而不是直接給 root ;透過最小化權限原則**把權力關進籠子裡**。
對於沒有被授予 root 權限的普通應用,App Profile 可以控制核心以及模組系統對此應用的行為;例如是否需要針對此應用程式卸載模組造成的修改等。核心和模組系統可以透過此配置決定是否要做一些類似「隱藏痕跡」類別的操作。
@@ -16,8 +17,8 @@ UID 為 0 的使用者稱為 root 使用者,GID 為 0 的群組稱為 root 群
對於 Android 系統來說,每個應用程式都是一個單獨的使用者(不考慮 share uid 的情況),擁有一個唯一的 UID。例如 `0` 是 root 使用者,`1000` 是 `system`,`2000` 是 ADB shell,10000-19999 的是一般使用者。
-:::info
-此處的 UID 跟 Android 系統的多使用者,或者說工作資料(Work Profile),不是概念。工作資料實際上是對 UID 進行分片實現的,例如 10000-19999 是主使用者,110000-119999 是工作資料;他們中的任何一個普通應用都擁有自己獨有的 UID。
+:::info 補充
+此處的 UID 跟 Android 系統的多使用者,或者說工作資料(Work Profile),是不同概念。工作資料實際上是對 UID 進行分片實現的,例如 10000-19999 是主使用者,110000-119999 是工作資料;他們中的任何一個普通應用都擁有自己獨有的 UID。
:::
每一個應用程式可以有若干個群組,GID 使其主要的群組,通常與 UID 一致;其他的群組稱為補充群組(groups)。某些權限是透過群組控制的,例如網路訪問,藍牙等。
@@ -29,7 +30,7 @@ oriole:/ $ id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),1078(ext_data_ww) (ext_obb_rw),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid),3012(readreadtracefs:s05:
```
-其中,UID 為`2000`,GID 也即主要組ID 也為`2000`;除此之外它還在許多補充組裡面,例如`inet` 組代表可以創建`AF_INET` 和`AF_INET6` 的socket(存取網路),`sdcard_rw` 代表可以讀寫sdcard 等。
+其中,UID 為`2000`,GID 也即主要組 ID 也為 `2000`;除此之外它還在許多補充組裡面,例如 `inet` 組代表可以創建 `AF_INET` 和 `AF_INET6` 的 socket(存取網路),`sdcard_rw` 代表可以讀寫 sdcard 等。
KernelSU 的 Root Profile 可以自訂執行 `su` 後 root 程式的 UID, GID 和 groups。例如,你可以設定某個 root 應用程式的Root Profile 其UID 為`2000`,這表示此應用程式在使用`su` 的時候,它的實際權限是ADB Shell 等級;你可以去掉groups 中的`inet` ,這樣這個`su` 就無法存取網路。
@@ -43,7 +44,7 @@ App Profile 只是控制 root 應用程式使用 `su` 後的權限,它並非
Capabilities 是 Linux 的一種分權機制。
-傳統的 UNIX 系統為了執行權限檢查,將流程分為兩類:特權程式(其有效使用者 ID 為 0,稱為超級使用者或 root)和非特權程式(其有效 UID 為非零)。特權程式會繞過所有核心權限檢查,而非特權程式則根據其憑證(通常是有效UID、有效GID和補充群組清單)進行完整的權限檢查。
+傳統的 UNIX 系統為了執行權限檢查,將流程分為兩類:特權程式(其等效使用者 ID 為 0,稱為超級使用者或 root)和非特權程式(其等效 UID 為非零)。特權程式會繞過所有核心權限檢查,而非特權程式則根據其憑證(通常是等校 UID、等效 GID 和補充群組清單)進行完整的權限檢查。
從 Linux 2.2開始,Linux 將傳統上與超級使用者關聯的特權分解為獨立的單元,稱為 Capabilities(有的也翻譯為「權能」),它們可以獨立啟用和停用。
@@ -52,7 +53,7 @@ Capabilities 是 Linux 的一種分權機制。
KernelSU 的 Root Profile 可以自訂執行 `su` 後 root 程式的 Capabilities,從而實現只授予「部分 root 權限」。與上面介紹的UID, GID 不同,某些 root 應用就是需要 `su` 後 UID 是 `0`,此時我們可以透過限制這個 UID 為 `0` 的 root 使用者的 Capabilities,就可以限制它能夠執行的操作。
:::tip 強烈建議
-Linux 系統關於 Capability 的[官方文件](https://man7.org/linux/man-pages/man7/capabilities.7.html),解釋了每一項Capability 所代表的能力,寫的非常詳細,如果你想要自訂Capabilities,請務必先閱讀此文件。
+Linux 的 Capability [官方文件](https://man7.org/linux/man-pages/man7/capabilities.7.html)詳細解釋了每一項 Capability 所代表的能力,如果你想要自訂Capabilities,請務必先閱讀此文件。
:::
### SELinux {#selinux}
@@ -76,7 +77,7 @@ SELinux 的完整概念比較複雜,我們這裡不打算講解它的具體運
KernelSU 的 Root Profile 可以自訂執行 `su` 後 root 程式的 SELinux context,並且可以針對這個 context 設定特定的存取控制規則,從而更精細地控制 root 權限。
-通常情況下,應用程式執行 `su` 後,會將進程切換到一個**不受任何限制** 的SELinux 域,例如`u:r:su:s0`,透過 Root Profile,我們可以將它切換到一個自訂的網域,例如 `u:r:app1:s0`,然後為這個網域制定一系列規則:
+通常情況下,應用程式執行 `su` 後,會將進程切換到一個**不受任何限制** 的 SELinux 域,例如`u:r:su:s0`,透過 Root Profile,我們可以將它切換到一個自訂的作用域,例如 `u:r:app1:s0`,然後為這個作用域制定一系列規則:
```sh
type app1
@@ -85,34 +86,34 @@ typeattribute app1 mlstrustedsubject
allow app1 * * *
```
-注意:此處的 `allow app1 * * *` 僅僅作為演示方便而使用,實際過程中不應使用這個規則,因為它跟 permissive 區別不大。
+注意:此處的 `allow app1 * * *` 僅僅作為示範方便而使用,實際過程中不應使用這個規則,因為它跟寬容模式區別不大。
### 逃逸 {#escalation}
如果 Root Profile 的配置不合理,那麼可能會發生逃逸的情況:Root Profile 的限制會意外失效。
-例如,如果你為ADB shell 使用者設定允許root 權限(這是相當常見的情況);然後你給某個普通應用程式允許root 權限,但是配置它的root profile 中的UID 為2000(ADB shell 使用者的UID);那麼此時,這個App 可以透過執行兩次 `su` 來獲得完整的root 權限:
+例如,如果你為ADB shell 使用者設定允許root 權限(這是相當常見的情況);然後你給某個普通應用程式允許 root 權限,但是配置它的 root profile 中的 UID 為 2000(ADB shell 使用者的UID);那麼此時,這個 App 可以透過執行兩次 `su` 來獲得完整的root 權限:
-1. 第一次執行 `su`,由於 App Profile 強制生效,會正常切換到 UID 為 `2000(adb shell)` 而非 `0(root)`。
-2. 第二次執行 `su`,由於此時它 UID 是 `2000`,而你給 `2000(adb shell)` 配置了允許 root,它會獲得完整的 root 權限!
+1. 第一次執行 `su`,由於 App Profile 強制生效,會正常切換到 UID 為 `2000` (adb shell) 而非 `0` (root)。
+2. 第二次執行 `su`,由於此時它 UID 是 `2000`,而你給 `2000` (adb shell) 配置了允許 root,它會獲得完整的 root 權限!
:::warning 注意
這是完全符合預期的行為,並非 BUG!因此我們建議:
-如果你的確需要給 adb 授予 root 權限(例如你是開發者),那麼不建議你在配置 Root Profile 的時候將 UID 改成 `2000`,用 `1000(system)` 會更好。
+如果你的確需要給 adb 授予 root 權限(例如你是開發者),那麼不建議你在配置 Root Profile 的時候將 UID 改成 `2000`,用 `1000` (system) 會更好。
:::
## Non Root Profile {#non-root-profile}
### 卸載模組 {#umount-modules}
-KernelSU 提供了一種 systemless 的方式來修改系統分區,這是透過掛載 overlayfs 來實現的。但有些情況下,App 可能會對這種行為比較敏感;因此,我們可以透過設定「卸載模組」來卸載掛載在這些應用程式上的模組。
+KernelSU 提供了一種無須直接修改系統分區的方式 (systemless) 來修改系統分區,這是透過掛載 overlayfs 來實現的。但有些情況下,App 可能會對這種行為比較敏感;因此,我們可以透過設定「卸載模組」來卸載掛載在這些應用程式上的模組。
另外,KernelSU 管理器的設定介面還提供了一個「預設卸載模組」的開關,這個開關預設是**開啟**的,這表示**如果不對應用程式做額外的設定**,預設情況下 KernelSU 或某些模組會對此應用程式執行卸載操作。當然,如果你不喜歡這個設定或這個設定會影響某些 App,你可以有以下選擇:
1. 保持「預設卸載模組」的開關,然後針對不需要「卸載模組」的應用程式進行單獨的設置,在 App Profile 中關閉「卸載模組」;(相當於「白名單」)。
2. 關閉「預設卸載模組」的開關,然後針對需要「卸載模組」的應用程式進行單獨的設置,在 App Profile 中開啟「卸載模組」;(相當於「黑名單」)。
-:::info
-KernelSU 在 5.10 及以上內核上,內核無須任何修改就可以卸載模組;但在 5.10 以下的設備上,這個開關僅僅是一個“設定”,KernelSU 本身不會做任何動作,如果你希望在 5.10 以前的內核可以卸載模組,你需要將 `path_unmount` 函數向後移植到 `fs/namespace.c`,您可以在[如何為非 GKI 核心整合 KernelSU](/zh_TW/guide/how-to-integrate-for-non-gki.html)的末尾獲取更多資訊。一些模組(如 ZygiskNext)也會透過這個設定決定是否需要卸載。
+:::info 提示
+KernelSU 在 5.10 及以上內核上,內核無須任何修改就可以卸載模組;但在 5.10 以下的設備上,這個開關僅僅是一個"設定",KernelSU 本身不會做任何動作,如果你希望在 5.10 以前的內核可以卸載模組,你需要將 `path_unmount` 函數向後移植到 `fs/namespace.c`,您可以在[如何為非 GKI 核心整合 KernelSU](how-to-integrate-for-non-gki.md#how-to-backport-path_unpount)獲取更多資訊。一些模組(如 ZygiskNext)也會透過這個設定決定是否需要卸載。
:::
\ No newline at end of file
diff --git a/website/docs/zh_TW/guide/difference-with-magisk.md b/website/docs/zh_TW/guide/difference-with-magisk.md
index 6cd291e171de..fdaa5fc9d940 100644
--- a/website/docs/zh_TW/guide/difference-with-magisk.md
+++ b/website/docs/zh_TW/guide/difference-with-magisk.md
@@ -1,4 +1,4 @@
-# KernelSU 與 Magisk 的差異 {#title}
+# KernelSU 與 Magisk 的差異 {#difference-with-magisk}
儘管 KernelSU 模組和 Magisk 模組之間有許多相似之處,但由於它們完全不同的實作機制,不可避免地存在一些差異;如果您想讓您的模組同時在 Magisk 和 KernelSU 上運作,那麼您必須瞭解這些差異。
@@ -6,7 +6,7 @@
- 模組檔案格式:都以 Zip 的格式組織模組,並且模組的格式幾乎相同
- 模組安裝目錄:都位於 `/data/adb/modules`
-- Systemless:都支援通過模組以無系統修改的方式來更改 `/system`
+- 無系統修改:都支援透過模組以無系統修改的方式來更改 `/system`
- `post-fs-data.sh`:執行階段和語義完全相同
- `service.sh`:執行階段和語義完全相同
- `system.prop`:完全相同
@@ -19,10 +19,10 @@
以下是一些不同之處:
-1. KernelSU 的模組不支援在 Recovery 中安裝。
+1. KernelSU 的模組無法在 Recovery 中安裝。
2. KernelSU 的模組沒有內建的 Zygisk 支援 (但您可以透過 [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext) 來使用 Zygisk 模組)。
3. KernelSU 模組取代或刪除檔案與 Magisk 完全不同。KernelSU 不支援 `.replace` 方法,相反,您需要透過 `mknod filename c 0 0` 建立相同名稱的資料夾以刪除對應檔案。
-4. BusyBox 的目錄不同;KernelSU 內建的 BusyBox 在 `/data/adb/ksu/bin/busybox` 而 Magisk 在 `/data/adb/magisk/busybox`;**注意此為 KernelSU 內部行為,未來可能會變更!**
-5. KernelSU 不支援 `.replace` 檔案;但 KernelSU 支援 `REPLACE` 和 `REMOVE` 變數以移除或取代檔案 (資料夾)。
+4. BusyBox 的目錄不同。KernelSU 內建的 BusyBox 在 `/data/adb/ksu/bin/busybox`,而 Magisk 在 `/data/adb/magisk/busybox`。**注意此為 KernelSU 內部行為,未來可能會變更!**
+5. KernelSU 不支援 `.replace` 檔案;但 KernelSU 支援 `REPLACE` 和 `REMOVE` 變數以移除或取代檔案與資料夾。
6. KernelSU 新增了 `boot-completed` 階段以在啟動完成時執行一些腳本。
-7. KernelSU 新增了 `post-mount` 階段,以便在掛載 overlayfs 後執行一些腳本
+7. KernelSU 新增了 `post-mount` 階段,以便在掛載 overlayfs 後執行一些腳本。
diff --git a/website/docs/zh_TW/guide/faq.md b/website/docs/zh_TW/guide/faq.md
index 8f1c13400c26..57166b68c4ac 100644
--- a/website/docs/zh_TW/guide/faq.md
+++ b/website/docs/zh_TW/guide/faq.md
@@ -26,7 +26,7 @@ KernelSU 沒有內建 Zygisk 支援,但是您可以用 [ZygiskNext](https://gi
KernelSU 的模組系統與 Magisk 的 magic mount 存在衝突,如果在 KernelSU 中啟用了任何模組,那麼整個 Magisk 將無法正常運作。
-但是如果您只使用 KernelSU 的 `su`,那么它會和 Magisk 一同運作:KernelSU 修改 `kernel` 、 Magisk 修改 `ramdisk`,它們可以搭配使用。
+但是如果您只使用 KernelSU 的 `su`,那么它會和 Magisk 一同運作:KernelSU 修改 `kernel`、Magisk 修改 `ramdisk`,它們可以搭配使用。
## KernelSU 会取代 Magisk 嗎?
@@ -49,11 +49,11 @@ KernelSU 的模組系統與 Magisk 的 magic mount 存在衝突,如果在 Kern
## 如何為舊版核心整合 KernelSU?
-請參閱[指南](how-to-integrate-for-non-gki)
+請參閱[指南](how-to-integrate-for-non-gki.md)
## 為何我的 Android 版本為 13,但核心版本卻是 "android12-5.10"?
-核心版本與 Android 版本無關,如果您要刷新 KernelSU,請一律使用**核心版本**而非 Android 版本,如果你為 "android12-5.10" 的裝置刷新 Android 13 的核心,等候您的將會是開機迴圈。
+核心版本與 Android 版本無關,如果您要使用 KernelSU,請一律使用**核心版本**而非 Android 版本,如果你為 "android12-5.10" 的裝置寫入 Android 13 的核心,等候您的將會是開機迴圈。
## 我是 GKI1.0,能用 KernelSU 嗎?
diff --git a/website/docs/zh_TW/guide/how-to-build.md b/website/docs/zh_TW/guide/how-to-build.md
index 034044945df1..89517c84b0d2 100644
--- a/website/docs/zh_TW/guide/how-to-build.md
+++ b/website/docs/zh_TW/guide/how-to-build.md
@@ -5,7 +5,7 @@
1. [建置核心](https://source.android.com/docs/setup/build/building-kernels)
2. [標準核心映像 (GKI) 發行組建](https://source.android.com/docs/core/architecture/kernel/gki-release-builds)
-::: warning
+::: warning 警告
此文件適用於 GKI 裝置,如果您是舊版核心,請參閱[如何為非 GKI 裝置整合 KernelSU](how-to-integrate-for-non-gki)
:::
@@ -20,7 +20,7 @@ repo init -m manifest.xml
repo sync
```
-`` 是一個可以唯一確定組建的資訊清單檔案,您可以使用這個資訊清單進行可重新預測的組建。您需要從[標準核心映像 (GKI) 發行組建](https://source.android.com/docs/core/architecture/kernel/gki-release-builds) 下載資訊清單檔案
+`` 是一個可以唯一確定組建的資訊清單,您可以使用這個資訊清單進行可重新預測的組建。您需要從[標準核心映像 (GKI) 發行組建](https://source.android.com/docs/core/architecture/kernel/gki-release-builds)下載資訊清單。
### 建置 {#build}
@@ -34,14 +34,14 @@ LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
不要忘記新增 `LTO=thin`,否則,如果您的電腦記憶體小於 24GB,建置可能會失敗。
-從 Android 13 開始,核心由 `bazel` 建置:
+從 Android 13 開始,核心使用 `bazel` 建置:
```sh
tools/bazel build --config=fast //common:kernel_aarch64_dist
```
-:::info
-對於某些 Android 14 內核,要使 Wi-Fi/藍牙正常工作,可能需要刪除所有受 GKI 保護的匯出:
+:::info 你可能需要知道...
+對於某些 Android 14 核心,要使 Wi-Fi/藍牙正常工作,可能需要刪除所有受 GKI 保護的匯出:
```sh
rm common/android/abi_gki_protected_exports_*
@@ -52,22 +52,20 @@ rm common/android/abi_gki_protected_exports_*
如果您可以成功建置核心,那麼建置 KernelSU 就會非常輕鬆,依自己的需求在核心原始碼根目錄中執行以下任一命令:
-- 最新 tag (穩定版本)
+::: code-group
-```sh
+```sh[最新 tag (穩定版本)]
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
```
-- main 分支 (開發版本)
-
-```sh
+```sh[main 分支 (開發版本)]
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
```
-- 選取 tag (例如 v0.5.2)
-
-```sh
+```sh[選取 tag (例如 v0.5.2)]
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
```
+:::
+
然後重新建置核心,您將會得到一個帶有 KernelSU 的核心映像!
diff --git a/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md b/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md
index 43b4980e9a66..a6c28485f313 100644
--- a/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md
+++ b/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md
@@ -1,4 +1,4 @@
-# 如何為非 GKI 核心整合 KernelSU {#introduction}
+# 如何為非 GKI 核心整合 KernelSU {#how-to-integrate-kernelsu-for-non-gki-kernels}
KernelSU 可以被整合到非 GKI 核心中,現在它最低支援到核心 4.14 版本;理論上也可以支援更低的版本。
@@ -11,31 +11,21 @@ KernelSU 可以被整合到非 GKI 核心中,現在它最低支援到核心 4.
1. 藉助 `kprobe` 自動整合
2. 手動修改核心原始碼
-## 使用 kprobe 整合 {#using-kprobes}
+## 使用 kprobe 整合 {#integrate-with-kprobe}
KernelSU 使用 kprobe 機制來處理核心的相關 hook,如果 *kprobe* 可以在您建置的核心中正常運作,那麼建議使用這個方法進行整合。
首先,把 KernelSU 新增至您的核心來源樹狀結構,再核心的根目錄執行以下命令:
-- 最新 tag (稳定版本)
-
-```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
-```
-
-- main 分支(開發版本)
-
```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
```
-- 選取 tag (例如 v0.5.2)
-
-```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
-```
+:::info 公告
+[KernelSU 1.0 及更新版本不再支援非 GKI 核心](https://github.com/tiann/KernelSU/issues/1705)。最後一個支援的版本為 `v0.9.5`,請確保使用的版本正確。
+:::
-然後,您需要檢查您的核心是否啟用 *kprobe* 相關組態,如果未啟用,則需要新增以下組態:
+然後,您需要檢查您的核心是否啟用 *kprobe*,如果未啟用,則需要新增以下設定:
```
CONFIG_KPROBES=y
@@ -45,33 +35,40 @@ CONFIG_KPROBE_EVENTS=y
最後,重新建置您的核心即可。
-如果您發現 KPROBES 仍未生效,很有可能是因為它的相依性 `CONFIG_MODULES` 並未被啟用 (如果還是未生效請輸入 `make menuconfig` 搜尋 KPROBES 的其他相依性並啟用)
+如果您發現 KPROBES 仍未生效,很有可能是因為它依賴的 `CONFIG_MODULES` 並未被啟用,如果還是未生效請輸入 `make menuconfig` 搜尋 KPROBES 的其他相依性並啟用。
如果您在整合 KernelSU 之後手機無法啟動,那麼很可能您的核心中 **kprobe 無法正常運作**,您需要修正這個錯誤,或者使用第二種方法。
:::tip 如何檢查 kprobe 是否損毀?
-將 `KernelSU/kernel/ksu.c` 中的 `ksu_enable_sucompat()` 和 `ksu_enable_ksud()` 取消註解,如果正常開機,即 kprobe 已損毀;或者您可以手動嘗試使用 kprobe 功能,如果不正常,手機會直接重新啟動。
+將 `KernelSU/kernel/ksu.c` 中的 `ksu_enable_sucompat()` 和 `ksu_enable_ksud()` 註解掉,如果正常開機,即 kprobe 已損毀;或者您可以手動嘗試使用 kprobe 功能,如果不正常,手機會直接重新啟動。
:::
:::info 如何為非 GKI 核心啟用卸載模組功能
-如果你的內核版本小於 5.10,你應該將 `path_umount` 向後移植至 `fs/namespace.c`。 卸載模組功能依賴於這個函數。 如果你沒有向後移植 `path_umount`,卸載模組功能將無法工作。 你可以在底下查看更多關於 `path_unmount` 的資料。
+如果你的內核版本小於 5.10,你應該將 `path_umount` 向後移植至 `fs/namespace.c`。卸載模組功能依賴於這個函數。如果你沒有向後移植 `path_umount`,卸載模組功能將無法工作。你可以在[這裡查看更多關於 `path_unmount` 的資料](#how-to-backport-path_unpount)。
:::
-## 手動修改核心原始碼 {#modify-kernel-source-code}
+## 手動修改核心原始碼 {#manually-modify-the-kernel-source}
-如果 kprobe 無法正常運作 (可能是上游的錯誤或核心版本過低),那您可以嘗試這種方法:
+如果 kprobe 無法正常運作 (在4.8之前可能是上游或核心的錯誤),那您可以嘗試這種方法:
-首先,將 KernelSU 新增至您的原始碼樹狀結構,再核心的根目錄執行以下命令:
+首先,將 KernelSU 新增至您的原始碼樹狀結構,在核心的根目錄執行以下命令:
```sh
-curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
+curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.9.5
+```
+請記住,在某些裝置上,您的 `defconfig` 可能位於 `arch/arm64/configs` 中,或在其他情況下位於 `arch/arm64/configs/vendor/你的defconfig` 中。無論您使用哪個 `defconfig`,請確保使用 `CONFIG_KSU=y` 啟用KernelSU,或使用 `n` 停用它。例如,如果您選擇啟用它,則 `defconfig` 應包含以下字串:
+```conf
+# KernelSU
+CONFIG_KSU=y
```
然後,手動修改核心原始碼,您可以參閱下方的 patch:
-```diff
+::: code-group
+
+```diff[exec.c]
diff --git a/fs/exec.c b/fs/exec.c
index ac59664eaecf..bdd585e1d2cc 100644
--- a/fs/exec.c
@@ -97,7 +94,7 @@ index ac59664eaecf..bdd585e1d2cc 100644
return __do_execve_file(fd, filename, argv, envp, flags, NULL);
}
```
-```diff
+```diff[open.c]
diff --git a/fs/open.c b/fs/open.c
index 05036d819197..965b84d486b8 100644
--- a/fs/open.c
@@ -128,7 +125,7 @@ index 05036d819197..965b84d486b8 100644
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
```
-```diff
+```diff[read_write.c]
diff --git a/fs/read_write.c b/fs/read_write.c
index 650fc7e0f3a6..55be193913b6 100644
--- a/fs/read_write.c
@@ -151,7 +148,7 @@ index 650fc7e0f3a6..55be193913b6 100644
return -EBADF;
if (!(file->f_mode & FMODE_CAN_READ))
```
-```diff
+```diff[stat.c]
diff --git a/fs/stat.c b/fs/stat.c
index 376543199b5a..82adcef03ecc 100644
--- a/fs/stat.c
@@ -175,6 +172,8 @@ index 376543199b5a..82adcef03ecc 100644
return -EINVAL;
```
+:::
+
主要修改四個項目:
1. do_faccessat,通常位於 `fs/open.c`
@@ -236,9 +235,11 @@ index 2ff887661237..e758d7db7663 100644
return -EINVAL;
```
+### 安全模式 {#safe-mode}
+
若要啟用 KernelSU 內建的安全模式,您還需要修改 `drivers/input/input.c` 中的 `input_handle_event` 方法:
-:::tip
+:::tip 小建議
強烈建議啟用此功能,如果遇到開機迴圈,這將會非常有用!
:::
@@ -266,9 +267,45 @@ index 45306f9ef247..815091ebfca4 100755
add_input_randomness(type, code, value);
```
+:::info 不小心進入安全模式?
+如果您使用手動整合且不停用 `CONFIG_KPROBES`,那麼您將可能會在啟動後透過按下音量來減少按鈕來觸發安全模式!因此,如果使用手動集成,您需要停用 `CONFIG_KPROBES` !
+:::
+
+### 無法在終端中執行 `pm` ? {#failed-to-execute-pm-in-terminal}
+
+你應該修改 `fs/devpts/inode.c`,參考:
+
+```diff
+diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
+index 32f6f1c68..d69d8eca2 100644
+--- a/fs/devpts/inode.c
++++ b/fs/devpts/inode.c
+@@ -602,6 +602,8 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv)
+ return dentry;
+ }
+
++#ifdef CONFIG_KSU
++extern int ksu_handle_devpts(struct inode*);
++#endif
++
+ /**
+ * devpts_get_priv -- get private data for a slave
+ * @pts_inode: inode of the slave
+@@ -610,6 +612,7 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv)
+ */
+ void *devpts_get_priv(struct dentry *dentry)
+ {
++ #ifdef CONFIG_KSU
++ ksu_handle_devpts(dentry->d_inode);
++ #endif
+ if (dentry->d_sb->s_magic != DEVPTS_SUPER_MAGIC)
+ return NULL;
+ return dentry->d_fsdata;
+```
+
### 如何向後移植 path_umount {#how-to-backport-path_unpount}
-你可以透過向後移植 `path_umount` 來讓卸載模組功能在小於 5.10 的非 GKI 核心上運作. 你可以參考這個修改:
+你可以透過向後移植 `path_umount` 來讓卸載模組功能在低於 5.10 的非 GKI 核心上運作。你可以參考這個修改:
```diff
--- a/fs/namespace.c
@@ -315,5 +352,4 @@ index 45306f9ef247..815091ebfca4 100755
* This is important for filesystems which use unnamed block devices.
```
-
最後,再次建置您的核心,KernelSU 將會如期運作。
diff --git a/website/docs/zh_TW/guide/installation.md b/website/docs/zh_TW/guide/installation.md
index c0e0f32d3d6e..1d2e7a3d852f 100644
--- a/website/docs/zh_TW/guide/installation.md
+++ b/website/docs/zh_TW/guide/installation.md
@@ -1,25 +1,25 @@
# 安裝 {#title}
-## 檢查您的裝置是否受支援 {#check-if-supported}
+## 檢查您的裝置是否受支援 {#check-if-your-device-is-supported}
-從 [GitHub Releases](https://github.com/tiann/KernelSU/releases) 下載 KernelSU 管理器應用程式,然後將應用程式安裝至裝置並開啟:
+從 [GitHub Releases](https://github.com/tiann/KernelSU/releases) 下載 KernelSU 管理器,然後安裝至裝置並開啟:
-- 如果應用程式顯示「不支援」,則表示您的裝置不支援 KernelSU,您需要自行編譯核心才能繼續使用,,KernelSU 官方也永遠不會為您提供一個可以刷新的 Boot 映像。
-- 如果應用程式顯示「未安裝」,那麼 KernelSU 支援您的裝置;可以進行下一步作業。
+- 如果顯示「不支援」,則表示您的裝置不支援 KernelSU,您需要自行編譯核心才能繼續使用,KernelSU 官方也永遠不會提供一個您可以寫入的 Boot 映像。
+- 如果顯示「未安裝」,那麼 KernelSU 支援您的裝置。
-:::info
+::: info 提示
對於顯示「不支援」的裝置,這裡有一個[非官方支援裝置清單](unofficially-support-devices.md),您可以使用這個清單裡的核心自行編譯。
:::
-## 備份您的原廠 boot.img {#backup-boot-image}
+## 備份您的原廠 boot.img {#backup-stock-boot-img}
-在進行刷新作業前,您必須預先備份您的原廠 boot.img。如果您在後續刷新作業中出現了任何問題,您都可以透過使用 Fastboot 刷新回到原廠 Boot 以還原系統。
+在寫入核心映像前,您必須預先備份您的原廠 boot.img。如果您在後續寫入中出現了任何問題,您都可以透過使用 Fastboot 寫回原廠 Boot 以還原系統。
-::: warning
-刷新作業可能會造成資料遺失,請確保做好這一步再繼續進行下一步作業!!必要時您還可以備份您手機的所有資料。
+::: warning 警告
+寫入核心映像可能會造成資料遺失,請確保做好這一步再繼續進行下一步作業!!必要時您還可以備份您手機的所有資料。
:::
-## 必要知識 {#acknowage}
+## 必要知識 {#necessary-knowledge}
### ADB 和 Fastboot {#adb-and-fastboot}
@@ -27,9 +27,9 @@
### KMI
-KMI 全稱 Kernel Module Interface,相同 KMI 的核心版本是**相容的** 這也是 GKI 中「標準」的涵義所在;反之,如果 KMI 不同,那麼這些核心之間無法彼此相容,刷新與您裝置 KMI 不同的核心映像可能會導致開機迴圈。
+KMI 全稱 Kernel Module Interface,相同 KMI 的核心版本是**相容的**,這也是 GKI 中「標準」的涵義所在。反之,如果 KMI 不同,那麼這些核心之間無法彼此相容,寫入與您裝置 KMI 不同的核心映像可能會導致無法開機。
-具體來講,對 GKI 的裝置,其核心版本格式應該如下:
+具體來講,對於 GKI 的裝置,其核心版本格式應該如下:
```txt
KernelRelease :=
@@ -37,21 +37,27 @@ Version.PatchLevel.SubLevel-AndroidRelease-KmiGeneration-suffix
w .x .y -zzz -k -something
```
-其中,`w.x-zzz-k` 為 KMI 版本。例如,一部裝置核心版本為 `5.10.101-android12-9-g30979850fc20`,那麼它的 KMI 為 `5.10-android12-9`;理論上刷新其他這個 KMI 的核心也能正常開機。
+其中,`w.x-zzz-k` 為 KMI 版本。例如,一部裝置核心版本為 `5.10.101-android12-9-g30979850fc20`,那麼它的 KMI 為 `5.10-android12-9`,理論上寫入其他這個 KMI 的核心也能正常開機。
-::: tip
+::: tip 補充
請注意,核心版本中的 SubLevel 並非 KMI 的一部分!也就是說 `5.10.101-android12-9-g30979850fc20` 與 `5.10.137-android12-9-g30979850fc20` 的 KMI 相同!
:::
+### 安全性修補程式等級 {#security-patch-level}
+
+較新的 Android 裝置可能具有防回滾機制,不允許寫入具有較舊安全性修補程式等級的啟動映像。例如,如果您的裝置核心為 `5.10.101-android12-9-g30979850fc20`,則其安全修補程式等級為 `2023-11`;即使寫入了 KMI 對應的核心,如果安全修補程式等級早於 `2023-11`(例如 `2023-06`),也可能會導致無法開機。
+
+因此,最好使用具有最新安全性修補程式等級的核心來維護與 KMI 的對應關係。
+
### 核心版本與 Android 版本 {#kernel-version-vs-android-version}
請注意:**核心版本與 Android 版本並不一定相同!**
-如果您發現您的核心版本是 `android12-5.10.101`,然而您 Android 系統的版本為 Android 13 或者其他;請不要覺得奇怪,因為 Android 系統的版本與 Linux 核心的版本號碼並非一致;Linux 核心的版本號碼一般與**裝置出廠時隨附的 Android 系統的版本一致**,如果後續 Android 系統更新,核心版本一般不會發生變化。如果您需要刷新,**請以核心版本為準!!**
+如果您發現您的核心版本是 `android12-5.10.101`,然而您 Android 系統的版本為 Android 13 或更高,請不要覺得奇怪,因為 Android 系統的版本與 Linux 核心的版本號碼並非一致。Linux 核心的版本號碼一般與**裝置出廠時隨附的 Android 系統的版本一致**,如果後續 Android 系統更新,核心版本一般不會發生變化。如果您需要寫入,**請以核心版本為準!!**
## 安裝簡介 {#introduction}
-自 `0.9.0` 版本以後,在 GKI 裝置中,KernelSU 支援兩種運行模式:
+自 `0.9.0` 版本以後,在 GKI 裝置上,KernelSU 支援兩種運作模式:
1. `GKI`:使用**通用核心鏡像**(GKI)取代掉裝置原有的核心。
2. `LKM`:使用**可載入核心模組**(LKM)的方式載入到裝置核心中,不會替換掉裝置原有的核心。
@@ -60,55 +66,56 @@ w .x .y -zzz -k -something
### GKI 模式 {#gki-mode}
-GKI 模式會替換掉裝置原有的內核,使用 KernelSU 提供的通用內核鏡像。 GKI 模式的優點是:
+GKI 模式會替換掉裝置原有的核心,使用 KernelSU 提供的通用核心鏡像。 GKI 模式的優點是:
-1. 通用型強,適用於大多數裝置;例如三星開啟了 KNOX 的裝置,LKM 模式無法運作。還有一些冷門的魔改裝置,也只能使用 GKI 模式;
-2. 不依賴官方韌體即可使用;不需要等待官方韌體更新,只要 KMI 一致,就可以使用;
+1. 通用型高,適用於大多數裝置;例如開啟了 KNOX 的三星裝置、或是 LKM 模式無法運作的裝置。還有一些冷門的魔改裝置,也只能使用 GKI 模式。
+2. 不依賴官方韌體即可使用;不需要等待官方韌體更新,只要 KMI 一致,就可以使用。
### LKM 模式 {#lkm-mode}
-LKM 模式不會替換掉裝置原有的內核,而是使用可載入內核模組的方式載入到裝置內核中。 LKM 模式的優點是:
+LKM 模式不會替換掉裝置原有的核心,而是使用可載入核心模組的方式載入到裝置核心中。 LKM 模式的優點是:
-1. 不會取代裝置原有的核心;如果你對裝置原有的核心有特殊需求,或是你希望在使用第三方核心的同時使用 KernelSU,可以使用 LKM 模式;
-2. 升級和 OTA 較為方便;升級 KernelSU 時,可以直接在管理器內部安裝,無需再手動刷寫;系統 OTA 後,可以直接安裝到第二個槽位,也無需再手動刷寫;
-3. 適用於一些特殊場景;例如使用臨時 ROOT 權限也可以載入 LKM,由於不需要替換 boot 分區,因此不會觸發 avb,不會使裝置意外變磚;
-4. LKM 可以被暫時卸載;如果你暫時想取消 root,可以卸載 LKM,這個過程不需要刷寫分區,甚至也不用重啟裝置;如果你想再次 root,只需要重啟裝置即可;
+1. 不會取代裝置原有的核心:如果你對裝置原有的核心有特殊需求,或是你希望在使用第三方核心的同時使用 KernelSU,可以使用 LKM 模式。
+2. 升級和 OTA 較為方便:升級 KernelSU 時,可以直接在管理器內部安裝,無需再手動寫入;系統 OTA 後,可以直接安裝到第二個槽位,也無需再手動寫入。
+3. 適用於一些特殊場景:例如使用臨時 root 權限也可以載入 LKM,由於不需要替換 boot 分區,因此不會觸發 avb,不會使裝置意外變磚。
+4. LKM 可以被暫時卸載:如果你暫時想取消 root,可以卸載 LKM,這個過程不需要寫入分區,甚至也不用重啟裝置。如果你想重新取得 root,只需要重啟裝置即可。
:::tip 兩種模式共存
-打開管理器後,你可以在首頁看到裝置目前運行的模式;注意 GKI 模式的優先級高於 LKM ,如你你既使用 GKI 內核替換掉了原有的內核,又使用 LKM 的方式修補了 GKI 內核,那麼 LKM 會被忽略,裝置將永遠以 GKI 的模式運作。
+打開管理器後,你可以在首頁看到裝置目前運行的模式。注意 GKI 模式的優先級高於 LKM ,如你既使用 GKI 核心替換掉了原有的核心,又使用 LKM 的方式修補了 GKI 核心,那麼 LKM 會被忽略,裝置將永遠以 GKI 的模式運作。
:::
### 選哪個? {#which-one}
-如果你的裝置是手機,我們建議您優先考慮 LKM 模式;如果你的裝置是模擬器、WSA 或 Waydroid 等,我們建議您優先考慮 GKI 模式。
+如果你的裝置是手機,我們建議您優先考慮 LKM 模式。
+如果你的裝置是模擬器、WSA 或 Waydroid 等,我們建議您優先考慮 GKI 模式。
## LKM 安裝 {#lkm-installation}
### 取得官方韌體 {#get-the-official-firmware}
-使用 LKM 的模式,需要取得官方韌體,然後在官方韌體的基礎上修補;如果你使用的是第三方內核,可以把第三方內核的 boot.img 作為官方韌體。
+使用 LKM 的模式,需要取得官方韌體,然後在官方韌體的基礎上修補;如果你使用的是第三方核心,可以把第三方核心的 boot.img 作為官方韌體。
-取得官方韌體的方法有很多,如果你的裝置支援 `fastboot boot`,那麼我們最推薦以及最簡單的方法是使用 `fastboot boot` 臨時啟動 KernelSU 提供的 GKI 內核,然後安裝管理器,最後在管理器中直接安裝;這種方法不需要你手動下載官方韌體,也不需要你手動提取 boot。
+取得官方韌體的方法有很多,如果你的裝置支援 `fastboot boot`,那麼我們最推薦以及最簡單的方法是使用 `fastboot boot` 臨時啟動 KernelSU 提供的 GKI 核心,並參考[使用管理器](#use-the-manager)安裝。
如果你的裝置不支援 `fastboot boot`,那麼你可能需要手動去下載官方韌體包,然後從中提取 boot。
-與 GKI 模式不同,LKM 模式會修改 `ramdisk`,因此在出廠 Android 13 的裝置上,它需要修補的是 `init_boot` 分區而非 `boot` 分區;而 GKI 模式則永遠是操作 `boot` 分區。
+與 GKI 模式不同,LKM 模式會修改 `ramdisk`,因此在出廠 Android 13 的裝置上,通常它需要修補的是 `init_boot` 分區而非 `boot` 分區;而 GKI 模式則永遠是修改 `boot` 分區。
### 使用管理器 {#use-the-manager}
開啟管理器,點選右上角的安裝圖標,會出現若干個選項:
-1. 選擇並修補一個文件:如果你手機目前沒有 root 權限,你可以選擇這個選項,然後選擇你的官方韌體,管理器會自動修補它;你只需要刷入這個修補後的文件,即可永久取得 root 權限;
-2. 直接安裝:如果你手機已經 root,你可以選擇這個選項,管理器會自動獲取你的裝置資訊,然後自動修補官方韌體,然後刷入;你可以考慮使用`fastboot boot` KernelSU 的 GKI 內核來取得臨時 root 安裝管理器,然後再使用這個選項;這種方式也是 KernelSU 升級最主要的方式;
-3. 安裝到另一個分割區:如果你的裝置支援 A/B 分割區,你可以選擇這個選項,管理器會自動修補官方韌體,然後安裝到另一個分割區;這種方式適用於 OTA 後的裝置,你可以在 OTA 後直接安裝到另一個分割區,然後重新啟動裝置即可;
+1. 選擇並修補一個文件:如果你手機目前沒有 root 權限,你可以選擇這個選項,然後選擇你的官方韌體,管理器會自動修補它。你只需要寫入這個修補後的文件,即可永久取得 root 權限。
+2. 直接安裝:如果你手機已經 root,你可以選擇這個選項,管理器會自動獲取你的裝置資訊,然後自動修補官方韌體,然後寫入。你可以考慮使用 `fastboot boot` KernelSU 的 GKI 核心來取得臨時 root 安裝管理器,然後再使用這個選項。**這種方式也是 KernelSU 升級最主要的方式**。
+3. 安裝到另一個分割區:如果你的裝置支援 A/B 分區,你可以選擇這個選項,管理器會自動修補官方韌體,然後安裝到另一個分區。這種方式適用於 OTA 後的裝置,你可以在 OTA 後直接安裝到另一個分割區,然後重新啟動裝置即可。
-### 使用命令列
+### 使用命令列{#use-the-command-line}
-如果你不想使用管理器,你也可以使用命令列來安裝 LKM;KernelSU 提供的 `ksud` 工具可以幫助你快速修補官方韌體,然後刷入。
+如果你不想使用管理器,你也可以使用命令列來安裝 LKM。KernelSU 提供的 `ksud` 可以幫助你快速修補官方韌體,然後寫入。
這個工具支援 macOS、Linux 和 Windows,你可以在 [GitHub Release](https://github.com/tiann/KernelSU/releases) 下載對應的版本。
-使用方法:`ksud boot-patch` 具體的使用方法你可以查看命令列幫助。
+使用方法:`ksud boot-patch`。 你可以查看命令列的提示了解具體的使用方法。
```sh
husky:/ # ksud boot-patch -h
@@ -129,126 +136,130 @@ Options:
-h, --help Print help
```
需要說明的幾個選項:
-1. `--magiskboot` 選項可以指定 magiskboot 的路徑,如果不指定,ksud 會在環境變數中尋找;如果你不知道如何取得 magiskboot,可以參考[這裡](#patch-boot-image);
-2. `--kmi` 選項可以指定 `KMI` 版本,如果你的裝置核心名字沒有遵循 KMI 規範,你可以透過這個選項來指定;
+1. `--magiskboot` 選項可以指定 magiskboot 的路徑,如果不指定,ksud 會在環境變數中尋找。如果你不知道如何取得 magiskboot,可以參考[這裡](#patch-boot-image)。
+2. `--kmi` 選項可以指定 `KMI` 版本,如果你的裝置核心名字沒有遵循 KMI 規範,你可以透過這個選項來指定。
+
最常見的使用方法為:
```sh
ksud boot-patch -b --kmi android13-5.10
```
-## GKI 安裝
+## GKI 安裝{#gki-mode-installation}
GKI 的安裝方式有以下幾種,各自適用於不同的場景,請依需求選擇:
-1. 使用自訂 Recovery (如 TWRP) 安裝
-2. 使用核心刷新應用程式 (例如 Franco Kernel Manager) 安裝
-3. 使用 KernelSU 提供的 boot.img 透過 Fastboot 安裝
+1. 使用 KernelSU 提供的 boot.img 透過 Fastboot 安裝
+2. 使用核心寫入程式 (例如 KernelFlasher) 安裝
+3. 使用自訂 Recovery (例如 TWRP) 安裝
4. 手動修補 boot.img 並安裝
-## 使用自訂 Recovery 安裝 {#install-by-recovery}
-
-先決條件:您的裝置必須有自訂的 Recovery,例如 TWRP;如果沒有或者只有官方 Recovery,請使用其他方法。
-
-步驟:
-
-1. 在 KernelSU 的 [Release 頁面](https://github.com/tiann/KernelSU/releases) 下載與您手機版本相符的以 AnyKernel3 開頭的 Zip 套件;例如,手機核心版本為 `android12-5.10.66`,那麼您應該下載 `AnyKernel3-android12-5.10.66_yyyy-MM.zip` 這個檔案 (其中 `yyyy` 為年份,`MM` 為月份)。
-2. 重新開機手機至 TWRP。
-3. 使用 Adb 將 AnyKernel3-*.zip 放置到手機 /sdcard 然後在 TWRP 圖形使用者介面選擇並安裝;或者您也可以直接 `adb sideload AnyKernel-*.zip` 安裝。
-
-PS. 這種方法適用於任何狀況下的安裝 (不限於初次安裝或後續更新),只要您用 TWRP 就可以進行作業。
-
-## 使用核心刷新應用程式安裝 {#install-by-kernel-flasher}
-
-先決條件:您的裝置必須已經 Root。例如您已經安裝了 Magisk 並取得 Root 存取權,或者您已經安裝了舊版本的 KernelSU 需升級到其他版本的 KernelSU;如果您的裝置並未 Root,請嘗試其他方法。
-
-步驟:
-
-1. 下載 AnyKernel3 的 Zip 檔案;請參閱 *使用自訂 Recovery 安裝* 章節的内容。
-2. 開啟核心刷新應用程式提供的 AnyKernel3 Zip 檔案進行刷新。
-
-如果您先前並未使用過核心刷新應用程式,可以嘗試下面幾個方法:
-
-1. [Kernel Flasher](https://github.com/capntrips/KernelFlasher/releases)
-2. [Franco Kernel Manager](https://play.google.com/store/apps/details?id=com.franco.kernel)
-3. [Ex Kernel Manager](https://play.google.com/store/apps/details?id=flar2.exkernelmanager)
-
-PS. 這種方法在更新 KernelSU 時比較方便,無需電腦即可完成 (注意備份!)。
-
## 使用 KernelSU 提供的 boot.img 安裝 {#install-with-boot-img-provided-by-kernelsu}
-這種方法無需您有 TWRP,也無需您的手機有 Root 權限;適用於您初次安裝 KernelSU。
+如果你的裝置的 `boot.img` 使用常見的壓縮格式,你可以直接寫入 KernelSU 提供的 GKI 核心映像,這種方法無需 TWRP,也無需您的手機有 Root 權限;適用於您初次安裝 KernelSU。
### 找到合適的 boot.img {#find-proper-boot-img}
-KernelSU 為 GKI 裝置提供了標準 boot.img,您需要將 boot.img 刷新至裝置的 Boot 分割區。
+KernelSU 為 GKI 裝置提供了標準 boot.img,您需要將 boot.img 寫入至裝置的 Boot 分區。
-您可以從 [GitHub Release](https://github.com/tiann/KernelSU/releases) 下載 boot.img,請注意,您應該使用正確版本的 boot.img。例如,如果您的裝置顯示核心是 `android12-5.10.101`,需要下載 `android-5.10.101_yyyy-MM.boot-.img`.
+您可以從 [GitHub Release](https://github.com/tiann/KernelSU/releases) 下載 boot.img,請注意,您應該使用正確版本的 boot.img。如果你不知道你該下載哪個檔案,請詳細閱讀文檔中的 [KMI](#kmi) 與[安全性修補程式等級](#security-patch-level)。
-其中 `` 指的是您的官方 boot.img 的核心壓縮格式,請檢查您原有 boot.img 的核心壓縮格式,您應該使用正確的格式,例如 `lz4`、`gz`;如果使用不正確的壓縮格式,刷新 Boot 後可能無法開機。
+通常,在相同的 KMI 和安全性修補程式等級下,會存在三種不同格式的啟動檔案。除了核心壓縮格式之外,它們都是相同的。請檢查您原來的 boot.img 的核心壓縮格式。您應該使用正確的格式,例如 `lz4` 、 `gz`,如果你使用了不正確的壓縮格式,你可能會在寫入後無法開機。
-::: info
-1. 您可以透過 magiskboot 以取得您的原始 Boot 的壓縮格式;當然,您也可以詢問與您相同型號的其他更有經驗的使用者。另外,核心的壓縮格式通常部會出現變更,如果您使用的某個壓縮格式成功開機,後續可以優先嘗試這個格式。
+::: info 關於 boot.img 的壓縮格式
+1. 您可以透過 magiskboot 以取得您的原始 Boot 的壓縮格式。當然,您也可以詢問與您相同型號的其他更有經驗的使用者。另外,核心的壓縮格式通常不會出現變更,如果您使用的某個壓縮格式成功開機,後續可以優先嘗試這個格式。
2. 小米裝置通常 `gz` 或者 **不壓縮**。
3. Pixel 裝置有些特殊,請遵循下方的指示。
:::
-### 將 boot.img 刷新至裝置 {#flash-boot-img-to-device}
+### 將 boot.img 寫入至裝置 {#flash-boot-img-to-device}
-使用 `adb` 連接您的裝置,然後執行 `adb reboot bootloader` 進入 fastboot 模式,然後使用此命令刷新 KernelSU:
+使用 `adb` 連接您的裝置,然後執行 `adb reboot bootloader` 進入 fastboot 模式,然後使用此命令寫入 KernelSU:
```sh
fastboot flash boot boot.img
```
-::: info
-如果您的裝置支援 `fastboot boot`,可以先使用 `fastboot boot boot.img` 來先嘗試使用 boot.img 開機進入系統,如果出現意外,重新啟動即可開機。
+::: info 提示
+如果您的裝置支援 `fastboot boot`,可以先使用 `fastboot boot boot.img` 來嘗試使用 boot.img 開機進入系統,如果出現意外,重新啟動即可開機。
:::
### 重新開機 {#reboot}
-刷新完成後,您應該重新啟動您的裝置:
+寫入完成後,您應該重新啟動您的裝置:
```sh
fastboot reboot
```
-## 手動修補 boot.img {#patch-boot-image}
+## 使用核心寫入程式安裝 {#install-with-kernel-flasher}
+
+先決條件:您的裝置必須已經 Root。例如您已經安裝了 Magisk 並取得 Root 存取權,或者您已經安裝了舊版本的 KernelSU 需升級到其他版本的 KernelSU;如果您的裝置並未 Root,請嘗試其他方法。
+
+步驟:
+
+1. 下載 AnyKernel3 的 Zip 檔。如果你不知道你該下載哪個檔案,請詳細閱讀文檔中的 [KMI](#kmi) 與[安全性修補程式等級](#security-patch-level)。
+2. 開啟核心寫入程式提供的 AnyKernel3 Zip 檔案並寫入核心。
-對於某些裝置來說,其 boot.img 格式並不是很常見,比如 `lz4`,`gz` 和未壓縮;最典型的就是 Pixel,它的 boot.img 格式是 `lz4_legacy` 壓縮,ramdisk 可能是 `gz` 也可能是 `lz4_legacy` 壓縮;此時如果您直接刷新 KernelSU 提供的 boot.img,手機可能無法開機;這時,您可以透過手動修補 boot.img 來完成。
+如果您先前並未使用過核心寫入應用程式,可以嘗試下面幾個:
-一般有兩種修補方法:
+1. [Kernel Flasher](https://github.com/capntrips/KernelFlasher/releases)
+2. [Franco Kernel Manager](https://play.google.com/store/apps/details?id=com.franco.kernel)
+3. [Ex Kernel Manager](https://play.google.com/store/apps/details?id=flar2.exkernelmanager)
+
+P.S. 這種方法在更新 KernelSU 時比較方便,無需電腦即可完成 (注意備份!)。
+
+## 手動修補 boot.img {#patch-boot-image}
-1. [Android-Image-Kitchen](https://forum.xda-developers.com/t/tool-android-image-kitchen-unpack-repack-kernel-ramdisk-win-android-linux-mac.2073775/)
-2. [magiskboot](https://github.com/topjohnwu/Magisk/releases)
+對於某些裝置來說,其 boot.img 格式並不是很常見,不屬於 `lz4`,`gz` 和未壓縮;最典型的就是 Pixel,它的 boot.img 格式是 `lz4_legacy` 壓縮,ramdisk 可能是 `gz` 也可能是 `lz4_legacy` 壓縮;此時如果您直接寫入 KernelSU 提供的 boot.img,手機可能無法開機。這時,您可以透過手動修補 boot.img 來完成。
-其中,Android-Image-Kitchen 適用於在電腦上作業,magiskboot 需要手機協作。
+永遠建議使用 `magiskboot` 來修補映像,一般有兩種修補方法:
-### 準備 {#patch-preparation}
+1. [magiskboot](https://github.com/topjohnwu/Magisk/releases)
+2. [magiskboot_build](https://github.com/ookiineko/magiskboot_build/releases/tag/last-ci)
-1. 取得您手機的原廠 boot.img;您可以聯絡您的裝置製造商,您也可能需要[payload-dumper-go](https://github.com/ssut/payload-dumper-go)
-2. 下載 KernelSU 提供的與您的裝置 KMI 一致地 AnyKernel3 Zip 檔案 (可參閱 *使用自訂 Recovery 安裝*)。
-3. 解壓縮 AnyKernel3 Zip 檔案,取得其中的 `Image` 檔案,此檔案為 KernelSU 的核心檔案。
+其中,官方的 `magiskboot` 僅能在 Android 上使用,若您想在電腦上完成,可以嘗試第二個選項。
-### 使用 Android-Image-Kitchen {#using-android-image-kitchen}
+### 準備 {#preparation}
-1. 下載 Android-Image-Kitchen 至您的電腦。
-2. 將手機原廠 boot.img 放置於 Android-Image-Kitchen 根目錄。
-3. 在 Android-Image-Kitchen 根目錄執行 `./unpackimg.sh boot.img`;此命令會將 boot.img 解除封裝,您會得到一些檔案。
-4. 將 `split_img` 目錄中的 `boot.img-kernel` 取代為您從 AnyKernel3 解壓縮出來的 `Image` (注意名稱變更為 boot.img-kernel)。
-5. 在 Android-Image-Kitchecn 根目錄執行 `./repackimg.sh`;此時您會得到一個 `image-new.img` 檔案;使用此 boot.img 透過 fastboot 刷新即可 (刷新方法請參閱上一章節)。
+1. 取得您手機的原廠 boot.img,您可以從您的裝置製造商取得,您也可能需要 [payload-dumper-go](https://github.com/ssut/payload-dumper-go)。
+2. 下載 KernelSU 提供的與您的裝置 KMI 一致的 AnyKernel3 Zip 檔 (可參閱[使用自訂 Recovery 安裝](#install-with-custom-recovery))。
+3. 解壓縮 AnyKernel3 Zip 檔,取得其中的 `Image` 檔,此檔案為具有 KernelSU 的核心。
-### 使用 magiskboot {#using magiskboot}
+### 在 Android 上使用 magiskboot {#using-magiskboot-on-Android-devices}
-1. 在 Magisk 的 [Release 頁面](https://github.com/topjohnwu/Magisk/releases) 下載最新的 Magisk 安裝套件。
-2. 將 `Magisk-*(version).apk` 重新命名為 `Magisk-*.zip` 然後解壓縮。
-3. 將解壓縮後的 `Magisk-*/lib/arm64-v8a/libmagiskboot.so` 檔案,使用 Adb 推入至手機:`adb push Magisk-*/lib/arm64-v8a/libmagiskboot.so /data/local/tmp/magiskboot`
+1. 在 Magisk 的 [Release 頁面](https://github.com/topjohnwu/Magisk/releases) 下載最新的 Magisk。
+2. 將 `Magisk-*(version).apk` 重新命名為 `Magisk-*.zip` 並解壓縮。
+3. 使用 Adb 將 magiskboot 推入至手機:`adb push Magisk-*/lib/arm64-v8a/libmagiskboot.so /data/local/tmp/magiskboot`。
4. 使用 Adb 將原廠 boot.img 和 AnyKernel3 中的 Image 推入至手機。
-5. adb shell 進入 /data/local/tmp/ 目錄,然後賦予先前推入檔案的可執行權限 `chmod +x magiskboot`
+5. adb shell 進入 /data/local/tmp/ 目錄,然後賦予先前推入的檔案可執行權限 `chmod +x magiskboot`。
6. adb shell 進入 /data/local/tmp/ 目錄,執行 `./magiskboot unpack boot.img` 此時會將 `boot.img` 解除封裝,得到一個名為 `kernel` 的檔案,這個檔案是您的原廠核心。
7. 使用 `Image` 取代 `kernel`: `mv -f Image kernel`
-8. 執行 `./magiskboot repack boot.img` 重新封裝 img,此時您會得到一個 `new-boot.img` 檔案,透過 Fastboot 將這個檔案刷新至裝置即可。
+8. 執行 `./magiskboot repack boot.img` 重新封裝映像,此時您會得到一個 `new-boot.img` 檔案,透過 Fastboot 將這個檔案寫入至裝置即可。
+
+### 在 Windows/macOS/Linux PC 上使用 magiskboot {#using-magiskboot-on-PC}
+
+1. 在 [magiskboot_build](https://github.com/ookiineko/magiskboot_build/releases/tag/last-ci) 下載對應的 magiskboot。
+2. (僅linux)賦予檔案可執行權限 `chmod +x magiskboot`。
+3. 執行 `./magiskboot unpack boot.img` 此時會將 `boot.img` 解除封裝,得到一個名為 `kernel` 的檔案,這個檔案是您的原廠核心。
+4. 使用 `Image` 取代 `kernel`: `mv -f Image kernel`
+5. 執行 `./magiskboot repack boot.img` 重新封裝映像,此時您會得到一個 `new-boot.img` 檔案,透過 Fastboot 將這個檔案寫入至裝置即可。
+
+## 使用自訂 Recovery 安裝 {#install-with-custom-recovery}
+
+先決條件:您的裝置必須有自訂的 Recovery,例如 TWRP。如果沒有或者只有官方 Recovery,請使用其他方法。
+
+步驟:
+
+1. 在 KernelSU 的 [Release 頁面](https://github.com/tiann/KernelSU/releases) 下載與您手機版本相符的以 AnyKernel3 開頭的 Zip 檔;例如,手機核心版本為 `android12-5.10.66`,那麼您應該下載 `AnyKernel3-android12-5.10.66_yyyy-MM.zip` 這個檔案 (其中 `yyyy` 為年份,`MM` 為月份)。
+2. 重新開機手機至 TWRP。
+3. 使用 Adb 將 AnyKernel3-*.zip 放置到手機 `/sdcard` 然後在 TWRP 圖形使用者介面選擇並安裝;或者您也可以直接 `adb sideload AnyKernel-*.zip` 安裝。
+
+PS. 這種方法適用於任何狀況下的安裝 (不限於初次安裝或後續更新),只要您用 TWRP 就可以進行作業。
## GKI的其他替代方法 {#other-methods}
-其實所有這些安裝方法的主旨只有一個,那就是**將原廠核心取代為 KernelSU 提供的核心**;只要能實現這個目的,就可以安裝;比如以下是其他可行的方法:
+其實所有這些安裝方法的主旨只有一個,那就是**將原廠核心取代為 KernelSU 提供的核心**。只要能實現這個目的,就可以安裝,比如以下是其他可行的方法:
+
+1. 首先安裝 Magisk,透過 Magisk 取得 Root 權限後使用核心寫入程式寫入 KernelSU 的 AnyKernel Zip。
+2. 使用某些 PC 上的寫入工具組寫入 KernelSU 提供的核心。
+
+但是,如果不起作用,請嘗試 Magiskboot 方法。
-1. 首先安裝 Magisk,透過 Magisk 取得 Root 權限後使用核心刷新程式刷新 KernelSU 的 AnyKernel Zip。
-2. 使用某些 PC 上的刷新工具組刷新 KernelSU 提供的核心。
diff --git a/website/docs/zh_TW/guide/module-webui.md b/website/docs/zh_TW/guide/module-webui.md
index 5dbdaf7826f2..671faad7a153 100644
--- a/website/docs/zh_TW/guide/module-webui.md
+++ b/website/docs/zh_TW/guide/module-webui.md
@@ -2,11 +2,11 @@
KernelSU 的模組除了執行啟動腳本和修改系統檔案之外,還支援顯示 UI 介面和與使用者互動。
-該模組可以透過任何 Web 技術編寫HTML + CSS + JavaScript頁面。 KernelSU的管理器將透過 WebView 顯示這些頁面。它還提供了一些用於與系統互動的JavaScript API,例如執行shell命令。
+該模組可以透過任何 Web 技術編寫 HTML + CSS + JavaScript 頁面。 KernelSU的管理器將透過 WebView 顯示這些頁面。它還提供了一些用於與系統互動的 JavaScript API,例如執行 shell 命令。
## WebUI 根目錄 {#webroot-directory}
-Web資源應放置在模組根目錄的`webroot`子目錄中,並且其中**必須**有一個名為`index.html`的文件,該檔案是模組頁面入口。
+Web資源應放置在模組根目錄的 `webroot` 子目錄中,並且其中**必須**有一個名為 `index.html` 的文件,該檔案是模組頁面入口。
包含Web介面的最簡單的模組結構如下:
@@ -18,7 +18,7 @@ Web資源應放置在模組根目錄的`webroot`子目錄中,並且其中**必
`-- index.html
```
-:::warning
+:::warning 提醒
安裝模組時,KernelSU 將自動設定`webroot`的權限和 SELinux context。如果您不知道自己在做什麼,請不要自行設定該目錄的權限!
:::
@@ -28,7 +28,7 @@ Web資源應放置在模組根目錄的`webroot`子目錄中,並且其中**必
如果只是一個顯示頁面,那和一般網頁沒有什麼不同。更重要的是,KernelSU 提供了一系列的系統 API,讓您可以實現模組獨特的功能。
-KernelSU 提供了一個 JavaScript 庫並[在 npm 上發布](https://www.npmjs.com/package/kernelsu),您可以在網頁的 JavaScript 程式碼中使用它。
+KernelSU [在 npm 上發布](https://www.npmjs.com/package/kernelsu)了一個 JavaScript 庫,您可以在網頁的 JavaScript 程式碼中使用它。
例如,您可以執行 shell 命令來取得特定配置或修改屬性:
@@ -42,8 +42,9 @@ const { errno, stdout } = exec("getprop ro.product.model");
[API 文檔](https://www.npmjs.com/package/kernelsu)
-如果您發現現有的API無法滿足您的需求或使用不方便,歡迎您在[這裡](https://github.com/tiann/KernelSU/issues)給我們建議!
-## 一些技巧
+如果您發現現有的 API 無法滿足您的需求或使用不方便,歡迎您在[這裡](https://github.com/tiann/KernelSU/issues)給我們建議!
-1. 您可以正常使用`localStorage`來儲存一些數據,但卸載管理器後,這些數據將會遺失。如果需要持久保存,可以自行將資料寫入某個目錄。
-2. 對於簡單的頁面,我建議您使用[parceljs](https://parceljs.org/)進行打包。它無須設定,使用非常方便。不過,如果你是前端高手或有自己的喜好,那就選擇你喜歡的吧!
+## 一些技巧 {#some-tips}
+
+1. 您可以正常使用 `localStorage` 來儲存一些數據,但解除安裝管理器後,這些數據將會遺失。如果需要持久保存,可以自行將資料寫入某個目錄。
+2. 對於簡單的頁面,我建議您使用 [parceljs](https://parceljs.org/) 進行打包。它無須設定,使用非常方便。不過,如果你是前端高手或有自己的喜好,那就選擇你喜歡的吧!
diff --git a/website/docs/zh_TW/guide/module.md b/website/docs/zh_TW/guide/module.md
index 717c862890ec..dac0fec6c3ee 100644
--- a/website/docs/zh_TW/guide/module.md
+++ b/website/docs/zh_TW/guide/module.md
@@ -1,8 +1,8 @@
-# 模組指南 {#introduction}
+# 模組指南 {#module-guide}
-KernelSU 提供了一個模組機制,它可以在保持系統分割區完整性的同時達到修改系統分割區的效果;這種機制一般被稱為 systemless。
+KernelSU 提供了一個模組機制,它可以在保持系統分割區完整性的同時達到修改系統分割區的效果;這種機制一般被稱為 systemless (無系統修改)。
-KernelSU 的模組運作機制與 Magisk 幾乎相同,如果您熟悉 Magisk 模組的開發,那麼開發 KernelSU 的模組大同小異,您可以跳過下列有關模組的介紹,只需要瞭解 [KernelSU 模組與 Magisk 模組的異同](difference-with-magisk.md)。
+KernelSU 的模組運作機制與 Magisk 幾乎相同,如果您熟悉 Magisk 模組的開發,那麼開發 KernelSU 的模組大同小異,您可以跳過下列有關模組的介紹,只需要瞭解 [KernelSU 模組與 Magisk 模組的差異](difference-with-magisk.md)。
## WebUI
@@ -11,20 +11,20 @@ KernelSU 的模組支援顯示互動介面,請參閱 [WebUI 文檔](module-web
## Busybox
KernelSU 提供了一個完備的 BusyBox 二進位檔案 (包括完整的 SELinux 支援)。可執行檔位於 `/data/adb/ksu/bin/busybox`。
-KernelSU 的 BusyBox 支援同時執行時可切換的 "ASH Standalone Shell Mode"。
-這種讀了模式意味著在執行 BusyBox 的 ash shell 時,每個命令都會直接使用 BusyBox 中內建的應用程式,而不論 PATH 的設定為何。
-例如,`ls`、`rm`、`chmod` 等命令將不會使用 PATH 中設定的命令 (在 Android 的狀況下,預設狀況下分別為 `/system/bin/ls`、`/system/bin/rm` 和 `/system/bin/chmod`),而是直接呼叫 BusyBox 內建的應用程式。
+KernelSU 的 BusyBox 支援執行時可切換的 "ASH 獨立模式"。
+ASH 獨立模式在執行 BusyBox 時,每個命令都會直接使用 BusyBox 中內建的應用程式,而不論 `PATH` 的設定為何。
+例如,`ls`、`rm`、`chmod` 等命令將不會使用 `PATH` 中設定的命令 (在 Android 的狀況下,預設狀況下分別為 `/system/bin/ls`、`/system/bin/rm` 和 `/system/bin/chmod`),而是直接呼叫 BusyBox 內建的應用程式。
這確保了腳本始終在可預測的環境中執行,並始終具有完整的命令套件,不論它執行在哪個 Android 版本上。
要強制下一個命令不使用 BusyBox,您必須使用完整路徑呼叫可執行檔。
-在 KernelSU 上下文中執行的每個 shell 腳本都將在 BusyBox 的 ash shell 中以獨立模式執行。對於第三方開發人員相關的內容,包括所有開機腳本和模組安裝腳本。
+每個基於 KernelSU 上下文的腳本都將在 BusyBox 的獨立模式執行。對於第三方開發人員而言,這包括所有開機腳本和模組安裝腳本。
對於想要在 KernelSU 之外使用這個「獨立模式」功能的使用者,有兩種啟用方法:
1. 將環境變數 `ASH_STANDALONE` 設為 `1`。例如:`ASH_STANDALONE=1 /data/adb/ksu/bin/busybox sh