diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 12031898..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,5 +0,0 @@ -# These are supported funding model platforms - -github: tiann -patreon: weishu -custom: https://vxposed.com/donate.html diff --git a/.github/manifests/android-14-avd_x86_64.xml b/.github/manifests/android-14-avd_x86_64.xml deleted file mode 100644 index db2a6c06..00000000 --- a/.github/manifests/android-14-avd_x86_64.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.github/manifests/android-15-avd_aarch64.xml b/.github/manifests/android-15-avd_aarch64.xml deleted file mode 100644 index e3a5e086..00000000 --- a/.github/manifests/android-15-avd_aarch64.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.github/manifests/android-15-avd_x86_64.xml b/.github/manifests/android-15-avd_x86_64.xml deleted file mode 100644 index 0504d8a5..00000000 --- a/.github/manifests/android-15-avd_x86_64.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.github/workflows/add-device.yml b/.github/workflows/add-device.yml deleted file mode 100644 index 0b3a01a7..00000000 --- a/.github/workflows/add-device.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: handle-add-device-issue - -on: - issues: - types: [labeled] - -jobs: - handle-add-device: - if: github.event.label.name == 'add-device' - runs-on: ubuntu-latest - env: - ISSUE_CONTENT: ${{ github.event.issue.body }} - steps: - - uses: actions/checkout@v4 - - name: Parse issue body - id: handle-add-device - run: | - python3 scripts/add_device_handler.py website/docs/repos.json || true - - name: Commit - if: steps.handle-add-device.outputs.success == 'true' - run: | - git config --local user.name "GitHub Actions" - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add website/docs/repos.json - git commit -m "add device: ${{ steps.handle-add-device.outputs.device }}" - - name: Make pull request - if: steps.handle-add-device.outputs.success == 'true' - id: cpr - uses: peter-evans/create-pull-request@v6 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "[add device]: ${{ steps.handle-add-device.outputs.device }}" - title: "[add device]: ${{ steps.handle-add-device.outputs.device }}" - body: | - ${{ steps.handle-add-device.outputs.device }} has been added to the website. - Related issue: ${{ github.event.issue.html_url }} - branch: "add-device-${{ github.event.issue.number }}" - labels: add-device - delete-branch: true - - name: Check outputs - if: ${{ steps.cpr.outputs.pull-request-number }} - run: | - echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" - echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" - - uses: Kernel-SU/actions-comment-on-issue@master - if: ${{ steps.cpr.outputs.pull-request-number }} - with: - message: "Automatically created pull request: ${{ steps.cpr.outputs.pull-request-url }}" - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: Kernel-SU/actions-comment-on-issue@master - if: steps.handle-add-device.outputs.success != 'true' - with: - message: "Cannot create pull request. Please check the issue content. Or you can create a pull request manually." - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: close issue - uses: peter-evans/close-issue@v3 - with: - issue-number: ${{ github.event.issue.number }} - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/avd-kernel.yml b/.github/workflows/avd-kernel.yml deleted file mode 100644 index c09bda5a..00000000 --- a/.github/workflows/avd-kernel.yml +++ /dev/null @@ -1,137 +0,0 @@ -name: GKI Kernel Build - -on: - workflow_call: - inputs: - version_name: - required: true - type: string - description: > - With SUBLEVEL of kernel, - for example: android12-5.10.66 - arch: - required: true - type: string - description: > - Build arch: aarch64/x86_64 - debug: - required: false - type: boolean - default: true - manifest_name: - required: false - type: string - description: > - Local repo manifest xml path, - typically for AVD kernel build. - secrets: - BOOT_SIGN_KEY: - required: false - CHAT_ID: - required: false - BOT_TOKEN: - required: false - MESSAGE_THREAD_ID: - required: false - -jobs: - build: - name: Build ${{ inputs.version_name }} - runs-on: ubuntu-latest - steps: - - name: Maximize build space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 8192 - temp-reserve-mb: 2048 - remove-dotnet: 'true' - remove-android: 'true' - remove-haskell: 'true' - remove-codeql: 'true' - - - uses: actions/checkout@v4 - with: - path: KernelSU - fetch-depth: 0 - - - name: Setup need_upload - id: need_upload - run: | - if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then - echo "UPLOAD=true" >> $GITHUB_OUTPUT - else - echo "UPLOAD=false" >> $GITHUB_OUTPUT - fi - - - name: Setup kernel source - run: | - echo "Free space:" - df -h - cd $GITHUB_WORKSPACE - sudo apt-get install repo -y - mkdir android-kernel && cd android-kernel - repo init --depth=1 -u https://android.googlesource.com/kernel/manifest -m "$GITHUB_WORKSPACE/KernelSU/.github/manifests/${{ inputs.manifest_name }}" --repo-rev=v2.16 - repo --version - repo --trace sync -c -j$(nproc --all) --no-tags - df -h - - - name: Setup KernelSU - env: - PATCH_PATH: ${{ inputs.patch_path }} - IS_DEBUG_KERNEL: ${{ inputs.debug }} - run: | - cd $GITHUB_WORKSPACE/android-kernel - echo "[+] KernelSU setup" - GKI_ROOT=$(pwd) - echo "[+] GKI_ROOT: $GKI_ROOT" - echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers" - ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu - echo "[+] Add KernelSU driver to Makefile" - DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile - DRIVER_KCONFIG=$GKI_ROOT/common/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 $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found" - - if [ "$IS_DEBUG_KERNEL" = "true" ]; then - echo "[+] Enable debug features for kernel" - printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile - fi - repo status - echo "[+] KernelSU setup done." - cd $GITHUB_WORKSPACE/KernelSU - VERSION=$(($(git rev-list --count HEAD) + 10200)) - echo "VERSION: $VERSION" - echo "kernelsu_version=$VERSION" >> $GITHUB_ENV - - - name: Make working directory clean to avoid dirty - working-directory: android-kernel - run: | - rm common/android/abi_gki_protected_exports_* || echo "No protected exports!" - git config --global user.email "bot@kernelsu.org" - git config --global user.name "KernelSUBot" - cd common/ && git add -A && git commit -a -m "Add KernelSU" - repo status - - - name: Build kernel - working-directory: android-kernel - run: | - if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then - export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }} - export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }} - fi - tools/bazel run --config=fast --config=stamp --lto=thin //common-modules/virtual-device:virtual_device_${{ inputs.arch }}_dist -- --dist_dir=dist - NAME=kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }} - TARGET_IMAGE=dist/bzImage - if [ ! -e $TARGET_IMAGE ]; then - TARGET_IMAGE=dist/Image - fi - mv $TARGET_IMAGE $NAME - echo "file_path=android-kernel/$NAME" >> $GITHUB_ENV - - - name: Upload Kernel - uses: actions/upload-artifact@v4 - with: - name: kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }} - path: "${{ env.file_path }}" diff --git a/.github/workflows/build-debug-kernel.yml b/.github/workflows/build-debug-kernel.yml deleted file mode 100644 index a0cab91b..00000000 --- a/.github/workflows/build-debug-kernel.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Build debug kernel -on: - workflow_dispatch: - -jobs: - build-debug-kernel-a12: - 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 - patch_path: "5.10" - debug: true - build-debug-kernel-a13: - strategy: - matrix: - include: - - version: "5.10" - sub_level: 209 - os_patch_level: 2024-05 - - version: "5.15" - sub_level: 148 - os_patch_level: 2024-05 - uses: ./.github/workflows/gki-kernel.yml - with: - version: android13-${{ matrix.version }} - version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }} - tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }} - patch_path: ${{ matrix.version }} - debug: true - build-debug-kernel-a14: - strategy: - matrix: - include: - - version: "5.15" - sub_level: 148 - os_patch_level: 2024-05 - - version: "6.1" - sub_level: 75 - os_patch_level: 2024-05 - 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 \ No newline at end of file diff --git a/.github/workflows/build-kernel-a12.yml b/.github/workflows/build-kernel-a12.yml deleted file mode 100644 index 89f9c984..00000000 --- a/.github/workflows/build-kernel-a12.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: Build Kernel - Android 12 -on: - push: - branches: ["main", "ci", "checkci"] - paths: - - ".github/workflows/build-kernel-a12.yml" - - ".github/workflows/gki-kernel.yml" - - ".github/scripts/build_a12.sh" - - "kernel/**" - pull_request: - branches: ["main"] - paths: - - ".github/workflows/build-kernel-a12.yml" - - ".github/workflows/gki-kernel.yml" - - ".github/scripts/build-a12.sh" - - "kernel/**" - workflow_call: -jobs: - build-kernel: - if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci' - strategy: - matrix: - include: - - sub_level: 198 - os_patch_level: 2024-01 - - sub_level: 205 - os_patch_level: 2024-03 - - sub_level: 209 - os_patch_level: 2024-05 - uses: ./.github/workflows/gki-kernel.yml - secrets: inherit - with: - version: android12-5.10 - version_name: android12-5.10.${{ matrix.sub_level }} - tag: android12-5.10-${{ matrix.os_patch_level }} - os_patch_level: ${{ matrix.os_patch_level }} - patch_path: "5.10" - - 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-2023 - 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_a12.sh - - - name: Display structure of boot files - run: ls -R - - - name: Upload images artifact - uses: actions/upload-artifact@v4 - with: - name: boot-images-android12 - path: Image-android12*/*.img.gz - - check-build-kernel: - if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci' - 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 - 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 deleted file mode 100644 index 9390b48e..00000000 --- a/.github/workflows/build-kernel-a13.yml +++ /dev/null @@ -1,145 +0,0 @@ -name: Build Kernel - Android 13 -on: - push: - branches: ["main", "ci", "checkci"] - paths: - - ".github/workflows/build-kernel-a13.yml" - - ".github/workflows/gki-kernel.yml" - - ".github/scripts/build_a13.sh" - - "kernel/**" - pull_request: - branches: ["main"] - paths: - - ".github/workflows/build-kernel-a13.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: "5.10" - sub_level: 189 - os_patch_level: 2023-11 - - version: "5.10" - sub_level: 198 - os_patch_level: 2024-01 - - version: "5.10" - sub_level: 205 - os_patch_level: 2024-03 - - version: "5.10" - sub_level: 209 - os_patch_level: 2024-05 - - version: "5.15" - sub_level: 123 - os_patch_level: 2023-11 - - version: "5.15" - sub_level: 137 - os_patch_level: 2024-01 - - version: "5.15" - sub_level: 144 - os_patch_level: 2024-03 - - version: "5.15" - sub_level: 148 - os_patch_level: 2024-05 - uses: ./.github/workflows/gki-kernel.yml - secrets: inherit - with: - version: android13-${{ matrix.version }} - version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }} - tag: android13-${{ 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-2023 - 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-android13 - path: Image-android13*/*.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: "5.10" - sub_level: 209 - os_patch_level: 2024-05 - - version: "5.15" - sub_level: 148 - os_patch_level: 2024-05 - uses: ./.github/workflows/gki-kernel.yml - with: - version: android13-${{ matrix.version }} - version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }} - tag: android13-${{ 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-a14.yml b/.github/workflows/build-kernel-a14.yml deleted file mode 100644 index a06f02b1..00000000 --- a/.github/workflows/build-kernel-a14.yml +++ /dev/null @@ -1,148 +0,0 @@ -name: Build Kernel - Android 14 -on: - push: - branches: ["main", "ci", "checkci"] - paths: - - ".github/workflows/build-kernel-a14.yml" - - ".github/workflows/gki-kernel.yml" - - ".github/scripts/build_a13.sh" - - "kernel/**" - pull_request: - branches: ["main"] - paths: - - ".github/workflows/build-kernel-a14.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: "5.15" - sub_level: 131 - os_patch_level: 2023-11 - - version: "5.15" - sub_level: 137 - os_patch_level: 2024-01 - - version: "5.15" - sub_level: 144 - os_patch_level: 2024-03 - - version: "5.15" - sub_level: 148 - os_patch_level: 2024-05 - - version: "6.1" - sub_level: 25 - os_patch_level: 2023-10 - - version: "6.1" - sub_level: 43 - os_patch_level: 2023-11 - - version: "6.1" - sub_level: 57 - os_patch_level: 2024-01 - - version: "6.1" - sub_level: 68 - os_patch_level: 2024-03 - - version: "6.1" - sub_level: 75 - os_patch_level: 2024-05 - uses: ./.github/workflows/gki-kernel.yml - secrets: inherit - with: - version: android14-${{ matrix.version }} - version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }} - tag: android14-${{ 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-2023 - 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-android14 - path: Image-android14*/*.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: "5.15" - sub_level: 148 - os_patch_level: 2024-05 - - version: "6.1" - sub_level: 75 - os_patch_level: 2024-05 - 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 }} - 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 deleted file mode 100644 index 18c97c2f..00000000 --- a/.github/workflows/build-kernel-arcvm.yml +++ /dev/null @@ -1,135 +0,0 @@ -name: Build Kernel - ChromeOS ARCVM -on: - push: - branches: ["main", "ci", "checkci"] - paths: - - ".github/workflows/build-kernel-arcvm.yml" - - "kernel/**" - pull_request: - branches: ["main"] - paths: - - ".github/workflows/build-kernel-arcvm.yml" - - "kernel/**" - workflow_call: - workflow_dispatch: - -env: - git_tag: chromeos-5.10-arcvm - -jobs: - build: - if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && !github.event.pull_request.draft) - strategy: - matrix: - include: - - arch: x86_64 - kernel_image_name: bzImage - build_config: build.config.gki.x86_64 - defconfig: x86_64_arcvm_defconfig - - arch: arm64 - kernel_image_name: Image - build_config: build.config.gki.aarch64 - defconfig: arm64_arcvm_defconfig - - name: Build ChromeOS ARCVM kernel - runs-on: ubuntu-20.04 - env: - LTO: thin - ROOT_DIR: / - KERNEL_DIR: ${{ github.workspace }}/kernel - - steps: - - name: Install Build Tools - run: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends bc \ - bison build-essential ca-certificates flex git gnupg \ - libelf-dev libssl-dev lsb-release software-properties-common wget \ - libncurses-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu nuget gzip \ - rsync python3 device-tree-compiler - - sudo ln -s --force python3 /usr/bin/python - - export LLVM_VERSION=12 - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh $LLVM_VERSION - rm ./llvm.sh - sudo ln -s --force /usr/bin/clang-$LLVM_VERSION /usr/bin/clang - sudo ln -s --force /usr/bin/ld.lld-$LLVM_VERSION /usr/bin/ld.lld - sudo ln -s --force /usr/bin/llvm-objdump-$LLVM_VERSION /usr/bin/llvm-objdump - sudo ln -s --force /usr/bin/llvm-ar-$LLVM_VERSION /usr/bin/llvm-ar - sudo ln -s --force /usr/bin/llvm-nm-$LLVM_VERSION /usr/bin/llvm-nm - sudo ln -s --force /usr/bin/llvm-strip-$LLVM_VERSION /usr/bin/llvm-strip - sudo ln -s --force /usr/bin/llvm-objcopy-$LLVM_VERSION /usr/bin/llvm-objcopy - sudo ln -s --force /usr/bin/llvm-readelf-$LLVM_VERSION /usr/bin/llvm-readelf - sudo ln -s --force /usr/bin/clang++-$LLVM_VERSION /usr/bin/clang++ - - - name: Checkout KernelSU - uses: actions/checkout@v4 - with: - path: KernelSU - fetch-depth: 0 - - - name: Setup kernel source - run: git clone https://chromium.googlesource.com/chromiumos/third_party/kernel.git -b ${{ env.git_tag }} --depth=1 - - - name: Extract version from Makefile - working-directory: kernel - run: | - VERSION=$(grep -E '^VERSION = ' Makefile | awk '{print $3}') - PATCHLEVEL=$(grep -E '^PATCHLEVEL = ' Makefile | awk '{print $3}') - 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: | - echo "[+] KernelSU setup" - KERNEL_ROOT=$GITHUB_WORKSPACE/kernel - echo "[+] KERNEL_ROOT: $KERNEL_ROOT" - echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers" - ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu - - echo "[+] Add KernelSU driver to Makefile" - DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile - grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE - - echo "[+] Apply KernelSU patches" - cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch || echo "[-] No patch found" - - echo "[+] Patch script/setlocalversion" - sed -i 's/-dirty//g' $KERNEL_ROOT/scripts/setlocalversion - - echo "[+] KernelSU setup done." - cd $GITHUB_WORKSPACE/KernelSU - KSU_VERSION=$(($(git rev-list --count HEAD) + 10200)) - echo "KernelSU version: $KSU_VERSION" - echo "kernelsu_version=$KSU_VERSION" >> $GITHUB_ENV - - - name: Build Kernel - working-directory: kernel - env: - KERNEL_IMAGE_NAME: ${{ matrix.kernel_image_name }} - ARCH: ${{ matrix.arch }} - run: | - set -a && . ${{ matrix.build_config }}; set +a - export DEFCONFIG=${{ matrix.defconfig }} - if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then - export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }} - export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }} - fi - - make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} mrproper - make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} ${DEFCONFIG} < /dev/null - scripts/config --file .config -e LTO_CLANG -d LTO_NONE -e LTO_CLANG_THIN -d LTO_CLANG_FULL -e THINLTO - make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} -j$(nproc) ${KERNEL_IMAGE_NAME} modules prepare-objtool - ls -l -h ${PWD}/arch/${ARCH}/boot - echo "file_path=${PWD}/arch/${ARCH}/boot/${KERNEL_IMAGE_NAME}" >> $GITHUB_ENV - - - name: Upload kernel-ARCVM-${{ matrix.arch }}-${{ env.version }} - uses: actions/upload-artifact@v4 - with: - name: kernel-ARCVM-${{ matrix.arch }}-${{ env.version }} - path: "${{ env.file_path }}" diff --git a/.github/workflows/build-kernel-avd.yml b/.github/workflows/build-kernel-avd.yml deleted file mode 100644 index 504a5207..00000000 --- a/.github/workflows/build-kernel-avd.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Build Kernel - AVD -on: - push: - branches: ["main", "ci", "checkci"] - paths: - - ".github/workflows/build-kernel-avd.yml" - - ".github/workflows/avd-kernel.yml" - - ".github/workflows/manifests/*xml" - - "kernel/**" - pull_request: - branches: ["main"] - paths: - - ".github/workflows/build-kernel-avd.yml" - - ".github/workflows/avd-kernel.yml" - - ".github/workflows/manifests/*.xml" - - "kernel/**" - workflow_call: - workflow_dispatch: -jobs: - build-kernel: - if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci' - uses: ./.github/workflows/avd-kernel.yml - secrets: inherit - strategy: - matrix: - include: - - version: "android-14-avd_x86_64" - manifest: "android-14-avd_x86_64.xml" - arch: "x86_64" - - version: "android-15-avd_aarch64" - manifest: "android-15-avd_aarch64.xml" - arch: "aarch64" - - version: "android-15-avd_x86_64" - manifest: "android-15-avd_x86_64.xml" - arch: "x86_64" - with: - version_name: ${{ matrix.version }} - manifest_name: ${{ matrix.manifest }} - arch: ${{ matrix.arch }} - debug: true diff --git a/.github/workflows/build-kernel-wsa.yml b/.github/workflows/build-kernel-wsa.yml deleted file mode 100644 index 9a313de9..00000000 --- a/.github/workflows/build-kernel-wsa.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Build Kernel - WSA -on: - push: - branches: ["main", "ci", "checkci"] - paths: - - ".github/workflows/build-kernel-wsa.yml" - - ".github/workflows/wsa-kernel.yml" - - "kernel/**" - pull_request: - branches: ["main"] - paths: - - ".github/workflows/build-kernel-wsa.yml" - - ".github/workflows/wsa-kernel.yml" - - "kernel/**" - workflow_call: - workflow_dispatch: - -jobs: - build: - if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci' - strategy: - matrix: - arch: [x86_64, arm64] - version: ["5.15.94.2", "5.15.104.1", "5.15.104.2", "5.15.104.3", "5.15.104.4"] - uses: ./.github/workflows/wsa-kernel.yml - with: - arch: ${{ matrix.arch }} - version: ${{ matrix.version }} - - check_build: - if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci' - uses: ./.github/workflows/wsa-kernel.yml - strategy: - matrix: - arch: [x86_64, arm64] - with: - arch: ${{ matrix.arch }} - version: "5.15.104.4" \ No newline at end of file diff --git a/.github/workflows/build-lkm.yml b/.github/workflows/build-lkm.yml deleted file mode 100644 index 5a14ce1b..00000000 --- a/.github/workflows/build-lkm.yml +++ /dev/null @@ -1,38 +0,0 @@ -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: 209 - os_patch_level: 2024-05 - - version: "android13-5.10" - sub_level: 209 - os_patch_level: 2024-05 - - version: "android13-5.15" - sub_level: 148 - os_patch_level: 2024-05 - - version: "android14-5.15" - sub_level: 148 - os_patch_level: 2024-05 - - version: "android14-6.1" - sub_level: 75 - os_patch_level: 2024-05 - 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 deleted file mode 100644 index b5013641..00000000 --- a/.github/workflows/build-manager.yml +++ /dev/null @@ -1,160 +0,0 @@ -name: Build Manager - -on: - push: - branches: [ "main", "ci" ] - paths: - - '.github/workflows/build-manager.yml' - - 'manager/**' - - 'kernel/**' - - 'userspace/ksud/**' - pull_request: - branches: [ "main" ] - paths: - - 'manager/**' - workflow_call: - -jobs: - build-lkm: - uses: ./.github/workflows/build-lkm.yml - secrets: inherit - - build-ksud: - needs: build-lkm - strategy: - matrix: - include: - - target: aarch64-linux-android - 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 }} - - build-manager: - needs: build-ksud - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./manager - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup need_upload - id: need_upload - run: | - if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then - echo "UPLOAD=true" >> $GITHUB_OUTPUT - else - echo "UPLOAD=false" >> $GITHUB_OUTPUT - fi - - - 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' - } >> gradle.properties - echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks - fi - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 21 - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 - with: - gradle-home-cache-cleanup: true - - - name: Download arm64 ksud - uses: actions/download-artifact@v4 - with: - name: ksud-aarch64-linux-android - path: . - - - name: Download x86_64 ksud - uses: actions/download-artifact@v4 - with: - name: ksud-x86_64-linux-android - path: . - - - name: Copy ksud to app jniLibs - run: | - mkdir -p app/src/main/jniLibs/arm64-v8a - mkdir -p app/src/main/jniLibs/x86_64 - cp -f ../aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud.so - cp -f ../x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud.so - - - name: Build with Gradle - run: | - { - echo 'org.gradle.parallel=true' - echo 'org.gradle.vfs.watch=true' - echo 'org.gradle.jvmargs=-Xmx2048m' - echo 'android.native.buildOutput=verbose' - } >> gradle.properties - sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties - ./gradlew clean assembleRelease - - - name: Upload build artifact - uses: actions/upload-artifact@v4 - if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }} - with: - name: manager - path: manager/app/build/outputs/apk/release/*.apk - - - name: Upload mappings - uses: actions/upload-artifact@v4 - if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }} - with: - name: "mappings" - path: "manager/app/build/outputs/mapping/release/" - - - name: Bot session cache - if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true' - id: bot_session_cache - uses: actions/cache@v4 - with: - path: scripts/ksubot.session - key: ${{ runner.os }}-bot-session - - - name: Upload to telegram - if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true' - 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 }} - TITLE: Manager - run: | - if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then - export VERSION=$(git rev-list --count HEAD) - APK=$(find ./app/build/outputs/apk/release -name "*.apk") - pip3 install telethon - python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK - fi \ No newline at end of file diff --git a/.github/workflows/build-su.yml b/.github/workflows/build-su.yml deleted file mode 100644 index 2fbb93a9..00000000 --- a/.github/workflows/build-su.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Build SU -on: - push: - branches: [ "main", "ci" ] - paths: - - '.github/workflows/build-su.yml' - - 'userspace/su/**' - - 'scripts/ksubot.py' - pull_request: - branches: [ "main" ] - paths: - - 'userspace/su/**' -jobs: - build-su: - name: Build userspace su - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup need_upload - id: need_upload - run: | - if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then - echo "UPLOAD=true" >> $GITHUB_OUTPUT - 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 - - name: Upload a Build Artifact - uses: actions/upload-artifact@v4 - with: - name: su - path: ./userspace/su/libs \ No newline at end of file diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml deleted file mode 100644 index 2ea5bc48..00000000 --- a/.github/workflows/clippy.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Clippy check - -on: - push: - branches: - - main - paths: - - '.github/workflows/clippy.yml' - - 'userspace/ksud/**' - pull_request: - branches: - - main - paths: - - '.github/workflows/clippy.yml' - - 'userspace/ksud/**' - -env: - RUSTFLAGS: '-Dwarnings' - -jobs: - clippy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: rustup update --force-non-host stable-x86_64-unknown-linux-gnu - - uses: Swatinem/rust-cache@v2 - with: - workspaces: userspace/ksud - - - name: Install cross - run: | - cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1 - - - name: Run clippy - run: | - cross clippy --manifest-path userspace/ksud/Cargo.toml --target aarch64-linux-android --release - cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml deleted file mode 100644 index b2b2b763..00000000 --- a/.github/workflows/deploy-website.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Deploy Website - -on: - push: - branches: - - main - - website - paths: - - '.github/workflows/deploy-website.yml' - - 'website/**' - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: pages - cancel-in-progress: false - -jobs: - # Build job - build: - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./website - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Not needed if lastUpdated is not enabled - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: yarn # or pnpm / yarn - cache-dependency-path: website/yarn.lock - - name: Setup Pages - uses: actions/configure-pages@v5 - - name: Install dependencies - run: yarn install --frozen-lockfile - - name: Build with VitePress - run: | - yarn docs:build - touch docs/.vitepress/dist/.nojekyll - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: website/docs/.vitepress/dist - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - needs: build - runs-on: ubuntu-latest - name: Deploy - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/.github/workflows/gki-kernel.yml b/.github/workflows/gki-kernel.yml deleted file mode 100644 index a70977d9..00000000 --- a/.github/workflows/gki-kernel.yml +++ /dev/null @@ -1,251 +0,0 @@ -name: GKI Kernel Build - -on: - workflow_call: - inputs: - version: - required: true - type: string - description: > - Output directory of gki, - for example: android12-5.10 - version_name: - required: true - type: string - description: > - With SUBLEVEL of kernel, - for example: android12-5.10.66 - tag: - required: true - type: string - description: > - Part of branch name of common kernel manifest, - for example: android12-5.10-2021-11 - os_patch_level: - required: false - type: string - description: > - Patch level of common kernel manifest, - for example: 2021-11 - default: 2022-05 - patch_path: - required: false - type: string - description: > - Directory name of .github/patches/ - for example: 5.10 - use_cache: - required: false - type: boolean - default: true - embed_ksud: - required: false - type: string - default: ksud-aarch64-linux-android - description: > - Artifact name of prebuilt ksud to be embedded - for example: ksud-aarch64-linux-android - debug: - required: false - type: boolean - default: false - build_lkm: - required: false - type: boolean - default: false - secrets: - BOOT_SIGN_KEY: - required: false - CHAT_ID: - required: false - BOT_TOKEN: - required: false - MESSAGE_THREAD_ID: - required: false - -jobs: - build: - name: Build ${{ inputs.version_name }} - runs-on: ubuntu-latest - env: - CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion" - CCACHE_NOHASHDIR: "true" - CCACHE_HARDLINK: "true" - steps: - - name: Maximize build space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 8192 - temp-reserve-mb: 2048 - remove-dotnet: 'true' - remove-android: 'true' - remove-haskell: 'true' - remove-codeql: 'true' - - - uses: actions/checkout@v4 - with: - path: KernelSU - fetch-depth: 0 - - - name: Setup need_upload - id: need_upload - run: | - if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then - echo "UPLOAD=true" >> $GITHUB_OUTPUT - else - echo "UPLOAD=false" >> $GITHUB_OUTPUT - fi - - - name: Setup kernel source - run: | - echo "Free space:" - df -h - cd $GITHUB_WORKSPACE - sudo apt-get install repo -y - mkdir android-kernel && cd android-kernel - repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.16 - REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${{ inputs.tag }}) - DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml - if grep -q deprecated <<< $REMOTE_BRANCH; then - echo "Found deprecated branch: ${{ inputs.tag }}" - sed -i 's/"${{ inputs.tag }}"/"deprecated\/${{ inputs.tag }}"/g' $DEFAULT_MANIFEST_PATH - cat $DEFAULT_MANIFEST_PATH - fi - repo --version - repo --trace sync -c -j$(nproc --all) --no-tags - df -h - - - name: Setup KernelSU - env: - PATCH_PATH: ${{ inputs.patch_path }} - IS_DEBUG_KERNEL: ${{ inputs.debug }} - run: | - cd $GITHUB_WORKSPACE/android-kernel - echo "[+] KernelSU setup" - GKI_ROOT=$(pwd) - echo "[+] GKI_ROOT: $GKI_ROOT" - echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers" - ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu - echo "[+] Add KernelSU driver to Makefile" - DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile - DRIVER_KCONFIG=$GKI_ROOT/common/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 $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found" - - if [ "$IS_DEBUG_KERNEL" = "true" ]; then - echo "[+] Enable debug features for kernel" - printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile - fi - repo status - echo "[+] KernelSU setup done." - - - name: Symbol magic - run: | - echo "[+] Export all symbol from abi_gki_aarch64.xml" - COMMON_ROOT=$GITHUB_WORKSPACE/android-kernel/common - KSU_ROOT=$GITHUB_WORKSPACE/KernelSU - ABI_XML=$COMMON_ROOT/android/abi_gki_aarch64.xml - SYMBOL_LIST=$COMMON_ROOT/android/abi_gki_aarch64 - # python3 $KSU_ROOT/scripts/abi_gki_all.py $ABI_XML > $SYMBOL_LIST - echo "[+] Add KernelSU symbols" - cat $KSU_ROOT/kernel/export_symbol.txt | awk '{sub("[ \t]+","");print " "$0}' >> $SYMBOL_LIST - - - name: Setup ccache - if: inputs.use_cache == true - uses: hendrikmuhs/ccache-action@v1 - with: - key: gki-kernel-aarch64-${{ inputs.version_name }} - max-size: 2G - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - - name: Setup for LKM - if: ${{ inputs.build_lkm == true }} - working-directory: android-kernel - run: | - pip install ast-grep-cli - sudo apt-get install llvm-15 -y - ast-grep -U -p '$$$ check_exports($$$) {$$$}' -r '' common/scripts/mod/modpost.c - ast-grep -U -p 'check_exports($$$);' -r '' common/scripts/mod/modpost.c - sed -i '/config KSU/,/help/{s/default y/default m/}' common/drivers/kernelsu/Kconfig - echo "drivers/kernelsu/kernelsu.ko" >> common/android/gki_aarch64_modules - - # bazel build, android14-5.15, android14-6.1 use bazel - if [ ! -e build/build.sh ]; then - sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found" - if [ -e common/modules.bzl ]; then - sed -i 's/_COMMON_GKI_MODULES_LIST = \[/_COMMON_GKI_MODULES_LIST = \[ "drivers\/kernelsu\/kernelsu.ko",/g' common/modules.bzl - fi - else - TARGET_FILE="build/kernel/build.sh" - if [ ! -e "$TARGET_FILE" ]; then - TARGET_FILE="build/build.sh" - fi - sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' $TARGET_FILE || echo "No unknown symbol in $TARGET_FILE" - sed -i 's/if ! diff -u "\${KERNEL_DIR}\/\${MODULES_ORDER}" "\${OUT_DIR}\/modules\.order"; then/if false; then/g' $TARGET_FILE - sed -i 's@${ROOT_DIR}/build/abi/compare_to_symbol_list@echo@g' $TARGET_FILE - sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found" - fi - - - name: Make working directory clean to avoid dirty - working-directory: android-kernel - run: | - rm common/android/abi_gki_protected_exports_* || echo "No protected exports!" - git config --global user.email "bot@kernelsu.org" - git config --global user.name "KernelSUBot" - cd common/ && git add -A && git commit -a -m "Add KernelSU" - repo status - - - name: Build Kernel/LKM - working-directory: android-kernel - run: | - if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then - export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }} - export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }} - fi - if [ -e build/build.sh ]; then - LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang" - else - tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist - fi - - - name: Prepare artifacts - id: prepareArtifacts - run: | - OUTDIR=android-kernel/out/${{ inputs.version }}/dist - if [ ! -e $OUTDIR ]; then - OUTDIR=android-kernel/dist - fi - mkdir output - if [ "${{ inputs.build_lkm}}" = "true" ]; then - llvm-strip-15 -d $OUTDIR/kernelsu.ko - mv $OUTDIR/kernelsu.ko ./output/${{ inputs.version }}_kernelsu.ko - else - cp $OUTDIR/Image ./output/ - cp $OUTDIR/Image.lz4 ./output/ - git clone https://github.com/Kernel-SU/AnyKernel3 - rm -rf ./AnyKernel3/.git - cp $OUTDIR/Image ./AnyKernel3/ - fi - - - name: Upload Image and Image.gz - uses: actions/upload-artifact@v4 - if: ${{ inputs.build_lkm == false }} - with: - name: Image-${{ inputs.version_name }}_${{ inputs.os_patch_level }} - path: ./output/* - - - name: Upload AnyKernel3 - if: ${{ inputs.build_lkm == false }} - uses: actions/upload-artifact@v4 - with: - name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }} - path: ./AnyKernel3/* - - - name: Upload LKM - uses: actions/upload-artifact@v4 - if: ${{ inputs.build_lkm == true }} - with: - name: ${{ inputs.version }}-lkm - path: ./output/*_kernelsu.ko \ No newline at end of file diff --git a/.github/workflows/ksud.yml b/.github/workflows/ksud.yml deleted file mode 100644 index e0fe80a1..00000000 --- a/.github/workflows/ksud.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Build ksud -on: - workflow_call: - inputs: - target: - required: true - type: string - os: - required: false - type: string - default: ubuntu-latest - pack_lkm: - required: false - type: boolean - default: true - use_cache: - required: false - type: boolean - default: true -jobs: - build: - runs-on: ${{ inputs.os }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Download artifacts - uses: actions/download-artifact@v4 - - - name: Prepare LKM fies - if: ${{ inputs.pack_lkm }} - run: | - cp android*-lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/ - - - name: Setup rustup - run: | - rustup update stable - rustup target add x86_64-apple-darwin - rustup target add aarch64-apple-darwin - - uses: Swatinem/rust-cache@v2 - with: - workspaces: userspace/ksud - cache-targets: false - - - name: Install cross - run: | - cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1 - - - name: Build ksud - run: CROSS_NO_WARNINGS=0 cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml - - - name: Upload ksud artifact - uses: actions/upload-artifact@v4 - with: - name: ksud-${{ inputs.target }} - path: userspace/ksud/target/**/release/ksud* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 26b3171c..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: Release -on: - push: - tags: - - "v*" - workflow_dispatch: - -jobs: - build-manager: - uses: ./.github/workflows/build-manager.yml - secrets: inherit - build-a12-kernel: - uses: ./.github/workflows/build-kernel-a12.yml - secrets: inherit - build-a13-kernel: - uses: ./.github/workflows/build-kernel-a13.yml - secrets: inherit - build-a14-kernel: - uses: ./.github/workflows/build-kernel-a14.yml - secrets: inherit - build-wsa-kernel: - uses: ./.github/workflows/build-kernel-wsa.yml - secrets: inherit - build-arcvm-kernel: - uses: ./.github/workflows/build-kernel-arcvm.yml - secrets: inherit - release: - needs: - - build-manager - - build-a12-kernel - - build-a13-kernel - - build-a14-kernel - - build-wsa-kernel - - build-arcvm-kernel - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v4 - - name: Zip AnyKernel3 - run: | - for dir in AnyKernel3-*; do - if [ -d "$dir" ]; then - echo "----- Zip $dir -----" - (cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..) - fi - done - - - name: Zip WSA kernel - run: | - for dir in kernel-WSA-*; do - if [ -d "$dir" ]; then - echo "------ Zip $dir ----------" - (cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..) - fi - done - - - name: Zip ChromeOS ARCVM kernel - run: | - for dir in kernel-ARCVM-*; do - if [ -d "$dir" ]; then - echo "------ Zip $dir ----------" - (cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..) - fi - done - - - name: Display structure of downloaded files - run: ls -R - - - name: release - uses: softprops/action-gh-release@v2 - with: - files: | - manager/*.apk - android*-lkm/*_kernelsu.ko - AnyKernel3-*.zip - boot-images-*/Image-*/*.img.gz - kernel-WSA*.zip - kernel-ARCVM*.zip - ksud-* diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml deleted file mode 100644 index 18a178b6..00000000 --- a/.github/workflows/rustfmt.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Rustfmt check - -on: - push: - branches: - - 'main' - paths: - - '.github/workflows/rustfmt.yml' - - 'userspace/ksud/**' - pull_request: - branches: - - 'main' - paths: - - '.github/workflows/rustfmt.yml' - - 'userspace/ksud/**' - -permissions: - checks: write - -jobs: - format: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: dtolnay/rust-toolchain@nightly - with: - components: rustfmt - - - uses: LoliGothick/rustfmt-check@master - with: - token: ${{ github.token }} - working-directory: userspace/ksud diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml deleted file mode 100644 index f864e05f..00000000 --- a/.github/workflows/shellcheck.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: ShellCheck - -on: - push: - branches: - - 'main' - paths: - - '.github/workflows/shellcheck.yml' - - '**/*.sh' - pull_request: - branches: - - 'main' - paths: - - '.github/workflows/shellcheck.yml' - - '**/*.sh' - -jobs: - shellcheck: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Run ShellCheck - uses: ludeeus/action-shellcheck@2.0.0 - with: - ignore_names: gradlew - ignore_paths: ./userspace/ksud/src/installer.sh diff --git a/.github/workflows/wsa-kernel.yml b/.github/workflows/wsa-kernel.yml deleted file mode 100644 index 1f87e497..00000000 --- a/.github/workflows/wsa-kernel.yml +++ /dev/null @@ -1,106 +0,0 @@ -name: Build Kernel - WSA -on: - workflow_call: - inputs: - arch: - required: true - type: string - description: > - Build arch: x86_64 / arm64 - version: - required: true - type: string - description: > - Build version -jobs: - build: - name: Build WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }} - runs-on: ubuntu-22.04 - env: - CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion" - CCACHE_NOHASHDIR: "true" - CCACHE_HARDLINK: "true" - - steps: - - name: Install Build Tools - uses: awalsh128/cache-apt-pkgs-action@v1 - with: - packages: bc bison build-essential flex libelf-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu gzip ccache - version: 1.0 - - - name: Cache LLVM - id: cache-llvm - uses: actions/cache@v4 - with: - path: ./llvm - key: llvm-12.0.1 - - - name: Setup LLVM - uses: KyleMayes/install-llvm-action@v1 - with: - version: "12.0.1" - force-version: true - ubuntu-version: "16.04" - cached: ${{ steps.cache-llvm.outputs.cache-hit }} - - - name: Checkout KernelSU - uses: actions/checkout@v4 - with: - path: KernelSU - fetch-depth: 0 - - - name: Setup kernel source - uses: actions/checkout@v4 - with: - repository: microsoft/WSA-Linux-Kernel - ref: android-lts/latte-2/${{ inputs.version }} - path: WSA-Linux-Kernel - - - name: Setup Ccache - uses: hendrikmuhs/ccache-action@v1 - with: - key: WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }} - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - max-size: 2G - - - name: Setup KernelSU - working-directory: WSA-Linux-Kernel - run: | - echo "[+] KernelSU setup" - KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel - echo "[+] KERNEL_ROOT: $KERNEL_ROOT" - echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers" - ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu - echo "[+] Add KernelSU driver to Makefile" - DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/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.15/*.patch || echo "[-] No patch found" - echo "[+] KernelSU setup done." - cd $GITHUB_WORKSPACE/KernelSU - VERSION=$(($(git rev-list --count HEAD) + 10200)) - echo "VERSION: $VERSION" - echo "kernelsu_version=$VERSION" >> $GITHUB_ENV - - - name: Build Kernel - working-directory: WSA-Linux-Kernel - run: | - if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then - export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }} - export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }} - fi - declare -A ARCH_MAP=(["x86_64"]="x64" ["arm64"]="arm64") - cp configs/wsa/config-wsa-${ARCH_MAP[${{ inputs.arch }}]} .config - make olddefconfig - declare -A FILE_NAME=(["x86_64"]="bzImage" ["arm64"]="Image") - make -j`nproc` LLVM=1 ARCH=${{ inputs.arch }} $(if [ "${{ inputs.arch }}" == "arm64" ]; then echo CROSS_COMPILE=aarch64-linux-gnu; fi) ${FILE_NAME[${{ inputs.arch }}]} CCACHE="/usr/bin/ccache" - declare -A ARCH_MAP_FILE=(["x86_64"]="x86" ["arm64"]="arm64") - echo "file_path=WSA-Linux-Kernel/arch/${ARCH_MAP_FILE[${{ inputs.arch }}]}/boot/${FILE_NAME[${{ inputs.arch }}]}" >> $GITHUB_ENV - - - name: Upload kernel-${{ inputs.arch }}-${{ inputs.version }} - uses: actions/upload-artifact@v4 - with: - name: kernel-WSA-${{ inputs.arch }}-${{ inputs.version }} - path: "${{ env.file_path }}" \ No newline at end of file diff --git a/docs/README.md b/README.md similarity index 100% rename from docs/README.md rename to README.md diff --git a/docs/README_CN.md b/docs/README_CN.md deleted file mode 100644 index dc34b86a..00000000 --- a/docs/README_CN.md +++ /dev/null @@ -1,57 +0,0 @@ -[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) - -# KernelSU - -logo - -一个 Android 上基于内核的 root 方案。 - -[![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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## 特性 - -- 基于内核的 `su` 和权限管理。 -- 基于 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模块系统。 -- [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html): 把 Root 权限关进笼子里。 - -## 兼容状态 - -KernelSU 官方支持 GKI 2.0 的设备(内核版本5.10以上);旧内核也是兼容的(最低4.14+),不过需要自己编译内核。 - -WSA, ChromeOS 和运行在容器上的 Android 也可以与 KernelSU 一起工作。 - -目前支持架构 : `arm64-v8a` 和 `x86_64`。 - -## 使用方法 - -- [安装教程](https://kernelsu.org/zh_CN/guide/installation.html) -- [如何构建?](https://kernelsu.org/zh_CN/guide/how-to-build.html) -- [官方网站](https://kernelsu.org/zh_CN/) - -## 参与翻译 - -要将 KernelSU 翻译成您的语言,或完善现有的翻译,请使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。现已不再接受有关管理器翻译的PR,因为这会与Weblate冲突。 - -## 讨论 - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## 安全性 - -有关报告 KernelSU 安全漏洞的信息,请参阅 [SECURITY.md](/SECURITY.md)。 - -## 许可证 - -- 目录 `kernel` 下所有文件为 [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。 -- 除 `kernel` 目录的其他部分均为 [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。 - -## 鸣谢 - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU 的灵感。 -- [Magisk](https://github.com/topjohnwu/Magisk):强大的 root 工具箱。 -- [genuine](https://github.com/brevent/genuine/):apk v2 签名验证。 -- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。 diff --git a/docs/README_ES.md b/docs/README_ES.md deleted file mode 100644 index ed4f699b..00000000 --- a/docs/README_ES.md +++ /dev/null @@ -1,56 +0,0 @@ -[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) - -# KernelSU - -logo - -Una solución root basada en el kernel para dispositivos 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/Localización-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu) -[![Channel](https://img.shields.io/badge/Seguir-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: GPL v2](https://img.shields.io/badge/Licencia-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## Características - -1. Binario `su` basado en el kernel y gestión de acceso root. -2. Sistema de módulos basado en [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS). - -## Estado de compatibilidad - -**KernelSU** soporta de forma oficial dispositivos Android con **GKI 2.0** (a partir de la versión **5.10** del kernel). Los kernels antiguos (a partir de la versión **4.14**) también son compatibles, pero necesitas compilarlos por tu cuenta. - -Con esto, WSA, ChromeOS y Android basado en contenedores están todos compatibles. - -Actualmente, solo se admiten las arquitecturas `arm64-v8a` y `x86_64`. - -## Uso - -- [¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html) -- [¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html) -- [Site oficial](https://kernelsu.org/) - -## Traducción - -Para ayudar a traducir KernelSU o mejorar las traducciones existentes, utilice [Weblate](https://hosted.weblate.org/engage/kernelsu/). Ya no se aceptan PR de la traducción de Manager porque entrará en conflicto con Weblate. - -## Discusión - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## Seguridad - -Para obtener información sobre cómo informar vulnerabilidades de seguridad en KernelSU, consulte [SECURITY.md](/SECURITY.md). - -## Licencia - -- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). -- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html). - -## Créditos - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de KernelSU. -- [Magisk](https://github.com/topjohnwu/Magisk): la poderosa herramienta root. -- [genuine](https://github.com/brevent/genuine/): validación de firma apk v2. -- [Diamorphine](https://github.com/m0nad/Diamorphine): algunas habilidades de rootkit. diff --git a/docs/README_ID.md b/docs/README_ID.md deleted file mode 100644 index 511683a7..00000000 --- a/docs/README_ID.md +++ /dev/null @@ -1,53 +0,0 @@ -[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) - -# KernelSU - -logo - -Solusi root berbasis Kernel untuk perangkat 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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## Fitur - -1. Manajemen akses root dan `su` berbasis kernel. -2. Sistem modul berdasarkan [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS). -3. [Profil Aplikasi](https://kernelsu.org/guide/app-profile.html): Kunci daya root di dalam sangkar. - -## Status Kompatibilitas - -KernelSU secara resmi mendukung perangkat Android GKI 2.0 (dengan kernel 5.10+), kernel lama (4.14+) juga kompatibel, tetapi Anda perlu membuat kernel sendiri. - -WSA, ChromeOS, dan Android berbasis wadah juga dapat bekerja dengan KernelSU terintegrasi. - -Dan ABI yang didukung saat ini adalah: `arm64-v8a` dan `x86_64` - -## Penggunaan - -- [Petunjuk Instalasi](https://kernelsu.org/id_ID/guide/installation.html) -- [Bagaimana cara membuat?](https://kernelsu.org/id_ID/guide/how-to-build.html) -- [Situs Web Resmi](https://kernelsu.org/id_ID/) - -## Terjemahan - -Untuk menerjemahkan KernelSU ke dalam bahasa Anda atau menyempurnakan terjemahan yang sudah ada, harap gunakan [Weblat](https://hosted.weblate.org/engage/kernelsu/). - -## Diskusi - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## Lisensi - -- File di bawah direktori `kernel` adalah [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). -- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html). - -## Kredit - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ide KernelSU. -- [Magisk](https://github.com/topjohnwu/Magisk): alat root yang ampuh. -- [genuine](https://github.com/brevent/genuine/): validasi tanda tangan apk v2. -- [Diamorphine](https://github.com/m0nad/Diamorphine): beberapa keterampilan rootkit. diff --git a/docs/README_IN.md b/docs/README_IN.md deleted file mode 100644 index 7396ab5c..00000000 --- a/docs/README_IN.md +++ /dev/null @@ -1,53 +0,0 @@ -[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) | **हिंदी** - -# KernelSU - -logo - -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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## विशेषताएँ - -1. कर्नेल-आधारित `su` और रूट एक्सेस प्रबंधन। -2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) पर आधारित मॉड्यूल प्रणाली। -3. [App Profile](https://kernelsu.org/guide/app-profile.html): Root शक्ति को पिंजरे में बंद कर दो। - -## अनुकूलता अवस्था - -KernelSU आधिकारिक तौर पर Android GKI 2.0 डिवाइस (कर्नेल 5.10+) का समर्थन करता है। पुराने कर्नेल (4.14+) भी संगत हैं, लेकिन कर्नेल को मैन्युअल रूप से बनाना होगा। - -इसके साथ, WSA, ChromeOS और कंटेनर-आधारित Android सभी समर्थित हैं। - -वर्तमान में, केवल `arm64-v8a` और `x86_64` समर्थित हैं। - -## प्रयोग - -- [स्थापना निर्देश](https://kernelsu.org/guide/installation.html) -- [कैसे बनाना है ?](https://kernelsu.org/guide/how-to-build.html) -- [आधिकारिक वेबसाइट](https://kernelsu.org/) - -## अनुवाद करना - -KernelSU का अनुवाद करने या मौजूदा अनुवादों को बेहतर बनाने में सहायता के लिए, कृपया इसका उपयोग करें [Weblate](https://hosted.weblate.org/engage/kernelsu/). - -## बहस - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## लाइसेंस - -- `Kernel` निर्देशिका के अंतर्गत फ़ाइलें हैं [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) -- `Kernel` निर्देशिका को छोड़कर अन्य सभी भाग हैं [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html) - -## आभार सूची - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU विचार। -- [Magisk](https://github.com/topjohnwu/Magisk): शक्तिशाली root उपकरण। -- [genuine](https://github.com/brevent/genuine/): apk v2 हस्ताक्षर सत्यापन। -- [Diamorphine](https://github.com/m0nad/Diamorphine): कुछ रूटकिट कौशल। diff --git a/docs/README_IW.md b/docs/README_IW.md deleted file mode 100644 index 5997487e..00000000 --- a/docs/README_IW.md +++ /dev/null @@ -1,53 +0,0 @@ -[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) - -# KernelSU - -logo - -פתרון לניהול root מבוסס על Kernel עבור מכשירי 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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## תכונות - -1. ניהול root ו־`su` מבוססים על Kernel. -2. מערכת מודולים מבוססת [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS). -3. [פרופיל אפליקציה](https://kernelsu.org/guide/app-profile.html): נעילת גישת root בכלוב. - -## מצב תאימות - -KernelSU תומך במכשירי Android GKI 2.0 (kernel 5.10+) באופן רשמי. לליבות ישנות (4.14+) יש גם תאימות, אך יידרש לבנות את הליבה באופן ידני. - -באמצעות זה, תמיכה זמינה גם ל-WSA, ChromeOS ומכשירי Android המבוססים על מיכלים. - -כרגע, רק `arm64-v8a` ו־`x86_64` נתמכים. - -## שימוש - -- [הוראות התקנה](https://kernelsu.org/guide/installation.html) -- [איך לבנות?](https://kernelsu.org/guide/how-to-build.html) -- [האתר רשמי](https://kernelsu.org/) - -## תרגום - -כדי לעזור בתרגום של KernelSU או לשפר תרגומים קיימים, יש להשתמש ב-[Weblate](https://hosted.weblate.org/engage/kernelsu/). - -## דיון - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## רשיון - -- קבצים תחת הספרייה `kernel` מוגנים על פי [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). -- כל החלקים האחרים, למעט הספרייה `kernel`, מוגנים על פי [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html). - -## קרדיטים - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): הרעיון של KernelSU. -- [Magisk](https://github.com/topjohnwu/Magisk): הכלי הסופר חזק לניהול root. -- [genuine](https://github.com/brevent/genuine/): אימות חתימת apk v2. -- [Diamorphine](https://github.com/m0nad/Diamorphine): כמה יכולות רוט. diff --git a/docs/README_JP.md b/docs/README_JP.md deleted file mode 100644 index 09361875..00000000 --- a/docs/README_JP.md +++ /dev/null @@ -1,53 +0,0 @@ -[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) - -# KernelSU - -logo - -Android におけるカーネルベースの root ソリューションです。 - -[![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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## 特徴 - -1. カーネルベースの `su` と権限管理。 -2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) に基づくモジュールシステム。 -3. [アプリのプロファイル](https://kernelsu.org/guide/app-profile.html): root の権限をケージ内に閉じ込めます。 - -## 対応状況 - -KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上)を公式にサポートしています。古いカーネル(4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。 - -WSA 、ChromeOS とコンテナ上で動作する Android でも KernelSU を統合して動かせます。 - -現在サポートしているアーキテクチャは `arm64-v8a` および `x86_64` です。 - -## 使用方法 - -- [インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html) -- [ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html) -- [公式サイト](https://kernelsu.org/ja_JP/) - -## 翻訳 - -KernelSU をあなたの言語に翻訳するか、既存の翻訳を改善するには、[Weblate](https://hosted.weblate.org/engage/kernelsu/) を使用してください。Manager翻訳した PR は、Weblate と競合するため受け入れられなくなりました。 - -## ディスカッション - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## ライセンス - -- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。 -- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。 - -## クレジット - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU のアイデア元。 -- [Magisk](https://github.com/topjohnwu/Magisk):強力な root ツール。 -- [genuine](https://github.com/brevent/genuine/):apk v2 の署名検証。 -- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル。 diff --git a/docs/README_KR.md b/docs/README_KR.md deleted file mode 100644 index 32260089..00000000 --- a/docs/README_KR.md +++ /dev/null @@ -1,57 +0,0 @@ -[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) - -# KernelSU - -logo - -안드로이드 기기에서 사용되는 커널 기반 루팅 솔루션입니다. - -[![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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## 기능들 - -1. 커널 기반 `su` 및 루트 액세스 관리. -2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 기반 모듈 시스템. -3. [App Profile](https://kernelsu.org/guide/app-profile.html): 루트 권한을 케이지에 가둡니다. - -## 호환 상태 - -KernelSU는 공식적으로 안드로이드 GKI 2.0 디바이스(커널 5.10 이상)를 지원합니다. 오래된 커널(4.14 이상)도 사용할 수 있지만, 커널을 수동으로 빌드해야 합니다. - -KernelSU는 WSA, ChromeOS, 컨테이너 기반 안드로이드 모두를 지원합니다. - -현재는 `arm64-v8a`와 `x86_64`만 지원됩니다. - -## 사용 방법 - -- [설치 방법](https://kernelsu.org/guide/installation.html) -- [어떻게 빌드하나요?](https://kernelsu.org/guide/how-to-build.html) -- [공식 웹사이트](https://kernelsu.org/) - -## 번역 - -KernelSU 번역을 돕거나 기존 번역을 개선하려면 [Weblate](https://hosted.weblate.org/engage/kernelsu/)를 이용해 주세요. 매니저의 번역은 Weblate와 충돌할 수 있으므로 더 이상 허용되지 않습니다. - -## 토론 - -- 텔레그램: [@KernelSU](https://t.me/KernelSU) - -## 보안 - -KernelSU의 보안 취약점 보고에 대한 자세한 내용은 [SECURITY.md](/SECURITY.md)를 참조하세요. - -## 저작권 - -- `kernel` 디렉터리 아래의 파일은 [GPL-2.0 전용](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)입니다. -- `kernel` 디렉토리를 제외한 다른 모든 부분은 [GPL-3.0-이상](https://www.gnu.org/licenses/gpl-3.0.html)입니다. - -## 크래딧 - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU의 아이디어. -- [Magisk](https://github.com/topjohnwu/Magisk): 강력한 루팅 도구. -- [genuine](https://github.com/brevent/genuine/): apk v2 서명 유효성 검사. -- [Diamorphine](https://github.com/m0nad/Diamorphine): 일부 rootkit 스킬. diff --git a/docs/README_PL.md b/docs/README_PL.md deleted file mode 100644 index ab906629..00000000 --- a/docs/README_PL.md +++ /dev/null @@ -1,55 +0,0 @@ -[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) - -# KernelSU - -logo - -Rozwiązanie root oparte na jądrze dla urządzeń z systemem 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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## Cechy - -1. Oparte na jądrze `su` i zarządzanie dostępem roota. -2. System modułów oparty na [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS). - -## Kompatybilność - -KernelSU oficjalnie obsługuje urządzenia z Androidem GKI 2.0 (z jądrem 5.10+), starsze jądra (4.14+) są również kompatybilne, ale musisz sam skompilować jądro. - -WSA i Android oparty na kontenerach również powinny działać ze zintegrowanym KernelSU. - -Aktualnie obsługiwane ABI to : `arm64-v8a` i `x86_64`. - -## Użycie - -- [Instalacja](https://kernelsu.org/guide/installation.html) -- [Jak skompilować?](https://kernelsu.org/guide/how-to-build.html) - -## Tłumaczenie - -Aby pomóc w tłumaczeniu KernelSU lub ulepszyć istniejące tłumaczenia, użyj [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR tłumaczenia Managera nie jest już akceptowany, ponieważ będzie kolidował z Weblate. - -## Dyskusja - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## Bezpieczeństwo - -Informacje na temat zgłaszania luk w zabezpieczeniach w KernelSU można znaleźć w pliku [SECURITY.md](/SECURITY.md). - -## Licencja - -- Pliki w katalogu `kernel` są na licencji [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). -- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html). - -## Podziękowania - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): pomysłodawca KernelSU. -- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy. -- [genuine](https://github.com/brevent/genuine/): walidacja podpisu apk v2. -- [Diamorphine](https://github.com/m0nad/Diamorphine): cenna znajomość rootkitów. diff --git a/docs/README_PT-BR.md b/docs/README_PT-BR.md deleted file mode 100644 index b5421e7f..00000000 --- a/docs/README_PT-BR.md +++ /dev/null @@ -1,57 +0,0 @@ -[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) - -# KernelSU - -logo - -Uma solução root baseada em kernel para dispositivos 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/Localização-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu) -[![Channel](https://img.shields.io/badge/Seguir-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: GPL v2](https://img.shields.io/badge/Licença-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## Características - -1. `su` e gerenciamento de acesso root baseado em kernel. -2. Sistema modular baseado em [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS). -3. [Perfil do Aplicativo](https://kernelsu.org/pt_BR/guide/app-profile.html): Tranque o poder root em uma gaiola. - -## Estado de compatibilidade - -O KernelSU oferece suporte oficial a dispositivos Android GKI 2.0 (kernel 5.10+). Kernels mais antigos (4.14+) também são compatíveis, mas o kernel terá que ser construído manualmente. - -Com isso, WSA, ChromeOS e Android baseado em contêiner são todos suportados. - -Atualmente, apenas `arm64-v8a` e `x86_64` são suportados. - -## Uso - - - [Instalação](https://kernelsu.org/pt_BR/guide/installation.html) - - [Como compilar o KernelSU?](https://kernelsu.org/pt_BR/guide/how-to-build.html) - - [Site oficial](https://kernelsu.org/pt_BR/) - -## Tradução - -Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, utilize o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Gerenciador não são mais aceitas, pois podem entrar em conflito com o Weblate. - -## Discussão - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## Segurança - -Para obter informações sobre como relatar vulnerabilidades de segurança do KernelSU, consulte [SECURITY.md](/SECURITY.md). - -## Licença - -- Os arquivos no diretório `kernel` são [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). -- Todas as outras partes, exceto o diretório `kernel` são [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html). - -## Créditos - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): a ideia do KernelSU. -- [Magisk](https://github.com/topjohnwu/Magisk): a poderosa ferramenta root. -- [genuine](https://github.com/brevent/genuine/): validação de assinatura apk v2. -- [Diamorphine](https://github.com/m0nad/Diamorphine): algumas habilidades de rootkit. diff --git a/docs/README_RU.md b/docs/README_RU.md deleted file mode 100644 index 7e50f47a..00000000 --- a/docs/README_RU.md +++ /dev/null @@ -1,49 +0,0 @@ -[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) - -# KernelSU - -logo - -Решение на основе ядра root для 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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## Особенности - -1. Управление `su` и root-доступом на основе ядра. -2. Система модулей на основе [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS). -3. [Профиль приложений](https://kernelsu.org/ru_RU/guide/app-profile.html): Запри корневую силу в клетке. - -## Совместимость - -KernelSU официально поддерживает устройства на базе Android GKI 2.0 (с ядром 5.10+), старые ядра (4.14+) также совместимы, но для этого необходимо собрать ядро самостоятельно. - -WSA и Android на основе контейнеров также должны работать с интегрированным KernelSU. - -В настоящее время поддерживаются следующие ABI: `arm64-v8a` и `x86_64`. - -## Использование - -- [Установка](https://kernelsu.org/ru_RU/guide/installation.html) -- [Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html) -- [официальный сайт](https://kernelsu.org/ru_RU/) - -## Обсуждение - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## Лицензия - -- Файлы в директории `kernel` [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). -- Все остальные части, кроме директории `kernel` [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html). - -## Благодарности - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): идея KernelSU. -- [Magisk](https://github.com/topjohnwu/Magisk): реализация sepolicy. -- [genuine](https://github.com/brevent/genuine/): проверка подписи apk v2. -- [Diamorphine](https://github.com/m0nad/Diamorphine): некоторые навыки руткита. diff --git a/docs/README_TR.md b/docs/README_TR.md deleted file mode 100644 index bc3363e8..00000000 --- a/docs/README_TR.md +++ /dev/null @@ -1,57 +0,0 @@ -[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) - -# KernelSU - -logo - -Android cihazlar için kernel tabanlı root çözümü. - -[![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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## Özellikler - -1. Kernel-tabanlı `su` ve root erişimi yönetimi. -2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)'ye dayalı modül sistemi. -3. [Uygulama profili](https://kernelsu.org/guide/app-profile.html): Root gücünü bir kafese kapatın. - -## Uyumluluk Durumu - -KernelSU resmi olarak Android GKI 2.0 cihazlarını (5.10+ kernelli) destekler, eski kernellerle de (4.14+) uyumludur, ancak kerneli kendinizin derlemeniz gerekir. - -Bununla birlikte; WSA, ChromeOS ve konteyner tabanlı Android'in tamamı desteklenmektedir. - -Şimdilik sadece `arm64-v8a` ve `x86_64` desteklenmektedir. - -## Kullanım - -- [Yükleme yönergeleri](https://kernelsu.org/guide/installation.html) -- [Nasıl derlenir?](https://kernelsu.org/guide/how-to-build.html) -- [Resmi WEB sitesi](https://kernelsu.org/) - -## Çeviri - -KernelSU'nun başka dillere çevrilmesine veya mevcut çevirilerin iyileştirilmesine yardımcı olmak için lütfen [Weblate](https://hosted.weblate.org/engage/kernelsu/) kullanın. Yönetici uygulamasının PR ile çevirisi, Weblate ile çakışacağından artık kabul edilmeyecektir. - -## Tartışma - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## Güvenlik - -KernelSU'daki güvenlik açıklarını bildirme hakkında bilgi için, bkz [SECURITY.md](/SECURITY.md). - -## Lisans - -- `kernel` klasöründeki dosyalar [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır. -- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3-veya-sonraki](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır. - -## Krediler - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU fikri. -- [Magisk](https://github.com/topjohnwu/Magisk): güçlü root aracı. -- [genuine](https://github.com/brevent/genuine/): apk v2 imza doğrulaması. -- [Diamorphine](https://github.com/m0nad/Diamorphine): bazı rootkit becerileri. diff --git a/docs/README_TW.md b/docs/README_TW.md deleted file mode 100644 index d025e174..00000000 --- a/docs/README_TW.md +++ /dev/null @@ -1,56 +0,0 @@ -[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) - -# KernelSU - -logo - -一個基於核心的 Android 裝置 Root 解決方案 - -[![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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## 功能 - -- 基於核心的 `su` 和 Root 存取權管理。 -- 基於 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模組系統。 -- [App Profile](https://kernelsu.org/zh_TW/guide/app-profile.html): 將 Root 的權限鎖在牢籠中. - -## 相容性狀態 - -KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+ );舊版核心同樣相容 (最低 4.14+ ),但需要自行編譯核心。 - -WSA和ChromeOS和執行在容器中的 Android 也可以與 KernelSU 一同運作。 - -目前支援架構:`arm64-v8a` 和 `x86_64`。 - -## 使用方法 - -- [安裝教學](https://kernelsu.org/zh_TW/guide/installation.html) -- [如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html) -- [官方網站](https://kernelsu.org/zh_TW/) - -## 翻譯 - -若要協助翻譯 KernelSU 或改進現有翻譯,請使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。 翻譯管理器的PR不再被接受,因為它會與Weblate衝突。 - -### 討論 - -- Telegram:[@KernelSU](https://t.me/KernelSU) - -## 安全 -有關報告 KernelSU 中的安全漏洞的資訊,請參閱 [SECURITY.md](/SECURITY.md)。 - -## 授權 - -- 目錄 `kernel` 下所有檔案為 [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。 -- 除 `kernel` 目錄的其他部分均為 [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。 - -## 致謝 - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU 的靈感。 -- [Magisk](https://github.com/topjohnwu/Magisk):sepolicy 實作。 -- [genuine](https://github.com/brevent/genuine/):apk v2 簽章驗證。 -- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。 diff --git a/docs/README_VI.md b/docs/README_VI.md deleted file mode 100644 index 7dd3b422..00000000 --- a/docs/README_VI.md +++ /dev/null @@ -1,53 +0,0 @@ -[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) - -# KernelSU - -logo - -Giải pháp root thông qua thay đổi trên Kernel hệ điều hành cho các thiết bị 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) -[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU) -[![License: 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) -[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE) - -## Tính năng - -1. Hỗ trợ gói thực thi `su` và quản lý quyền root. -2. Hệ thống mô-đun thông qua [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS). -3. [App Profile](https://kernelsu.org/guide/app-profile.html): Hạn chế quyền root của ứng dụng. - -## Tình trạng tương thích - -KernelSU chính thức hỗ trợ các thiết bị Android với kernel GKI 2.0 (phiên bản kernel 5.10+), các phiên bản kernel cũ hơn (4.14+) cũng tương thích, nhưng bạn cần phải tự biên dịch. - -WSA, ChromeOS và Android dựa trên container(container-based) cũng được hỗ trợ bởi KernelSU. - -Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a` và `x86_64`. - -## Sử dụng - -- [Hướng dẫn cài đặt](https://kernelsu.org/vi_VN/guide/installation.html) -- [Cách để build?](https://kernelsu.org/vi_VN/guide/how-to-build.html) -- [Website Chính Thức](https://kernelsu.org/vi_VN/) - -## Hỗ trợ dịch - -Nếu bạn muốn hỗ trợ dịch KernelSU sang một ngôn ngữ khác hoặc cải thiện các bản dịch trước, vui lòng sử dụng [Weblate](https://hosted.weblate.org/engage/kernelsu/). - -## Thảo luận - -- Telegram: [@KernelSU](https://t.me/KernelSU) - -## Giấy phép - -- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). -- Tất cả các thành phần khác ngoại trừ thư mục `kernel` dùng giấy phép [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html). - -## Lời cảm ơn - -- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ý tưởng cho KernelSU. -- [Magisk](https://github.com/topjohnwu/Magisk): công cụ root mạnh mẽ. -- [genuine](https://github.com/brevent/genuine/): phương pháp xác thực apk v2. -- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit. diff --git a/js/README.md b/js/README.md deleted file mode 100644 index 4af3a718..00000000 --- a/js/README.md +++ /dev/null @@ -1,111 +0,0 @@ -# Library for KernelSU's module WebUI - -## Install - -```sh -yarn add kernelsu -``` - -## API - -### exec - -Spawns a **root** shell and runs a command within that shell, passing the `stdout` and `stderr` to a Promise when complete. - -- `command` `` The command to run, with space-separated arguments. -- `options` `` - - `cwd` - Current working directory of the child process - - `env` - Environment key-value pairs - -```javascript -import { exec } from 'kernelsu'; - -const { errno, stdout, stderr } = await exec('ls -l', { cwd: '/tmp' }); -if (errno === 0) { - // success - console.log(stdout); -} -``` - -### spawn - -Spawns a new process using the given `command` in **root** shell, with command-line arguments in `args`. If omitted, `args` defaults to an empty array. - -Returns a `ChildProcess`, Instances of the ChildProcess represent spawned child processes. - -- `command` `` The command to run. -- `args` `` List of string arguments. -- `options` ``: - - `cwd` `` - Current working directory of the child process - - `env` `` - Environment key-value pairs - -Example of running `ls -lh /data`, capturing `stdout`, `stderr`, and the exit code: - -```javascript -import { spawn } from 'kernelsu'; - -const ls = spawn('ls', ['-lh', '/data']); - -ls.stdout.on('data', (data) => { - console.log(`stdout: ${data}`); -}); - -ls.stderr.on('data', (data) => { - console.log(`stderr: ${data}`); -}); - -ls.on('exit', (code) => { - console.log(`child process exited with code ${code}`); -}); -``` - -#### ChildProcess - -##### Event 'exit' - -- `code` `` The exit code if the child exited on its own. - -The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise null - -##### Event 'error' - -- `err` `` The error. - -The `'error'` event is emitted whenever: - -- The process could not be spawned. -- The process could not be killed. - -##### `stdout` - -A `Readable Stream` that represents the child process's `stdout`. - -```javascript -const subprocess = spawn('ls'); - -subprocess.stdout.on('data', (data) => { - console.log(`Received chunk ${data}`); -}); -``` - -#### `stderr` - -A `Readable Stream` that represents the child process's `stderr`. - -### fullScreen - -Request the WebView enter/exit full screen. - -```javascript -import { fullScreen } from 'kernelsu'; -fullScreen(true); -``` - -### toast - -Show a toast message. - -```javascript -import { toast } from 'kernelsu'; -toast('Hello, world!'); -``` diff --git a/js/index.d.ts b/js/index.d.ts deleted file mode 100644 index b65248e3..00000000 --- a/js/index.d.ts +++ /dev/null @@ -1,45 +0,0 @@ -interface ExecOptions { - cwd?: string, - env?: { [key: string]: string } -} - -interface ExecResults { - errno: number, - stdout: string, - stderr: string -} - -declare function exec(command: string): Promise; -declare function exec(command: string, options: ExecOptions): Promise; - -interface SpawnOptions { - cwd?: string, - env?: { [key: string]: string } -} - -interface Stdio { - on(event: 'data', callback: (data: string) => void) -} - -interface ChildProcess { - stdout: Stdio, - stderr: Stdio, - on(event: 'exit', callback: (code: number) => void) - on(event: 'error', callback: (err: any) => void) -} - -declare function spawn(command: string): ChildProcess; -declare function spawn(command: string, args: string[]): ChildProcess; -declare function spawn(command: string, options: SpawnOptions): ChildProcess; -declare function spawn(command: string, args: string[], options: SpawnOptions): ChildProcess; - -declare function fullScreen(isFullScreen: boolean); - -declare function toast(message: string); - -export { - exec, - spawn, - fullScreen, - toast -} diff --git a/js/index.js b/js/index.js deleted file mode 100644 index 4b64e9c4..00000000 --- a/js/index.js +++ /dev/null @@ -1,115 +0,0 @@ -let callbackCounter = 0; -function getUniqueCallbackName(prefix) { - return `${prefix}_callback_${Date.now()}_${callbackCounter++}`; -} - -export function exec(command, options) { - if (typeof options === "undefined") { - options = {}; - } - - return new Promise((resolve, reject) => { - // Generate a unique callback function name - const callbackFuncName = getUniqueCallbackName("exec"); - - // Define the success callback function - window[callbackFuncName] = (errno, stdout, stderr) => { - resolve({ errno, stdout, stderr }); - cleanup(callbackFuncName); - }; - - function cleanup(successName) { - delete window[successName]; - } - - try { - ksu.exec(command, JSON.stringify(options), callbackFuncName); - } catch (error) { - reject(error); - cleanup(callbackFuncName); - } - }); -} - -function Stdio() { - this.listeners = {}; - } - - Stdio.prototype.on = function (event, listener) { - if (!this.listeners[event]) { - this.listeners[event] = []; - } - this.listeners[event].push(listener); - }; - - Stdio.prototype.emit = function (event, ...args) { - if (this.listeners[event]) { - this.listeners[event].forEach((listener) => listener(...args)); - } - }; - - function ChildProcess() { - this.listeners = {}; - this.stdin = new Stdio(); - this.stdout = new Stdio(); - this.stderr = new Stdio(); - } - - ChildProcess.prototype.on = function (event, listener) { - if (!this.listeners[event]) { - this.listeners[event] = []; - } - this.listeners[event].push(listener); - }; - - ChildProcess.prototype.emit = function (event, ...args) { - if (this.listeners[event]) { - this.listeners[event].forEach((listener) => listener(...args)); - } - }; - - export function spawn(command, args, options) { - if (typeof args === "undefined") { - args = []; - } else if (!(args instanceof Array)) { - // allow for (command, options) signature - options = args; - } - - if (typeof options === "undefined") { - options = {}; - } - - const child = new ChildProcess(); - const childCallbackName = getUniqueCallbackName("spawn"); - window[childCallbackName] = child; - - function cleanup(name) { - delete window[name]; - } - - child.on("exit", code => { - cleanup(childCallbackName); - }); - - try { - ksu.spawn( - command, - JSON.stringify(args), - JSON.stringify(options), - childCallbackName - ); - } catch (error) { - child.emit("error", error); - cleanup(childCallbackName); - } - return child; - } - -export function fullScreen(isFullScreen) { - ksu.fullScreen(isFullScreen); -} - -export function toast(message) { - ksu.toast(message); -} diff --git a/js/package.json b/js/package.json deleted file mode 100644 index 02b350f3..00000000 --- a/js/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "kernelsu", - "version": "1.0.6", - "description": "Library for KernelSU's module WebUI", - "main": "index.js", - "types": "index.d.ts", - "scripts": { - "test": "npm run test" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/tiann/KernelSU.git" - }, - "keywords": [ - "su", - "kernelsu", - "module", - "webui" - ], - "author": "weishu", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/tiann/KernelSU/issues" - }, - "homepage": "https://github.com/tiann/KernelSU#readme" -} diff --git a/justfile b/justfile deleted file mode 100644 index 51bef767..00000000 --- a/justfile +++ /dev/null @@ -1,14 +0,0 @@ -alias bk := build_ksud -alias bm := build_manager - -build_ksud: - cross build --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml - -build_manager: build_ksud - cp userspace/ksud/target/aarch64-linux-android/release/ksud manager/app/src/main/jniLibs/arm64-v8a/libksud.so - cd manager && ./gradlew aDebug - -clippy: - cargo fmt --manifest-path ./userspace/ksud/Cargo.toml - cross clippy --target x86_64-pc-windows-gnu --release --manifest-path ./userspace/ksud/Cargo.toml - cross clippy --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml diff --git a/manager/.gitignore b/manager/.gitignore deleted file mode 100644 index dd42da43..00000000 --- a/manager/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -*.iml -.gradle -local.properties -.idea -.DS_Store -build -captures -.cxx -key.jks diff --git a/manager/app/.gitignore b/manager/app/.gitignore deleted file mode 100644 index dc5ca963..00000000 --- a/manager/app/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/release/ diff --git a/manager/app/build.gradle.kts b/manager/app/build.gradle.kts deleted file mode 100644 index 1c85d8af..00000000 --- a/manager/app/build.gradle.kts +++ /dev/null @@ -1,116 +0,0 @@ -import com.android.build.gradle.internal.api.BaseVariantOutputImpl - -plugins { - alias(libs.plugins.agp.app) - alias(libs.plugins.kotlin) - alias(libs.plugins.compose.compiler) - alias(libs.plugins.ksp) - alias(libs.plugins.lsplugin.apksign) - id("kotlin-parcelize") -} - -val managerVersionCode: Int by rootProject.extra -val managerVersionName: String by rootProject.extra - -apksign { - storeFileProperty = "KEYSTORE_FILE" - storePasswordProperty = "KEYSTORE_PASSWORD" - keyAliasProperty = "KEY_ALIAS" - keyPasswordProperty = "KEY_PASSWORD" -} - -android { - namespace = "me.weishu.kernelsu" - - buildTypes { - release { - isMinifyEnabled = true - isShrinkResources = true - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") - } - } - - buildFeatures { - aidl = true - buildConfig = true - compose = true - } - - kotlinOptions { - jvmTarget = "21" - } - - packaging { - jniLibs { - useLegacyPackaging = true - } - resources { - excludes += "/META-INF/{AL2.0,LGPL2.1}" - } - } - - externalNativeBuild { - cmake { - path("src/main/cpp/CMakeLists.txt") - } - } - - applicationVariants.all { - outputs.forEach { - val output = it as BaseVariantOutputImpl - output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk" - } - - kotlin.sourceSets { - getByName(name) { - kotlin.srcDir("build/generated/ksp/$name/kotlin") - } - } - } -} - -dependencies { - implementation(libs.androidx.activity.compose) - implementation(libs.androidx.navigation.compose) - - implementation(platform(libs.androidx.compose.bom)) - implementation(libs.androidx.compose.material.icons.extended) - implementation(libs.androidx.compose.material) - implementation(libs.androidx.compose.material3) - implementation(libs.androidx.compose.ui) - implementation(libs.androidx.compose.ui.tooling.preview) - - debugImplementation(libs.androidx.compose.ui.test.manifest) - debugImplementation(libs.androidx.compose.ui.tooling) - - implementation(libs.androidx.lifecycle.runtime.compose) - 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) - ksp(libs.compose.destinations.ksp) - - implementation(libs.com.github.topjohnwu.libsu.core) - implementation(libs.com.github.topjohnwu.libsu.service) - implementation(libs.com.github.topjohnwu.libsu.io) - - implementation(libs.dev.rikka.rikkax.parcelablelist) - - implementation(libs.io.coil.kt.coil.compose) - - implementation(libs.kotlinx.coroutines.core) - - implementation(libs.me.zhanghai.android.appiconloader.coil) - - implementation(libs.sheet.compose.dialogs.core) - implementation(libs.sheet.compose.dialogs.list) - implementation(libs.sheet.compose.dialogs.input) - - implementation(libs.markdown) - implementation(libs.androidx.webkit) -} \ No newline at end of file diff --git a/manager/app/proguard-rules.pro b/manager/app/proguard-rules.pro deleted file mode 100644 index dcaf39ce..00000000 --- a/manager/app/proguard-rules.pro +++ /dev/null @@ -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 deleted file mode 100644 index 32c920ab..00000000 --- a/manager/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/manager/app/src/main/aidl/me/weishu/kernelsu/IKsuInterface.aidl b/manager/app/src/main/aidl/me/weishu/kernelsu/IKsuInterface.aidl deleted file mode 100644 index a6545566..00000000 --- a/manager/app/src/main/aidl/me/weishu/kernelsu/IKsuInterface.aidl +++ /dev/null @@ -1,9 +0,0 @@ -// IKsuInterface.aidl -package me.weishu.kernelsu; - -import android.content.pm.PackageInfo; -import rikka.parcelablelist.ParcelableListSlice; - -interface IKsuInterface { - ParcelableListSlice getPackages(int flags); -} \ No newline at end of file diff --git a/manager/app/src/main/cpp/CMakeLists.txt b/manager/app/src/main/cpp/CMakeLists.txt deleted file mode 100644 index cca26d5e..00000000 --- a/manager/app/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ - -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -# Sets the minimum version of CMake required to build the native library. -cmake_minimum_required(VERSION 3.18.1) - -project("kernelsu") - -add_library(kernelsu - SHARED - jni.cc - ksu.cc - ) - -find_library(log-lib log) - -target_link_libraries(kernelsu ${log-lib}) \ No newline at end of file diff --git a/manager/app/src/main/cpp/jni.cc b/manager/app/src/main/cpp/jni.cc deleted file mode 100644 index b0d28698..00000000 --- a/manager/app/src/main/cpp/jni.cc +++ /dev/null @@ -1,298 +0,0 @@ -#include - -#include - -#include -#include - -#include "ksu.h" - -#define LOG_TAG "KernelSU" -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) - -extern "C" -JNIEXPORT jboolean JNICALL -Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jobject, jstring pkg) { - auto cpkg = env->GetStringUTFChars(pkg, nullptr); - auto result = become_manager(cpkg); - env->ReleaseStringUTFChars(pkg, cpkg); - return result; -} - -extern "C" -JNIEXPORT jint JNICALL -Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jobject) { - return get_version(); -} - -extern "C" -JNIEXPORT jintArray JNICALL -Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jobject) { - int uids[1024]; - int size = 0; - bool result = get_allow_list(uids, &size); - LOGD("getAllowList: %d, size: %d", result, size); - if (result) { - auto array = env->NewIntArray(size); - env->SetIntArrayRegion(array, 0, size, uids); - return array; - } - return env->NewIntArray(0); -} - -extern "C" -JNIEXPORT jboolean JNICALL -Java_me_weishu_kernelsu_Natives_isSafeMode(JNIEnv *env, jclass clazz) { - return is_safe_mode(); -} - -extern "C" -JNIEXPORT jboolean JNICALL -Java_me_weishu_kernelsu_Natives_isLkmMode(JNIEnv *env, jclass clazz) { - return is_lkm_mode(); -} - -static void fillIntArray(JNIEnv *env, jobject list, int *data, int count) { - auto cls = env->GetObjectClass(list); - auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z"); - auto integerCls = env->FindClass("java/lang/Integer"); - auto constructor = env->GetMethodID(integerCls, "", "(I)V"); - for (int i = 0; i < count; ++i) { - auto integer = env->NewObject(integerCls, constructor, data[i]); - env->CallBooleanMethod(list, add, integer); - } -} - -static void addIntToList(JNIEnv *env, jobject list, int ele) { - auto cls = env->GetObjectClass(list); - auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z"); - auto integerCls = env->FindClass("java/lang/Integer"); - auto constructor = env->GetMethodID(integerCls, "", "(I)V"); - auto integer = env->NewObject(integerCls, constructor, ele); - env->CallBooleanMethod(list, add, integer); -} - -static uint64_t capListToBits(JNIEnv *env, jobject list) { - auto cls = env->GetObjectClass(list); - auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;"); - auto size = env->GetMethodID(cls, "size", "()I"); - auto listSize = env->CallIntMethod(list, size); - auto integerCls = env->FindClass("java/lang/Integer"); - auto intValue = env->GetMethodID(integerCls, "intValue", "()I"); - uint64_t result = 0; - for (int i = 0; i < listSize; ++i) { - auto integer = env->CallObjectMethod(list, get, i); - int data = env->CallIntMethod(integer, intValue); - - if (cap_valid(data)) { - result |= (1ULL << data); - } - } - - return result; -} - -static int getListSize(JNIEnv *env, jobject list) { - auto cls = env->GetObjectClass(list); - auto size = env->GetMethodID(cls, "size", "()I"); - return env->CallIntMethod(list, size); -} - -static void fillArrayWithList(JNIEnv *env, jobject list, int *data, int count) { - auto cls = env->GetObjectClass(list); - auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;"); - auto integerCls = env->FindClass("java/lang/Integer"); - auto intValue = env->GetMethodID(integerCls, "intValue", "()I"); - for (int i = 0; i < count; ++i) { - auto integer = env->CallObjectMethod(list, get, i); - data[i] = env->CallIntMethod(integer, intValue); - } -} - -extern "C" -JNIEXPORT jobject JNICALL -Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg, jint uid) { - if (env->GetStringLength(pkg) > KSU_MAX_PACKAGE_NAME) { - return nullptr; - } - - p_key_t key = {}; - auto cpkg = env->GetStringUTFChars(pkg, nullptr); - strcpy(key, cpkg); - env->ReleaseStringUTFChars(pkg, cpkg); - - app_profile profile = {}; - profile.version = KSU_APP_PROFILE_VER; - - strcpy(profile.key, key); - profile.current_uid = uid; - - bool useDefaultProfile = !get_app_profile(key, &profile); - - auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile"); - auto constructor = env->GetMethodID(cls, "", "()V"); - auto obj = env->NewObject(cls, constructor); - auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;"); - auto currentUidField = env->GetFieldID(cls, "currentUid", "I"); - auto allowSuField = env->GetFieldID(cls, "allowSu", "Z"); - - auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z"); - auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;"); - - auto uidField = env->GetFieldID(cls, "uid", "I"); - auto gidField = env->GetFieldID(cls, "gid", "I"); - auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;"); - auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;"); - auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;"); - auto namespacesField = env->GetFieldID(cls, "namespace", "I"); - - auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z"); - auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z"); - - env->SetObjectField(obj, keyField, env->NewStringUTF(profile.key)); - env->SetIntField(obj, currentUidField, profile.current_uid); - - if (useDefaultProfile) { - // no profile found, so just use default profile: - // don't allow root and use default profile! - LOGD("use default profile for: %s, %d", key, uid); - - // allow_su = false - // non root use default = true - env->SetBooleanField(obj, allowSuField, false); - env->SetBooleanField(obj, nonRootUseDefaultField, true); - - return obj; - } - - auto allowSu = profile.allow_su; - - if (allowSu) { - env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default); - if (strlen(profile.rp_config.template_name) > 0) { - env->SetObjectField(obj, rootTemplateField, - env->NewStringUTF(profile.rp_config.template_name)); - } - - env->SetIntField(obj, uidField, profile.rp_config.profile.uid); - env->SetIntField(obj, gidField, profile.rp_config.profile.gid); - - jobject groupList = env->GetObjectField(obj, groupsField); - int groupCount = profile.rp_config.profile.groups_count; - if (groupCount > KSU_MAX_GROUPS) { - LOGD("kernel group count too large: %d???", groupCount); - groupCount = KSU_MAX_GROUPS; - } - fillIntArray(env, groupList, profile.rp_config.profile.groups, groupCount); - - jobject capList = env->GetObjectField(obj, capabilitiesField); - for (int i = 0; i <= CAP_LAST_CAP; i++) { - if (profile.rp_config.profile.capabilities.effective & (1ULL << i)) { - addIntToList(env, capList, i); - } - } - - env->SetObjectField(obj, domainField, - env->NewStringUTF(profile.rp_config.profile.selinux_domain)); - env->SetIntField(obj, namespacesField, profile.rp_config.profile.namespaces); - env->SetBooleanField(obj, allowSuField, profile.allow_su); - } else { - env->SetBooleanField(obj, nonRootUseDefaultField, - (jboolean) profile.nrp_config.use_default); - env->SetBooleanField(obj, umountModulesField, profile.nrp_config.profile.umount_modules); - } - - return obj; -} - -extern "C" -JNIEXPORT jboolean JNICALL -Java_me_weishu_kernelsu_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobject profile) { - auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile"); - - auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;"); - auto currentUidField = env->GetFieldID(cls, "currentUid", "I"); - auto allowSuField = env->GetFieldID(cls, "allowSu", "Z"); - - auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z"); - auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;"); - - auto uidField = env->GetFieldID(cls, "uid", "I"); - auto gidField = env->GetFieldID(cls, "gid", "I"); - auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;"); - auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;"); - auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;"); - auto namespacesField = env->GetFieldID(cls, "namespace", "I"); - - auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z"); - auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z"); - - auto key = env->GetObjectField(profile, keyField); - if (!key) { - return false; - } - if (env->GetStringLength((jstring) key) > KSU_MAX_PACKAGE_NAME) { - return false; - } - - auto cpkg = env->GetStringUTFChars((jstring) key, nullptr); - p_key_t p_key = {}; - strcpy(p_key, cpkg); - env->ReleaseStringUTFChars((jstring) key, cpkg); - - auto currentUid = env->GetIntField(profile, currentUidField); - - auto uid = env->GetIntField(profile, uidField); - auto gid = env->GetIntField(profile, gidField); - auto groups = env->GetObjectField(profile, groupsField); - auto capabilities = env->GetObjectField(profile, capabilitiesField); - auto domain = env->GetObjectField(profile, domainField); - auto allowSu = env->GetBooleanField(profile, allowSuField); - auto umountModules = env->GetBooleanField(profile, umountModulesField); - - app_profile p = {}; - p.version = KSU_APP_PROFILE_VER; - - strcpy(p.key, p_key); - p.allow_su = allowSu; - p.current_uid = currentUid; - - if (allowSu) { - p.rp_config.use_default = env->GetBooleanField(profile, rootUseDefaultField); - auto templateName = env->GetObjectField(profile, rootTemplateField); - if (templateName) { - auto ctemplateName = env->GetStringUTFChars((jstring) templateName, nullptr); - strcpy(p.rp_config.template_name, ctemplateName); - env->ReleaseStringUTFChars((jstring) templateName, ctemplateName); - } - - p.rp_config.profile.uid = uid; - p.rp_config.profile.gid = gid; - - int groups_count = getListSize(env, groups); - if (groups_count > KSU_MAX_GROUPS) { - LOGD("groups count too large: %d", groups_count); - return false; - } - p.rp_config.profile.groups_count = groups_count; - fillArrayWithList(env, groups, p.rp_config.profile.groups, groups_count); - - p.rp_config.profile.capabilities.effective = capListToBits(env, capabilities); - - auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr); - strcpy(p.rp_config.profile.selinux_domain, cdomain); - env->ReleaseStringUTFChars((jstring) domain, cdomain); - - p.rp_config.profile.namespaces = env->GetIntField(profile, namespacesField); - } else { - p.nrp_config.use_default = env->GetBooleanField(profile, nonRootUseDefaultField); - p.nrp_config.profile.umount_modules = umountModules; - } - - return set_app_profile(&p); -} -extern "C" -JNIEXPORT jboolean JNICALL -Java_me_weishu_kernelsu_Natives_uidShouldUmount(JNIEnv *env, jobject thiz, jint uid) { - return uid_should_umount(uid); -} \ No newline at end of file diff --git a/manager/app/src/main/cpp/ksu.cc b/manager/app/src/main/cpp/ksu.cc deleted file mode 100644 index 1e798189..00000000 --- a/manager/app/src/main/cpp/ksu.cc +++ /dev/null @@ -1,86 +0,0 @@ -// -// Created by weishu on 2022/12/9. -// - -#include -#include -#include -#include -#include - -#include "ksu.h" - -#define KERNEL_SU_OPTION 0xDEADBEEF - -#define CMD_GRANT_ROOT 0 - -#define CMD_BECOME_MANAGER 1 -#define CMD_GET_VERSION 2 -#define CMD_ALLOW_SU 3 -#define CMD_DENY_SU 4 -#define CMD_GET_SU_LIST 5 -#define CMD_GET_DENY_LIST 6 -#define CMD_CHECK_SAFEMODE 9 - -#define CMD_GET_APP_PROFILE 10 -#define CMD_SET_APP_PROFILE 11 - -#define CMD_IS_UID_GRANTED_ROOT 12 -#define CMD_IS_UID_SHOULD_UMOUNT 13 - -static bool ksuctl(int cmd, void* arg1, void* arg2) { - int32_t result = 0; - prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result); - return result == KERNEL_SU_OPTION; -} - -bool become_manager(const char* pkg) { - char param[128]; - uid_t uid = getuid(); - uint32_t userId = uid / 100000; - if (userId == 0) { - sprintf(param, "/data/data/%s", pkg); - } else { - snprintf(param, sizeof(param), "/data/user/%d/%s", userId, pkg); - } - - return ksuctl(CMD_BECOME_MANAGER, param, nullptr); -} - -// cache the result to avoid unnecessary syscall -static bool is_lkm; -int get_version() { - int32_t version = -1; - int32_t lkm = 0; - ksuctl(CMD_GET_VERSION, &version, &lkm); - if (!is_lkm && lkm != 0) { - is_lkm = true; - } - return version; -} - -bool get_allow_list(int *uids, int *size) { - return ksuctl(CMD_GET_SU_LIST, uids, size); -} - -bool is_safe_mode() { - return ksuctl(CMD_CHECK_SAFEMODE, nullptr, nullptr); -} - -bool is_lkm_mode() { - // you should call get_version first! - return is_lkm; -} - -bool uid_should_umount(int uid) { - bool should; - return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, reinterpret_cast(uid), &should) && should; -} - -bool set_app_profile(const app_profile *profile) { - return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, nullptr); -} - -bool get_app_profile(p_key_t key, app_profile *profile) { - return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr); -} diff --git a/manager/app/src/main/cpp/ksu.h b/manager/app/src/main/cpp/ksu.h deleted file mode 100644 index 160a9d6f..00000000 --- a/manager/app/src/main/cpp/ksu.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// Created by weishu on 2022/12/9. -// - -#ifndef KERNELSU_KSU_H -#define KERNELSU_KSU_H - -#include - -bool become_manager(const char *); - -int get_version(); - -bool get_allow_list(int *uids, int *size); - -bool uid_should_umount(int uid); - -bool is_safe_mode(); - -bool is_lkm_mode(); - -#define KSU_APP_PROFILE_VER 2 -#define KSU_MAX_PACKAGE_NAME 256 -// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups. -#define KSU_MAX_GROUPS 32 -#define KSU_SELINUX_DOMAIN 64 - -using p_key_t = char[KSU_MAX_PACKAGE_NAME]; - -struct root_profile { - int32_t uid; - int32_t gid; - - int32_t groups_count; - int32_t groups[KSU_MAX_GROUPS]; - - // kernel_cap_t is u32[2] for capabilities v3 - struct { - uint64_t effective; - uint64_t permitted; - uint64_t inheritable; - } capabilities; - - char selinux_domain[KSU_SELINUX_DOMAIN]; - - int32_t namespaces; -}; - -struct non_root_profile { - bool umount_modules; -}; - -struct app_profile { - // It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this. - uint32_t version; - - // this is usually the package of the app, but can be other value for special apps - char key[KSU_MAX_PACKAGE_NAME]; - int32_t current_uid; - bool allow_su; - - union { - struct { - bool use_default; - char template_name[KSU_MAX_PACKAGE_NAME]; - - struct root_profile profile; - } rp_config; - - struct { - bool use_default; - - struct non_root_profile profile; - } nrp_config; - }; -}; - -bool set_app_profile(const app_profile *profile); - -bool get_app_profile(p_key_t key, app_profile *profile); - -#endif //KERNELSU_KSU_H diff --git a/manager/app/src/main/java/me/weishu/kernelsu/KernelSUApplication.kt b/manager/app/src/main/java/me/weishu/kernelsu/KernelSUApplication.kt deleted file mode 100644 index 0503b42f..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/KernelSUApplication.kt +++ /dev/null @@ -1,36 +0,0 @@ -package me.weishu.kernelsu - -import android.app.Application -import coil.Coil -import coil.ImageLoader -import me.zhanghai.android.appiconloader.coil.AppIconFetcher -import me.zhanghai.android.appiconloader.coil.AppIconKeyer -import java.io.File - -lateinit var ksuApp: KernelSUApplication - -class KernelSUApplication : Application() { - - override fun onCreate() { - super.onCreate() - ksuApp = this - - val context = this - val iconSize = resources.getDimensionPixelSize(android.R.dimen.app_icon_size) - Coil.setImageLoader( - ImageLoader.Builder(context) - .components { - add(AppIconKeyer()) - add(AppIconFetcher.Factory(iconSize, false, context)) - } - .build() - ) - - val webroot = File(dataDir, "webroot") - if (!webroot.exists()) { - webroot.mkdir() - } - } - - -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/Kernels.kt b/manager/app/src/main/java/me/weishu/kernelsu/Kernels.kt deleted file mode 100644 index 860e46fc..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/Kernels.kt +++ /dev/null @@ -1,44 +0,0 @@ -package me.weishu.kernelsu - -import android.system.Os - -/** - * @author weishu - * @date 2022/12/10. - */ - -data class KernelVersion(val major: Int, val patchLevel: Int, val subLevel: Int) { - override fun toString(): String { - return "$major.$patchLevel.$subLevel" - } - - fun isGKI(): Boolean { - - // kernel 6.x - if (major > 5) { - return true - } - - // kernel 5.10.x - if (major == 5) { - return patchLevel >= 10 - } - - return false - } -} - -fun parseKernelVersion(version: String): KernelVersion { - val find = "(\\d+)\\.(\\d+)\\.(\\d+)".toRegex().find(version) - return if (find != null) { - KernelVersion(find.groupValues[1].toInt(), find.groupValues[2].toInt(), find.groupValues[3].toInt()) - } else { - KernelVersion(-1, -1, -1) - } -} - -fun getKernelVersion(): KernelVersion { - Os.uname().release.let { - return parseKernelVersion(it) - } -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/Natives.kt b/manager/app/src/main/java/me/weishu/kernelsu/Natives.kt deleted file mode 100644 index bb788293..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/Natives.kt +++ /dev/null @@ -1,117 +0,0 @@ -package me.weishu.kernelsu - -import android.os.Parcelable -import androidx.annotation.Keep -import androidx.compose.runtime.Immutable -import kotlinx.parcelize.Parcelize - -/** - * @author weishu - * @date 2022/12/8. - */ -object Natives { - // minimal supported kernel version - // 10915: allowlist breaking change, add app profile - // 10931: app profile struct add 'version' field - // 10946: add capabilities - // 10977: change groups_count and groups to avoid overflow write - // 11071: Fix the issue of failing to set a custom SELinux type. - const val MINIMAL_SUPPORTED_KERNEL = 11071 - - // 11640: Support query working mode, LKM or GKI - // when MINIMAL_SUPPORTED_KERNEL > 11640, we can remove this constant. - const val MINIMAL_SUPPORTED_KERNEL_LKM = 11648 - const val KERNEL_SU_DOMAIN = "u:r:su:s0" - - const val ROOT_UID = 0 - const val ROOT_GID = 0 - - init { - System.loadLibrary("kernelsu") - } - - // become root manager, return true if success. - external fun becomeManager(pkg: String?): Boolean - val version: Int - external get - - // get the uid list of allowed su processes. - val allowList: IntArray - external get - - val isSafeMode: Boolean - external get - - val isLkmMode: Boolean - external get - - external fun uidShouldUmount(uid: Int): Boolean - - /** - * Get the profile of the given package. - * @param key usually the package name - * @return return null if failed. - */ - external fun getAppProfile(key: String?, uid: Int): Profile - external fun setAppProfile(profile: Profile?): Boolean - - private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$" - private const val NOBODY_UID = 9999 - - fun setDefaultUmountModules(umountModules: Boolean): Boolean { - Profile( - NON_ROOT_DEFAULT_PROFILE_KEY, - NOBODY_UID, - false, - umountModules = umountModules - ).let { - return setAppProfile(it) - } - } - - fun isDefaultUmountModules(): Boolean { - getAppProfile(NON_ROOT_DEFAULT_PROFILE_KEY, NOBODY_UID).let { - return it.umountModules - } - } - - fun requireNewKernel(): Boolean { - return version < MINIMAL_SUPPORTED_KERNEL - } - - @Immutable - @Parcelize - @Keep - data class Profile( - // and there is a default profile for root and non-root - val name: String, - // current uid for the package, this is convivent for kernel to check - // if the package name doesn't match uid, then it should be invalidated. - val currentUid: Int = 0, - - // if this is true, kernel will grant root permission to this package - val allowSu: Boolean = false, - - // these are used for root profile - val rootUseDefault: Boolean = true, - val rootTemplate: String? = null, - val uid: Int = ROOT_UID, - val gid: Int = ROOT_GID, - val groups: List = mutableListOf(), - val capabilities: List = mutableListOf(), - val context: String = KERNEL_SU_DOMAIN, - val namespace: Int = Namespace.INHERITED.ordinal, - - val nonRootUseDefault: Boolean = true, - val umountModules: Boolean = true, - var rules: String = "", // this field is save in ksud!! - ) : Parcelable { - enum class Namespace { - INHERITED, - GLOBAL, - INDIVIDUAL, - } - - constructor() : this("") - } -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/profile/Capabilities.kt b/manager/app/src/main/java/me/weishu/kernelsu/profile/Capabilities.kt deleted file mode 100644 index d52518c2..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/profile/Capabilities.kt +++ /dev/null @@ -1,49 +0,0 @@ -package me.weishu.kernelsu.profile - -/** - * @author weishu - * @date 2023/6/3. - */ -enum class Capabilities(val cap: Int, val display: String, val desc: String) { - CAP_CHOWN(0, "CHOWN", "Make arbitrary changes to file UIDs and GIDs (see chown(2))"), - CAP_DAC_OVERRIDE(1, "DAC_OVERRIDE", "Bypass file read, write, and execute permission checks"), - CAP_DAC_READ_SEARCH(2, "DAC_READ_SEARCH", "Bypass file read permission checks and directory read and execute permission checks"), - CAP_FOWNER(3, "FOWNER", "Bypass permission checks on operations that normally require the filesystem UID of the process to match the UID of the file (e.g., chmod(2), utime(2)), excluding those operations covered by CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH"), - CAP_FSETID(4, "FSETID", "Don’t clear set-user-ID and set-group-ID permission bits when a file is modified; set the set-group-ID bit for a file whose GID does not match the filesystem or any of the supplementary GIDs of the calling process"), - CAP_KILL(5, "KILL", "Bypass permission checks for sending signals (see kill(2))."), - CAP_SETGID(6, "SETGID", "Make arbitrary manipulations of process GIDs and supplementary GID list; allow setgid(2) manipulation of the caller’s effective and real group IDs"), - CAP_SETUID(7, "SETUID", "Make arbitrary manipulations of process UIDs (setuid(2), setreuid(2), setresuid(2), setfsuid(2)); allow changing the current process user IDs; allow changing of the current process group ID to any value in the system’s range of legal group IDs"), - CAP_SETPCAP(8, "SETPCAP", "If file capabilities are supported: grant or remove any capability in the caller’s permitted capability set to or from any other process. (This property supersedes the obsolete notion of giving a process all capabilities by granting all capabilities in its permitted set, and of removing all capabilities from a process by granting no capabilities in its permitted set. It does not permit any actions that were not permitted before.)"), - CAP_LINUX_IMMUTABLE(9, "LINUX_IMMUTABLE", "Set the FS_APPEND_FL and FS_IMMUTABLE_FL inode flags (see chattr(1))."), - CAP_NET_BIND_SERVICE(10, "NET_BIND_SERVICE", "Bind a socket to Internet domain"), - CAP_NET_BROADCAST(11, "NET_BROADCAST", "Make socket broadcasts, and listen to multicasts"), - CAP_NET_ADMIN(12, "NET_ADMIN", "Perform various network-related operations: interface configuration, administration of IP firewall, masquerading, and accounting, modify routing tables, bind to any address for transparent proxying, set type-of-service (TOS), clear driver statistics, set promiscuous mode, enabling multicasting, use setsockopt(2) to set the following socket options: SO_DEBUG, SO_MARK, SO_PRIORITY (for a priority outside the range 0 to 6), SO_RCVBUFFORCE, and SO_SNDBUFFORCE"), - CAP_NET_RAW(13, "NET_RAW", "Use RAW and PACKET sockets"), - CAP_IPC_LOCK(14, "IPC_LOCK", "Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2))"), - CAP_IPC_OWNER(15, "IPC_OWNER", "Bypass permission checks for operations on System V IPC objects"), - CAP_SYS_MODULE(16, "SYS_MODULE", "Load and unload kernel modules (see init_module(2) and delete_module(2)); in kernels before 2.6.25, this also granted rights for various other operations related to kernel modules"), - CAP_SYS_RAWIO(17, "SYS_RAWIO", "Perform I/O port operations (iopl(2) and ioperm(2)); access /proc/kcore"), - CAP_SYS_CHROOT(18, "SYS_CHROOT", "Use chroot(2)"), - CAP_SYS_PTRACE(19, "SYS_PTRACE", "Trace arbitrary processes using ptrace(2)"), - CAP_SYS_PACCT(20, "SYS_PACCT", "Use acct(2)"), - CAP_SYS_ADMIN(21, "SYS_ADMIN", "Perform a range of system administration operations including: quotactl(2), mount(2), umount(2), swapon(2), swapoff(2), sethostname(2), and setdomainname(2); set and modify process resource limits (setrlimit(2)); perform various network-related operations (e.g., setting privileged socket options, enabling multicasting, interface configuration); perform various IPC operations (e.g., SysV semaphores, POSIX message queues, System V shared memory); allow reboot and kexec_load(2); override /proc/sys kernel tunables; perform ptrace(2) PTRACE_SECCOMP_GET_FILTER operation; perform some tracing and debugging operations (see ptrace(2)); administer the lifetime of kernel tracepoints (tracefs(5)); perform the KEYCTL_CHOWN and KEYCTL_SETPERM keyctl(2) operations; perform the following keyctl(2) operations: KEYCTL_CAPABILITIES, KEYCTL_CAPSQUASH, and KEYCTL_PKEY_ OPERATIONS; set state for the Extensible Authentication Protocol (EAP) kernel module; and override the RLIMIT_NPROC resource limit; allow ioperm/iopl access to I/O ports"), - CAP_SYS_BOOT(22, "SYS_BOOT", "Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution"), - CAP_SYS_NICE(23, "SYS_NICE", "Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes; set real-time scheduling policies for calling process, and set scheduling policies and priorities for arbitrary processes (sched_setscheduler(2), sched_setparam(2)"), - CAP_SYS_RESOURCE(24, "SYS_RESOURCE", "Override resource Limits. Set resource limits (setrlimit(2), prlimit(2)), override quota limits (quota(2), quotactl(2)), override reserved space on ext2 filesystem (ext2_ioctl(2)), override size restrictions on IPC message queues (msg(2)) and system V shared memory segments (shmget(2)), and override the /proc/sys/fs/pipe-size-max limit"), - CAP_SYS_TIME(25, "SYS_TIME", "Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock"), - CAP_SYS_TTY_CONFIG(26, "SYS_TTY_CONFIG", "Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals"), - CAP_MKNOD(27, "MKNOD", "Create special files using mknod(2)"), - CAP_LEASE(28, "LEASE", "Establish leases on arbitrary files (see fcntl(2))"), - CAP_AUDIT_WRITE(29, "AUDIT_WRITE", "Write records to kernel auditing log"), - CAP_AUDIT_CONTROL(30, "AUDIT_CONTROL", "Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules"), - CAP_SETFCAP(31, "SETFCAP", "If file capabilities are supported: grant or remove any capability in any capability set to any file"), - CAP_MAC_OVERRIDE(32, "MAC_OVERRIDE", "Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM)"), - CAP_MAC_ADMIN(33, "MAC_ADMIN", "Allow MAC configuration or state changes. Implemented for the Smack LSM"), - CAP_SYSLOG(34, "SYSLOG", "Perform privileged syslog(2) operations. See syslog(2) for information on which operations require privilege"), - CAP_WAKE_ALARM(35, "WAKE_ALARM", "Trigger something that will wake up the system"), - CAP_BLOCK_SUSPEND(36, "BLOCK_SUSPEND", "Employ features that can block system suspend"), - CAP_AUDIT_READ(37, "AUDIT_READ", "Allow reading the audit log via a multicast netlink socket"), - CAP_PERFMON(38, "PERFMON", "Allow performance monitoring via perf_event_open(2)"), - CAP_BPF(39, "BPF", "Allow BPF operations via bpf(2)"), - CAP_CHECKPOINT_RESTORE(40, "CHECKPOINT_RESTORE", "Allow processes to be checkpointed via checkpoint/restore in user namespace(2)"), -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/profile/Groups.kt b/manager/app/src/main/java/me/weishu/kernelsu/profile/Groups.kt deleted file mode 100644 index 2ddb94dc..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/profile/Groups.kt +++ /dev/null @@ -1,130 +0,0 @@ -package me.weishu.kernelsu.profile - -/** - * https://cs.android.com/android/platform/superproject/main/+/main:system/core/libcutils/include/private/android_filesystem_config.h - * @author weishu - * @date 2023/6/3. - */ -enum class Groups(val gid: Int, val display: String, val desc: String) { - ROOT(0, "root", "traditional unix root user"), - DAEMON(1, "daemon", "Traditional unix daemon owner."), - BIN(2, "bin", "Traditional unix binaries owner."), - SYS(3, "sys", "A group with the same gid on Linux/macOS/Android."), - SYSTEM(1000, "system", "system server"), - RADIO(1001, "radio", "telephony subsystem, RIL"), - BLUETOOTH(1002, "bluetooth", "bluetooth subsystem"), - GRAPHICS(1003, "graphics", "graphics devices"), - INPUT(1004, "input", "input devices"), - AUDIO(1005, "audio", "audio devices"), - CAMERA(1006, "camera", "camera devices"), - LOG(1007, "log", "log devices"), - COMPASS(1008, "compass", "compass device"), - MOUNT(1009, "mount", "mountd socket"), - WIFI(1010, "wifi", "wifi subsystem"), - ADB(1011, "adb", "android debug bridge (adbd)"), - INSTALL(1012, "install", "group for installing packages"), - MEDIA(1013, "media", "mediaserver process"), - DHCP(1014, "dhcp", "dhcp client"), - SDCARD_RW(1015, "sdcard_rw", "external storage write access"), - VPN(1016, "vpn", "vpn system"), - KEYSTORE(1017, "keystore", "keystore subsystem"), - USB(1018, "usb", "USB devices"), - DRM(1019, "drm", "DRM server"), - MDNSR(1020, "mdnsr", "MulticastDNSResponder (service discovery)"), - GPS(1021, "gps", "GPS daemon"), - UNUSED1(1022, "unused1", "deprecated, DO NOT USE"), - MEDIA_RW(1023, "media_rw", "internal media storage write access"), - MTP(1024, "mtp", "MTP USB driver access"), - UNUSED2(1025, "unused2", "deprecated, DO NOT USE"), - DRMRPC(1026, "drmrpc", "group for drm rpc"), - NFC(1027, "nfc", "nfc subsystem"), - SDCARD_R(1028, "sdcard_r", "external storage read access"), - CLAT(1029, "clat", "clat part of nat464"), - LOOP_RADIO(1030, "loop_radio", "loop radio devices"), - MEDIA_DRM(1031, "media_drm", "MediaDrm plugins"), - PACKAGE_INFO(1032, "package_info", "access to installed package details"), - SDCARD_PICS(1033, "sdcard_pics", "external storage photos access"), - SDCARD_AV(1034, "sdcard_av", "external storage audio/video access"), - SDCARD_ALL(1035, "sdcard_all", "access all users external storage"), - LOGD(1036, "logd", "log daemon"), - SHARED_RELRO(1037, "shared_relro", "creator of shared GNU RELRO files"), - DBUS(1038, "dbus", "dbus-daemon IPC broker process"), - TLSDATE(1039, "tlsdate", "tlsdate unprivileged user"), - MEDIA_EX(1040, "media_ex", "mediaextractor process"), - AUDIOSERVER(1041, "audioserver", "audioserver process"), - METRICS_COLL(1042, "metrics_coll", "metrics_collector process"), - METRICSD(1043, "metricsd", "metricsd process"), - WEBSERV(1044, "webserv", "webservd process"), - DEBUGGERD(1045, "debuggerd", "debuggerd unprivileged user"), - MEDIA_CODEC(1046, "media_codec", "media_codec process"), - CAMERASERVER(1047, "cameraserver", "cameraserver process"), - FIREWALL(1048, "firewall", "firewall process"), - TRUNKS(1049, "trunks", "trunksd process"), - NVRAM(1050, "nvram", "nvram daemon"), - DNS(1051, "dns", "DNS resolution daemon (system: netd)"), - DNS_TETHER(1052, "dns_tether", "DNS resolution daemon (tether: dnsmasq)"), - WEBVIEW_ZYGOTE(1053, "webview_zygote", "WebView zygote process"), - VEHICLE_NETWORK(1054, "vehicle_network", "Vehicle network service"), - MEDIA_AUDIO(1055, "media_audio", "GID for audio files on internal media storage"), - MEDIA_VIDEO(1056, "media_video", "GID for video files on internal media storage"), - MEDIA_IMAGE(1057, "media_image", "GID for image files on internal media storage"), - TOMBSTONED(1058, "tombstoned", "tombstoned user"), - MEDIA_OBB(1059, "media_obb", "GID for OBB files on internal media storage"), - ESE(1060, "ese", "embedded secure element (eSE) subsystem"), - OTA_UPDATE(1061, "ota_update", "resource tracking UID for OTA updates"), - AUTOMOTIVE_EVS(1062, "automotive_evs", "Automotive rear and surround view system"), - LOWPAN(1063, "lowpan", "LoWPAN subsystem"), - HSM(1064, "lowpan", "hardware security module subsystem"), - RESERVED_DISK(1065, "reserved_disk", "GID that has access to reserved disk space"), - STATSD(1066, "statsd", "statsd daemon"), - INCIDENTD(1067, "incidentd", "incidentd daemon"), - SECURE_ELEMENT(1068, "secure_element", "secure element subsystem"), - LMKD(1069, "lmkd", "low memory killer daemon"), - LLKD(1070, "llkd", "live lock daemon"), - IORAPD(1071, "iorapd", "input/output readahead and pin daemon"), - GPU_SERVICE(1072, "gpu_service", "GPU service daemon"), - NETWORK_STACK(1073, "network_stack", "network stack service"), - GSID(1074, "GSID", "GSI service daemon"), - FSVERITY_CERT(1075, "fsverity_cert", "fs-verity key ownership in keystore"), - CREDSTORE(1076, "credstore", "identity credential manager service"), - EXTERNAL_STORAGE(1077, "external_storage", "Full external storage access including USB OTG volumes"), - EXT_DATA_RW(1078, "ext_data_rw", "GID for app-private data directories on external storage"), - EXT_OBB_RW(1079, "ext_obb_rw", "GID for OBB directories on external storage"), - CONTEXT_HUB(1080, "context_hub", "GID for access to the Context Hub"), - VIRTUALIZATIONSERVICE(1081, "virtualizationservice", "VirtualizationService daemon"), - ARTD(1082, "artd", "ART Service daemon"), - UWB(1083, "uwb", "UWB subsystem"), - THREAD_NETWORK(1084, "thread_network", "Thread Network subsystem"), - DICED(1085, "diced", "Android's DICE daemon"), - DMESGD(1086, "dmesgd", "dmesg parsing daemon for kernel report collection"), - JC_WEAVER(1087, "jc_weaver", "Javacard Weaver HAL - to manage omapi ARA rules"), - JC_STRONGBOX(1088, "jc_strongbox", "Javacard Strongbox HAL - to manage omapi ARA rules"), - JC_IDENTITYCRED(1089, "jc_identitycred", "Javacard Identity Cred HAL - to manage omapi ARA rules"), - SDK_SANDBOX(1090, "sdk_sandbox", "SDK sandbox virtual UID"), - SECURITY_LOG_WRITER(1091, "security_log_writer", "write to security log"), - PRNG_SEEDER(1092, "prng_seeder", "PRNG seeder daemon"), - - SHELL(2000, "shell", "adb and debug shell user"), - CACHE(2001, "cache", "cache access"), - DIAG(2002, "diag", "access to diagnostic resources"), - - /* The 3000 series are intended for use as supplemental group id's only. - * They indicate special Android capabilities that the kernel is aware of. */ - NET_BT_ADMIN(3001, "net_bt_admin", "bluetooth: create any socket"), - NET_BT(3002, "net_bt", "bluetooth: create sco, rfcomm or l2cap sockets"), - INET(3003, "inet", "can create AF_INET and AF_INET6 sockets"), - NET_RAW(3004, "net_raw", "can create raw INET sockets"), - NET_ADMIN(3005, "net_admin", "can configure interfaces and routing tables."), - NET_BW_STATS(3006, "net_bw_stats", "read bandwidth statistics"), - NET_BW_ACCT(3007, "net_bw_acct", "change bandwidth statistics accounting"), - NET_BT_STACK(3008, "net_bt_stack", "access to various bluetooth management functions"), - READPROC(3009, "readproc", "Allow /proc read access"), - WAKELOCK(3010, "wakelock", "Allow system wakelock read/write access"), - UHID(3011, "uhid", "Allow read/write to /dev/uhid node"), - READTRACEFS(3012, "readtracefs", "Allow tracefs read"), - - EVERYBODY(9997, "everybody", "Shared external storage read/write"), - MISC(9998, "misc", "Access to misc storage"), - NOBODY(9999, "nobody", "Reserved"), - APP(10000, "app", "Access to app data"), -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/KsuService.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/KsuService.java deleted file mode 100644 index 2ebcc786..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/KsuService.java +++ /dev/null @@ -1,77 +0,0 @@ -package me.weishu.kernelsu.ui; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.IBinder; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.topjohnwu.superuser.ipc.RootService; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import me.weishu.kernelsu.IKsuInterface; -import rikka.parcelablelist.ParcelableListSlice; - -/** - * @author weishu - * @date 2023/4/18. - */ - -public class KsuService extends RootService { - - private static final String TAG = "KsuService"; - - class Stub extends IKsuInterface.Stub { - @Override - public ParcelableListSlice getPackages(int flags) { - List list = getInstalledPackagesAll(flags); - Log.i(TAG, "getPackages: " + list.size()); - return new ParcelableListSlice<>(list); - } - } - - @Override - public IBinder onBind(@NonNull Intent intent) { - return new Stub(); - } - - List getUserIds() { - List result = new ArrayList<>(); - UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); - List userProfiles = um.getUserProfiles(); - for (UserHandle userProfile : userProfiles) { - int userId = userProfile.hashCode(); - result.add(userProfile.hashCode()); - } - return result; - } - - ArrayList getInstalledPackagesAll(int flags) { - ArrayList packages = new ArrayList<>(); - for (Integer userId : getUserIds()) { - Log.i(TAG, "getInstalledPackagesAll: " + userId); - packages.addAll(getInstalledPackagesAsUser(flags, userId)); - } - return packages; - } - - List getInstalledPackagesAsUser(int flags, int userId) { - try { - PackageManager pm = getPackageManager(); - Method getInstalledPackagesAsUser = pm.getClass().getDeclaredMethod("getInstalledPackagesAsUser", int.class, int.class); - return (List) getInstalledPackagesAsUser.invoke(pm, flags, userId); - } catch (Throwable e) { - Log.e(TAG, "err", e); - } - - return new ArrayList<>(); - } -} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt deleted file mode 100644 index 042155fb..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt +++ /dev/null @@ -1,97 +0,0 @@ -package me.weishu.kernelsu.ui - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Icon -import androidx.compose.material3.NavigationBar -import androidx.compose.material3.NavigationBarItem -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import com.ramcosta.composedestinations.DestinationsNavHost -import com.ramcosta.composedestinations.navigation.popBackStack -import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.ksuApp -import me.weishu.kernelsu.ui.screen.BottomBarDestination -import me.weishu.kernelsu.ui.screen.NavGraphs -import me.weishu.kernelsu.ui.theme.KernelSUTheme -import me.weishu.kernelsu.ui.util.LocalSnackbarHost -import me.weishu.kernelsu.ui.util.rootAvailable - -class MainActivity : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContent { - KernelSUTheme { - val navController = rememberNavController() - val snackbarHostState = remember { SnackbarHostState() } - Scaffold( - bottomBar = { BottomBar(navController) }, - snackbarHost = { SnackbarHost(snackbarHostState) } - ) { innerPadding -> - CompositionLocalProvider( - LocalSnackbarHost provides snackbarHostState, - ) { - DestinationsNavHost( - modifier = Modifier.padding(innerPadding), - navGraph = NavGraphs.root, - navController = navController - ) - } - } - } - } - } -} - -@Composable -private fun BottomBar(navController: NavHostController) { - val isManager = Natives.becomeManager(ksuApp.packageName) - val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable() - NavigationBar(tonalElevation = 8.dp) { - BottomBarDestination.entries.forEach { destination -> - if (!fullFeatured && destination.rootRequired) return@forEach - val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction) - NavigationBarItem( - selected = isCurrentDestOnBackStack, - onClick = { - if (isCurrentDestOnBackStack) { - navController.popBackStack(destination.direction, false) - } - - navController.navigate(destination.direction.route) { - popUpTo(NavGraphs.root.route) { - saveState = true - } - launchSingleTop = true - restoreState = true - } - }, - icon = { - if (isCurrentDestOnBackStack) { - Icon(destination.iconSelected, stringResource(destination.label)) - } else { - Icon(destination.iconNotSelected, stringResource(destination.label)) - } - }, - label = { Text(stringResource(destination.label)) }, - alwaysShowLabel = false - ) - } - } -} 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 deleted file mode 100644 index 0807d052..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/AboutCard.kt +++ /dev/null @@ -1,123 +0,0 @@ -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 -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -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.RoundedCornerShape -import androidx.compose.material3.ElevatedCard -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.MaterialTheme -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.res.stringResource -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 - -@Preview -@Composable -fun AboutCard() { - ElevatedCard( - modifier = Modifier - .fillMaxWidth(), - shape = RoundedCornerShape(8.dp), - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(24.dp) - ) { - AboutCardContent() - } - } -} - -@Composable -fun AboutDialog(dismiss: () -> Unit) { - Dialog(onDismissRequest = { dismiss() }) { - AboutCard() - } -} - -@Composable -private fun AboutCardContent() { - Column( - 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) - ) - - Spacer(modifier = Modifier.width(12.dp)) - - Column { - - Text( - stringResource(id = R.string.app_name), - style = MaterialTheme.typography.titleSmall, - fontSize = 18.sp - ) - Text( - BuildConfig.VERSION_NAME, - style = MaterialTheme.typography.bodySmall, - fontSize = 14.sp - ) - - Spacer(modifier = Modifier.height(8.dp)) - - HtmlText( - html = stringResource( - id = R.string.about_source_code, - "GitHub", - "Telegram" - ) - ) - } - } - } -} - -@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 deleted file mode 100644 index e2c3fa45..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt +++ /dev/null @@ -1,450 +0,0 @@ -package me.weishu.kernelsu.ui.component - -import android.graphics.text.LineBreaker -import android.os.Parcelable -import android.text.Layout -import android.text.method.LinkMovementMethod -import android.util.Log -import android.view.ViewGroup -import android.widget.TextView -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.runtime.saveable.Saver -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties -import io.noties.markwon.Markwon -import io.noties.markwon.utils.NoCopySpannableFactory -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.ReceiveChannel -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.flow.consumeAsFlow -import kotlinx.coroutines.flow.onEach -import kotlinx.parcelize.Parcelize -import kotlin.coroutines.resume - -private const val TAG = "DialogComponent" - -interface ConfirmDialogVisuals : Parcelable { - val title: String - val content: String - val isMarkdown: Boolean - val confirm: String? - val dismiss: String? -} - -@Parcelize -private data class ConfirmDialogVisualsImpl( - override val title: String, - override val content: String, - override val isMarkdown: Boolean, - override val confirm: String?, - override val dismiss: String?, -) : ConfirmDialogVisuals { - companion object { - val Empty: ConfirmDialogVisuals = ConfirmDialogVisualsImpl("", "", false, null, null) - } -} - -interface DialogHandle { - val isShown: Boolean - val dialogType: String - fun show() - fun hide() -} - -interface LoadingDialogHandle : DialogHandle { - suspend fun withLoading(block: suspend () -> R): R - fun showLoading() -} - -sealed interface ConfirmResult { - object Confirmed : ConfirmResult - object Canceled : ConfirmResult -} - -interface ConfirmDialogHandle : DialogHandle { - val visuals: ConfirmDialogVisuals - - fun showConfirm( - title: String, - content: String, - markdown: Boolean = false, - confirm: String? = null, - dismiss: String? = null - ) - - suspend fun awaitConfirm( - title: String, - content: String, - markdown: Boolean = false, - confirm: String? = null, - dismiss: String? = null - ): ConfirmResult -} - -private abstract class DialogHandleBase( - protected val visible: MutableState, - protected val coroutineScope: CoroutineScope -) : DialogHandle { - override val isShown: Boolean - get() = visible.value - - override fun show() { - coroutineScope.launch { - visible.value = true - } - } - - final override fun hide() { - coroutineScope.launch { - visible.value = false - } - } - - override fun toString(): String { - return dialogType - } -} - -private class LoadingDialogHandleImpl( - visible: MutableState, - coroutineScope: CoroutineScope -) : LoadingDialogHandle, DialogHandleBase(visible, coroutineScope) { - override suspend fun withLoading(block: suspend () -> R): R { - return coroutineScope.async { - try { - visible.value = true - block() - } finally { - visible.value = false - } - }.await() - } - - override fun showLoading() { - show() - } - - override val dialogType: String get() = "LoadingDialog" -} - -typealias NullableCallback = (() -> Unit)? - -interface ConfirmCallback { - - val onConfirm: NullableCallback - - val onDismiss: NullableCallback - - val isEmpty: Boolean get() = onConfirm == null && onDismiss == null - - companion object { - operator fun invoke(onConfirmProvider: () -> NullableCallback, onDismissProvider: () -> NullableCallback): ConfirmCallback { - return object : ConfirmCallback { - override val onConfirm: NullableCallback - get() = onConfirmProvider() - override val onDismiss: NullableCallback - get() = onDismissProvider() - } - } - } -} - -private class ConfirmDialogHandleImpl( - visible: MutableState, - coroutineScope: CoroutineScope, - callback: ConfirmCallback, - override var visuals: ConfirmDialogVisuals = ConfirmDialogVisualsImpl.Empty, - private val resultFlow: ReceiveChannel -) : ConfirmDialogHandle, DialogHandleBase(visible, coroutineScope) { - private class ResultCollector( - private val callback: ConfirmCallback - ) : FlowCollector { - fun handleResult(result: ConfirmResult) { - Log.d(TAG, "handleResult: ${result.javaClass.simpleName}") - when (result) { - ConfirmResult.Confirmed -> onConfirm() - ConfirmResult.Canceled -> onDismiss() - } - } - - fun onConfirm() { - callback.onConfirm?.invoke() - } - - fun onDismiss() { - callback.onDismiss?.invoke() - } - - override suspend fun emit(value: ConfirmResult) { - handleResult(value) - } - } - - private val resultCollector = ResultCollector(callback) - - private var awaitContinuation: CancellableContinuation? = null - - private val isCallbackEmpty = callback.isEmpty - - init { - coroutineScope.launch { - resultFlow - .consumeAsFlow() - .onEach { result -> - awaitContinuation?.let { - awaitContinuation = null - if (it.isActive) { - it.resume(result) - } - } - } - .onEach { hide() } - .collect(resultCollector) - } - } - - private suspend fun awaitResult(): ConfirmResult { - return suspendCancellableCoroutine { - awaitContinuation = it.apply { - if (isCallbackEmpty) { - invokeOnCancellation { - visible.value = false - } - } - } - } - } - - fun updateVisuals(visuals: ConfirmDialogVisuals) { - this.visuals = visuals - } - - override fun show() { - if (visuals !== ConfirmDialogVisualsImpl.Empty) { - super.show() - } else { - throw UnsupportedOperationException("can't show confirm dialog with the Empty visuals") - } - } - - override fun showConfirm( - title: String, - content: String, - markdown: Boolean, - confirm: String?, - dismiss: String? - ) { - coroutineScope.launch { - updateVisuals(ConfirmDialogVisualsImpl(title, content, markdown, confirm, dismiss)) - show() - } - } - - override suspend fun awaitConfirm( - title: String, - content: String, - markdown: Boolean, - confirm: String?, - dismiss: String? - ): ConfirmResult { - coroutineScope.launch { - updateVisuals(ConfirmDialogVisualsImpl(title, content, markdown, confirm, dismiss)) - show() - } - return awaitResult() - } - - override val dialogType: String get() = "ConfirmDialog" - - override fun toString(): String { - return "${super.toString()}(visuals: $visuals)" - } - - companion object { - fun Saver( - visible: MutableState, - coroutineScope: CoroutineScope, - callback: ConfirmCallback, - resultChannel: ReceiveChannel - ) = Saver( - save = { - it.visuals - }, - restore = { - Log.d(TAG, "ConfirmDialog restore, visuals: $it") - ConfirmDialogHandleImpl(visible, coroutineScope, callback, it, resultChannel) - } - ) - } -} - -private class CustomDialogHandleImpl( - visible: MutableState, - coroutineScope: CoroutineScope -) : DialogHandleBase(visible, coroutineScope) { - override val dialogType: String get() = "CustomDialog" -} - -@Composable -fun rememberLoadingDialog(): LoadingDialogHandle { - val visible = remember { - mutableStateOf(false) - } - val coroutineScope = rememberCoroutineScope() - - if (visible.value) { - LoadingDialog() - } - - return remember { - LoadingDialogHandleImpl(visible, coroutineScope) - } -} - -@Composable -private fun rememberConfirmDialog(visuals: ConfirmDialogVisuals, callback: ConfirmCallback): ConfirmDialogHandle { - val visible = rememberSaveable { - mutableStateOf(false) - } - val coroutineScope = rememberCoroutineScope() - val resultChannel = remember { - Channel() - } - - val handle = rememberSaveable( - saver = ConfirmDialogHandleImpl.Saver(visible, coroutineScope, callback, resultChannel), - init = { - ConfirmDialogHandleImpl(visible, coroutineScope, callback, visuals, resultChannel) - } - ) - - if (visible.value) { - ConfirmDialog( - handle.visuals, - confirm = { coroutineScope.launch { resultChannel.send(ConfirmResult.Confirmed) } }, - dismiss = { coroutineScope.launch { resultChannel.send(ConfirmResult.Canceled) } } - ) - } - - return handle -} - -@Composable -fun rememberConfirmCallback(onConfirm: NullableCallback, onDismiss: NullableCallback): ConfirmCallback { - val currentOnConfirm by rememberUpdatedState(newValue = onConfirm) - val currentOnDismiss by rememberUpdatedState(newValue = onDismiss) - return remember { - ConfirmCallback({ currentOnConfirm }, { currentOnDismiss }) - } -} - -@Composable -fun rememberConfirmDialog(onConfirm: NullableCallback = null, onDismiss: NullableCallback = null): ConfirmDialogHandle { - return rememberConfirmDialog(rememberConfirmCallback(onConfirm, onDismiss)) -} - -@Composable -fun rememberConfirmDialog(callback: ConfirmCallback): ConfirmDialogHandle { - return rememberConfirmDialog(ConfirmDialogVisualsImpl.Empty, callback) -} - -@Composable -fun rememberCustomDialog(composable: @Composable (dismiss: () -> Unit) -> Unit): DialogHandle { - val visible = rememberSaveable { - mutableStateOf(false) - } - val coroutineScope = rememberCoroutineScope() - if (visible.value) { - composable { visible.value = false } - } - return remember { - CustomDialogHandleImpl(visible, coroutineScope) - } -} - -@Composable -private fun LoadingDialog() { - Dialog( - onDismissRequest = {}, - properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false) - ) { - Surface( - modifier = Modifier.size(100.dp), shape = RoundedCornerShape(8.dp) - ) { - Box( - contentAlignment = Alignment.Center, - ) { - CircularProgressIndicator() - } - } - } -} - -@Composable -private fun ConfirmDialog(visuals: ConfirmDialogVisuals, confirm: () -> Unit, dismiss: () -> Unit) { - AlertDialog( - onDismissRequest = { - dismiss() - }, - title = { - Text(text = visuals.title) - }, - text = { - if (visuals.isMarkdown) { - MarkdownContent(content = visuals.content) - } else { - Text(text = visuals.content) - } - }, - confirmButton = { - TextButton(onClick = confirm) { - Text(text = visuals.confirm ?: stringResource(id = android.R.string.ok)) - } - }, - dismissButton = { - TextButton(onClick = dismiss) { - Text(text = visuals.dismiss ?: stringResource(id = android.R.string.cancel)) - } - }, - ) -} - -@Composable -private fun MarkdownContent(content: String) { - val contentColor = LocalContentColor.current - - AndroidView( - factory = { context -> - TextView(context).apply { - movementMethod = LinkMovementMethod.getInstance() - setSpannableFactory(NoCopySpannableFactory.getInstance()) - breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE - hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - }, - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight(), - update = { - Markwon.create(it.context).setMarkdown(it, content) - it.setTextColor(contentColor.toArgb()) - } - ) -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/KeyEventBlocker.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/KeyEventBlocker.kt deleted file mode 100644 index b3268131..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/KeyEventBlocker.kt +++ /dev/null @@ -1,28 +0,0 @@ -package me.weishu.kernelsu.ui.component - -import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.Box -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.input.key.KeyEvent -import androidx.compose.ui.input.key.onKeyEvent - -@Composable -fun KeyEventBlocker(predicate: (KeyEvent) -> Boolean) { - val requester = remember { FocusRequester() } - Box( - Modifier - .onKeyEvent { - predicate(it) - } - .focusRequester(requester) - .focusable() - ) - LaunchedEffect(Unit) { - requester.requestFocus() - } -} \ No newline at end of file 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 deleted file mode 100644 index 8195cddd..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt +++ /dev/null @@ -1,149 +0,0 @@ -package me.weishu.kernelsu.ui.component - -import android.util.Log -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.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.ArrowBack -import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.focus.onFocusChanged -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp - -private const val TAG = "SearchBar" - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun SearchAppBar( - title: @Composable () -> Unit, - searchText: String, - onSearchTextChange: (String) -> Unit, - onClearClick: () -> Unit, - onBackClick: (() -> Unit)? = null, - onConfirm: (() -> Unit)? = null, - dropdownContent: @Composable (() -> Unit)? = null, -) { - val keyboardController = LocalSoftwareKeyboardController.current - val focusRequester = remember { FocusRequester() } - var onSearch by remember { mutableStateOf(false) } - - if (onSearch) { - LaunchedEffect(Unit) { focusRequester.requestFocus() } - } - DisposableEffect(Unit) { - onDispose { - keyboardController?.hide() - } - } - - TopAppBar( - title = { - Box { - AnimatedVisibility( - modifier = Modifier.align(Alignment.CenterStart), - visible = !onSearch, - enter = fadeIn(), - exit = fadeOut(), - content = { title() } - ) - - AnimatedVisibility( - visible = onSearch, - enter = fadeIn(), - exit = fadeOut() - ) { - OutlinedTextField( - modifier = Modifier - .fillMaxWidth() - .padding(top = 2.dp, bottom = 2.dp, end = if (onBackClick != null) 0.dp else 14.dp) - .focusRequester(focusRequester) - .onFocusChanged { focusState -> - if (focusState.isFocused) onSearch = true - Log.d(TAG, "onFocusChanged: $focusState") - }, - value = searchText, - onValueChange = onSearchTextChange, - trailingIcon = { - IconButton( - onClick = { - onSearch = false - keyboardController?.hide() - onClearClick() - }, - content = { Icon(Icons.Filled.Close, null) } - ) - }, - maxLines = 1, - singleLine = true, - keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done), - keyboardActions = KeyboardActions(onDone = { - keyboardController?.hide() - onConfirm?.invoke() - }) - ) - } - } - }, - navigationIcon = { - if (onBackClick != null) { - IconButton( - onClick = onBackClick, - content = { Icon(Icons.AutoMirrored.Outlined.ArrowBack, null) } - ) - } - }, - actions = { - AnimatedVisibility( - visible = !onSearch - ) { - IconButton( - onClick = { onSearch = true }, - content = { Icon(Icons.Filled.Search, null) } - ) - } - - if (dropdownContent != null) { - dropdownContent() - } - - } - ) -} - -@Preview -@Composable -private fun SearchAppBarPreview() { - var searchText by remember { mutableStateOf("") } - SearchAppBar( - title = { Text("Search text") }, - searchText = searchText, - onSearchTextChange = { searchText = it }, - onClearClick = { searchText = "" } - ) -} 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 deleted file mode 100644 index 6db20b16..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SettingsItem.kt +++ /dev/null @@ -1,57 +0,0 @@ -package me.weishu.kernelsu.ui.component - -import androidx.compose.foundation.clickable -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.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector - -@Composable -fun SwitchItem( - icon: ImageVector? = null, - title: String, - summary: String? = null, - checked: Boolean, - enabled: Boolean = true, - onCheckedChange: (Boolean) -> Unit -) { - ListItem( - modifier = Modifier.clickable { - onCheckedChange.invoke(!checked) - }, - headlineContent = { - Text(title) - }, - leadingContent = icon?.let { - { Icon(icon, title) } - }, - trailingContent = { - Switch(checked = checked, enabled = enabled, onCheckedChange = onCheckedChange) - }, - supportingContent = { - if (summary != null) { - Text(summary) - } - } - ) -} - -@Composable -fun RadioItem( - title: String, - selected: Boolean, - onClick: () -> Unit, -) { - ListItem( - headlineContent = { - Text(title) - }, - leadingContent = { - RadioButton(selected = selected, onClick = onClick) - }, - ) -} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/AppProfileConfig.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/AppProfileConfig.kt deleted file mode 100644 index 065ff6d0..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/AppProfileConfig.kt +++ /dev/null @@ -1,63 +0,0 @@ -package me.weishu.kernelsu.ui.component.profile - -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.R -import me.weishu.kernelsu.ui.component.SwitchItem - -@Composable -fun AppProfileConfig( - modifier: Modifier = Modifier, - fixedName: Boolean, - enabled: Boolean, - profile: Natives.Profile, - onProfileChange: (Natives.Profile) -> Unit, -) { - Column(modifier = modifier) { - if (!fixedName) { - OutlinedTextField( - label = { Text(stringResource(R.string.profile_name)) }, - value = profile.name, - onValueChange = { onProfileChange(profile.copy(name = it)) } - ) - } - - SwitchItem( - title = stringResource(R.string.profile_umount_modules), - summary = stringResource(R.string.profile_umount_modules_summary), - checked = if (enabled) { - profile.umountModules - } else { - Natives.isDefaultUmountModules() - }, - enabled = enabled, - onCheckedChange = { - onProfileChange( - profile.copy( - umountModules = it, - nonRootUseDefault = false - ) - ) - } - ) - } -} - -@Preview -@Composable -private fun AppProfileConfigPreview() { - var profile by remember { mutableStateOf(Natives.Profile("")) } - AppProfileConfig(fixedName = true, enabled = false, profile = profile) { - profile = it - } -} 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 deleted file mode 100644 index d2cb3f34..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt +++ /dev/null @@ -1,471 +0,0 @@ -@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.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowDropDown -import androidx.compose.material.icons.filled.ArrowDropUp -import androidx.compose.material3.AssistChip -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.Icon -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -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.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.core.text.isDigitsOnly -import com.maxkeppeker.sheets.core.models.base.Header -import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState -import com.maxkeppeler.sheets.input.InputDialog -import com.maxkeppeler.sheets.input.models.InputHeader -import com.maxkeppeler.sheets.input.models.InputSelection -import com.maxkeppeler.sheets.input.models.InputTextField -import com.maxkeppeler.sheets.input.models.InputTextFieldType -import com.maxkeppeler.sheets.input.models.ValidationResult -import com.maxkeppeler.sheets.list.ListDialog -import com.maxkeppeler.sheets.list.models.ListOption -import com.maxkeppeler.sheets.list.models.ListSelection -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.R -import me.weishu.kernelsu.profile.Capabilities -import me.weishu.kernelsu.profile.Groups -import me.weishu.kernelsu.ui.component.rememberCustomDialog -import me.weishu.kernelsu.ui.util.isSepolicyValid - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun RootProfileConfig( - modifier: Modifier = Modifier, - fixedName: Boolean, - profile: Natives.Profile, - onProfileChange: (Natives.Profile) -> Unit, -) { - Column(modifier = modifier) { - if (!fixedName) { - OutlinedTextField( - label = { Text(stringResource(R.string.profile_name)) }, - value = profile.name, - onValueChange = { onProfileChange(profile.copy(name = it)) } - ) - } - - var expanded by remember { mutableStateOf(false) } - val currentNamespace = when (profile.namespace) { - Natives.Profile.Namespace.INHERITED.ordinal -> stringResource(R.string.profile_namespace_inherited) - Natives.Profile.Namespace.GLOBAL.ordinal -> stringResource(R.string.profile_namespace_global) - Natives.Profile.Namespace.INDIVIDUAL.ordinal -> stringResource(R.string.profile_namespace_individual) - else -> stringResource(R.string.profile_namespace_inherited) - } - ListItem(headlineContent = { - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { expanded = !expanded } - ) { - OutlinedTextField( - modifier = Modifier - .menuAnchor() - .fillMaxWidth(), - readOnly = true, - label = { Text(stringResource(R.string.profile_namespace)) }, - value = currentNamespace, - onValueChange = {}, - trailingIcon = { - if (expanded) Icon(Icons.Filled.ArrowDropUp, null) - else Icon(Icons.Filled.ArrowDropDown, null) - }, - ) - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - DropdownMenuItem( - text = { Text(stringResource(R.string.profile_namespace_inherited)) }, - onClick = { - onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.INHERITED.ordinal)) - expanded = false - }, - ) - DropdownMenuItem( - text = { Text(stringResource(R.string.profile_namespace_global)) }, - onClick = { - onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.GLOBAL.ordinal)) - expanded = false - }, - ) - DropdownMenuItem( - text = { Text(stringResource(R.string.profile_namespace_individual)) }, - onClick = { - onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.INDIVIDUAL.ordinal)) - expanded = false - }, - ) - } - } - }) - - UidPanel(uid = profile.uid, label = "uid", onUidChange = { - onProfileChange( - profile.copy( - uid = it, - rootUseDefault = false - ) - ) - }) - - UidPanel(uid = profile.gid, label = "gid", onUidChange = { - onProfileChange( - profile.copy( - gid = it, - rootUseDefault = false - ) - ) - }) - - val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e -> - e.mapNotNull { g -> - Groups.entries.find { it.gid == g } - } - } - GroupsPanel(selectedGroups) { - onProfileChange( - profile.copy( - groups = it.map { group -> group.gid }.ifEmpty { listOf(0) }, - rootUseDefault = false - ) - ) - } - - val selectedCaps = profile.capabilities.mapNotNull { e -> - Capabilities.entries.find { it.cap == e } - } - - CapsPanel(selectedCaps) { - onProfileChange( - profile.copy( - capabilities = it.map { cap -> cap.cap }, - rootUseDefault = false - ) - ) - } - - SELinuxPanel(profile = profile, onSELinuxChange = { domain, rules -> - onProfileChange( - profile.copy( - context = domain, - rules = rules, - rootUseDefault = false - ) - ) - }) - - } -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -fun GroupsPanel(selected: List, closeSelection: (selection: Set) -> Unit) { - val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit -> - val groups = Groups.entries.toTypedArray().sortedWith( - compareBy { if (selected.contains(it)) 0 else 1 } - .then(compareBy { - when (it) { - Groups.ROOT -> 0 - Groups.SYSTEM -> 1 - Groups.SHELL -> 2 - else -> Int.MAX_VALUE - } - }) - .then(compareBy { it.name }) - - ) - val options = groups.map { value -> - ListOption( - titleText = value.display, - subtitleText = value.desc, - selected = selected.contains(value), - ) - } - - val selection = HashSet(selected) - ListDialog( - state = rememberUseCaseState(visible = true, onFinishedRequest = { - closeSelection(selection) - }, onCloseRequest = { - dismiss() - }), - header = Header.Default( - title = stringResource(R.string.profile_groups), - ), - selection = ListSelection.Multiple( - showCheckBoxes = true, - options = options, - maxChoices = 32, // Kernel only supports 32 groups at most - ) { indecies, _ -> - // Handle selection - selection.clear() - indecies.forEach { index -> - val group = groups[index] - selection.add(group) - } - } - ) - } - - OutlinedCard(modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - .clickable { - selectGroupsDialog.show() - }) { - - Column(modifier = Modifier.padding(16.dp)) { - Text(stringResource(R.string.profile_groups)) - FlowRow { - selected.forEach { group -> - AssistChip( - modifier = Modifier.padding(3.dp), - onClick = { /*TODO*/ }, - label = { Text(group.display) }) - } - } - } - - } -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -fun CapsPanel( - selected: Collection, - closeSelection: (selection: Set) -> Unit -) { - val selectCapabilitiesDialog = rememberCustomDialog { dismiss -> - val caps = Capabilities.entries.toTypedArray().sortedWith( - compareBy { if (selected.contains(it)) 0 else 1 } - .then(compareBy { it.name }) - ) - val options = caps.map { value -> - ListOption( - titleText = value.display, - subtitleText = value.desc, - selected = selected.contains(value), - ) - } - - val selection = HashSet(selected) - ListDialog( - state = rememberUseCaseState(visible = true, onFinishedRequest = { - closeSelection(selection) - }, onCloseRequest = { - dismiss() - }), - header = Header.Default( - title = stringResource(R.string.profile_capabilities), - ), - selection = ListSelection.Multiple( - showCheckBoxes = true, - options = options - ) { indecies, _ -> - // Handle selection - selection.clear() - indecies.forEach { index -> - val group = caps[index] - selection.add(group) - } - } - ) - } - - OutlinedCard(modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - .clickable { - selectCapabilitiesDialog.show() - }) { - - Column(modifier = Modifier.padding(16.dp)) { - Text(stringResource(R.string.profile_capabilities)) - FlowRow { - selected.forEach { group -> - AssistChip( - modifier = Modifier.padding(3.dp), - onClick = { /*TODO*/ }, - label = { Text(group.display) }) - } - } - } - - } -} - -@Composable -private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) { - - ListItem(headlineContent = { - var isError by remember { - mutableStateOf(false) - } - var lastValidUid by remember { - mutableStateOf(uid) - } - - val keyboardController = LocalSoftwareKeyboardController.current - OutlinedTextField( - modifier = Modifier.fillMaxWidth(), - label = { Text(label) }, - value = uid.toString(), - isError = isError, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Number, - imeAction = ImeAction.Done - ), - keyboardActions = KeyboardActions(onDone = { - keyboardController?.hide() - }), - onValueChange = { - if (it.isEmpty()) { - onUidChange(0) - return@OutlinedTextField - } - val valid = isTextValidUid(it) - - val targetUid = if (valid) it.toInt() else lastValidUid - if (valid) { - lastValidUid = it.toInt() - } - - onUidChange(targetUid) - - isError = !valid - } - ) - }) -} - -@Composable -private fun SELinuxPanel( - profile: Natives.Profile, - onSELinuxChange: (domain: String, rules: String) -> Unit -) { - val editSELinuxDialog = rememberCustomDialog { dismiss -> - var domain by remember { mutableStateOf(profile.context) } - var rules by remember { mutableStateOf(profile.rules) } - - val inputOptions = listOf( - InputTextField( - text = domain, - header = InputHeader( - title = stringResource(id = R.string.profile_selinux_domain), - ), - type = InputTextFieldType.OUTLINED, - required = true, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Ascii, - imeAction = ImeAction.Next - ), - resultListener = { - domain = it ?: "" - }, - validationListener = { value -> - // value can be a-zA-Z0-9_ - val regex = Regex("^[a-z_]+:[a-z0-9_]+:[a-z0-9_]+(:[a-z0-9_]+)?$") - if (value?.matches(regex) == true) ValidationResult.Valid - else ValidationResult.Invalid("Domain must be in the format of \"user:role:type:level\"") - } - ), - InputTextField( - text = rules, - header = InputHeader( - title = stringResource(id = R.string.profile_selinux_rules), - ), - type = InputTextFieldType.OUTLINED, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Ascii, - ), - singleLine = false, - resultListener = { - rules = it ?: "" - }, - validationListener = { value -> - if (isSepolicyValid(value)) ValidationResult.Valid - else ValidationResult.Invalid("SELinux rules is invalid!") - } - ) - ) - - InputDialog( - state = rememberUseCaseState(visible = true, - onFinishedRequest = { - onSELinuxChange(domain, rules) - }, - onCloseRequest = { - dismiss() - }), - header = Header.Default( - title = stringResource(R.string.profile_selinux_context), - ), - selection = InputSelection( - input = inputOptions, - onPositiveClick = { result -> - // Handle selection - }, - ) - ) - } - - ListItem(headlineContent = { - OutlinedTextField( - modifier = Modifier - .fillMaxWidth() - .clickable { - editSELinuxDialog.show() - }, - enabled = false, - colors = OutlinedTextFieldDefaults.colors( - disabledTextColor = MaterialTheme.colorScheme.onSurface, - disabledBorderColor = MaterialTheme.colorScheme.outline, - disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant, - disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant - ), - label = { Text(text = stringResource(R.string.profile_selinux_context)) }, - value = profile.context, - onValueChange = { }, - ) - }) -} - -@Preview -@Composable -private fun RootProfileConfigPreview() { - var profile by remember { mutableStateOf(Natives.Profile("")) } - RootProfileConfig(fixedName = true, profile = profile) { - profile = it - } -} - -private fun isTextValidUid(text: String): Boolean { - return text.isNotEmpty() && text.isDigitsOnly() && text.toInt() >= 0 && text.toInt() <= Int.MAX_VALUE -} 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 deleted file mode 100644 index d09a2343..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt +++ /dev/null @@ -1,116 +0,0 @@ -package me.weishu.kernelsu.ui.component.profile - -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ReadMore -import androidx.compose.material.icons.filled.ArrowDropDown -import androidx.compose.material.icons.filled.ArrowDropUp -import androidx.compose.material.icons.filled.Create -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.R -import me.weishu.kernelsu.ui.util.listAppProfileTemplates -import me.weishu.kernelsu.ui.util.setSepolicy -import me.weishu.kernelsu.ui.viewmodel.getTemplateInfoById - -/** - * @author weishu - * @date 2023/10/21. - */ -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun TemplateConfig( - profile: Natives.Profile, - onViewTemplate: (id: String) -> Unit = {}, - onManageTemplate: () -> Unit = {}, - onProfileChange: (Natives.Profile) -> Unit -) { - var expanded by remember { mutableStateOf(false) } - var template by rememberSaveable { - mutableStateOf(profile.rootTemplate ?: "") - } - val profileTemplates = listAppProfileTemplates() - val noTemplates = profileTemplates.isEmpty() - - ListItem(headlineContent = { - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { expanded = it }, - ) { - OutlinedTextField( - modifier = Modifier - .menuAnchor() - .fillMaxWidth(), - readOnly = true, - label = { Text(stringResource(R.string.profile_template)) }, - value = template.ifEmpty { "None" }, - onValueChange = {}, - trailingIcon = { - if (noTemplates) { - IconButton( - onClick = onManageTemplate - ) { - Icon(Icons.Filled.Create, null) - } - } else if (expanded) Icon(Icons.Filled.ArrowDropUp, null) - else Icon(Icons.Filled.ArrowDropDown, null) - }, - ) - if (profileTemplates.isEmpty()) { - return@ExposedDropdownMenuBox - } - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - profileTemplates.forEach { tid -> - val templateInfo = - getTemplateInfoById(tid) ?: return@forEach - DropdownMenuItem( - text = { Text(tid) }, - onClick = { - template = tid - if (setSepolicy(tid, templateInfo.rules.joinToString("\n"))) { - onProfileChange( - profile.copy( - rootTemplate = tid, - rootUseDefault = false, - uid = templateInfo.uid, - gid = templateInfo.gid, - groups = templateInfo.groups, - capabilities = templateInfo.capabilities, - context = templateInfo.context, - namespace = templateInfo.namespace, - ) - ) - } - expanded = false - }, - trailingIcon = { - IconButton(onClick = { - onViewTemplate(tid) - }) { - Icon(Icons.AutoMirrored.Filled.ReadMore, null) - } - } - ) - } - } - } - }) -} \ No newline at end of file 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 deleted file mode 100644 index ca53388f..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt +++ /dev/null @@ -1,362 +0,0 @@ -package me.weishu.kernelsu.ui.screen - -import androidx.annotation.StringRes -import androidx.compose.animation.Crossfade -import androidx.compose.foundation.gestures.detectTapGestures -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.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -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.AccountCircle -import androidx.compose.material.icons.filled.Android -import androidx.compose.material.icons.filled.Security -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilterChip -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -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.geometry.Offset -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.DpOffset -import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import coil.request.ImageRequest -import com.ramcosta.composedestinations.annotation.Destination -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.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 -import me.weishu.kernelsu.ui.util.launchApp -import me.weishu.kernelsu.ui.util.restartApp -import me.weishu.kernelsu.ui.util.setSepolicy -import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel -import me.weishu.kernelsu.ui.viewmodel.getTemplateInfoById - -/** - * @author weishu - * @date 2023/5/16. - */ -@Destination -@Composable -fun AppProfileScreen( - navigator: DestinationsNavigator, - appInfo: SuperUserViewModel.AppInfo, -) { - val context = LocalContext.current - val snackbarHost = LocalSnackbarHost.current - 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 packageName = appInfo.packageName - val initialProfile = Natives.getAppProfile(packageName, appInfo.uid) - if (initialProfile.allowSu) { - initialProfile.rules = getSepolicy(packageName) - } - var profile by rememberSaveable { - mutableStateOf(initialProfile) - } - - Scaffold( - topBar = { TopBar { navigator.popBackStack() } }, - ) { paddingValues -> - AppProfileInner( - modifier = Modifier - .padding(paddingValues) - .verticalScroll(rememberScrollState()), - packageName = appInfo.packageName, - appLabel = appInfo.label, - appIcon = { - AsyncImage( - model = ImageRequest.Builder(context).data(appInfo.packageInfo).crossfade(true) - .build(), - contentDescription = appInfo.label, - modifier = Modifier - .padding(4.dp) - .width(48.dp) - .height(48.dp) - ) - }, - profile = profile, - onViewTemplate = { - getTemplateInfoById(it)?.let { info -> - navigator.navigate(TemplateEditorScreenDestination(info)) - } - }, - onManageTemplate = { - navigator.navigate(AppProfileTemplateScreenDestination()) - }, - onProfileChange = { - scope.launch { - if (it.allowSu && !it.rootUseDefault && it.rules.isNotEmpty()) { - if (!setSepolicy(profile.name, it.rules)) { - snackbarHost.showSnackbar(failToUpdateSepolicy) - return@launch - } - } - if (!Natives.setAppProfile(it)) { - snackbarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid)) - } else { - profile = it - } - } - }, - ) - } -} - -@Composable -private fun AppProfileInner( - modifier: Modifier = Modifier, - packageName: String, - appLabel: String, - appIcon: @Composable () -> Unit, - profile: Natives.Profile, - onViewTemplate: (id: String) -> Unit = {}, - onManageTemplate: () -> Unit = {}, - onProfileChange: (Natives.Profile) -> Unit, -) { - val isRootGranted = profile.allowSu - - Column(modifier = modifier) { - AppMenuBox(packageName) { - ListItem( - headlineContent = { Text(appLabel) }, - supportingContent = { Text(packageName) }, - leadingContent = appIcon, - ) - } - - SwitchItem( - icon = Icons.Filled.Security, - title = stringResource(id = R.string.superuser), - checked = isRootGranted, - onCheckedChange = { onProfileChange(profile.copy(allowSu = it)) }, - ) - - Crossfade(targetState = isRootGranted, label = "") { current -> - Column { - if (current) { - val initialMode = if (profile.rootUseDefault) { - Mode.Default - } else if (profile.rootTemplate != null) { - Mode.Template - } else { - Mode.Custom - } - var mode by rememberSaveable { - mutableStateOf(initialMode) - } - ProfileBox(mode, true) { - // template mode shouldn't change profile here! - if (it == Mode.Default || it == Mode.Custom) { - onProfileChange(profile.copy(rootUseDefault = it == Mode.Default)) - } - mode = it - } - Crossfade(targetState = mode, label = "") { currentMode -> - if (currentMode == Mode.Template) { - TemplateConfig( - profile = profile, - onViewTemplate = onViewTemplate, - onManageTemplate = onManageTemplate, - onProfileChange = onProfileChange - ) - } else if (mode == Mode.Custom) { - RootProfileConfig( - fixedName = true, - profile = profile, - onProfileChange = onProfileChange - ) - } - } - } else { - val mode = if (profile.nonRootUseDefault) Mode.Default else Mode.Custom - ProfileBox(mode, false) { - onProfileChange(profile.copy(nonRootUseDefault = (it == Mode.Default))) - } - Crossfade(targetState = mode, label = "") { currentMode -> - val modifyEnabled = currentMode == Mode.Custom - AppProfileConfig( - fixedName = true, - profile = profile, - enabled = modifyEnabled, - onProfileChange = onProfileChange - ) - } - } - } - } - } -} - -private enum class Mode(@StringRes private val res: Int) { - Default(R.string.profile_default), Template(R.string.profile_template), Custom(R.string.profile_custom); - - val text: String - @Composable get() = stringResource(res) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar(onBack: () -> Unit) { - TopAppBar( - title = { - Text(stringResource(R.string.profile)) - }, - navigationIcon = { - IconButton( - onClick = onBack - ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) } - }, - ) -} - -@Composable -private fun ProfileBox( - mode: Mode, - hasTemplate: Boolean, - onModeChange: (Mode) -> Unit, -) { - ListItem( - headlineContent = { Text(stringResource(R.string.profile)) }, - supportingContent = { Text(mode.text) }, - leadingContent = { Icon(Icons.Filled.AccountCircle, null) }, - ) - HorizontalDivider(thickness = Dp.Hairline) - ListItem(headlineContent = { - Row( - modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly - ) { - FilterChip( - selected = mode == Mode.Default, - label = { Text(stringResource(R.string.profile_default)) }, - onClick = { onModeChange(Mode.Default) }, - ) - if (hasTemplate) { - FilterChip( - selected = mode == Mode.Template, - label = { Text(stringResource(R.string.profile_template)) }, - onClick = { onModeChange(Mode.Template) }, - ) - } - FilterChip( - selected = mode == Mode.Custom, - label = { Text(stringResource(R.string.profile_custom)) }, - onClick = { onModeChange(Mode.Custom) }, - ) - } - }) -} - -@Composable -private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) { - - var expanded by remember { mutableStateOf(false) } - var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) } - val density = LocalDensity.current - - BoxWithConstraints( - Modifier - .fillMaxSize() - .pointerInput(Unit) { - detectTapGestures { - touchPoint = it - expanded = true - } - }) { - - content() - - val (offsetX, offsetY) = with(density) { - (touchPoint.x.toDp()) to (touchPoint.y.toDp()) - } - - DropdownMenu( - expanded = expanded, - offset = DpOffset(offsetX, -offsetY), - onDismissRequest = { - expanded = false - }, - ) { - DropdownMenuItem( - text = { Text(stringResource(id = R.string.launch_app)) }, - onClick = { - expanded = false - launchApp(packageName) - }, - ) - DropdownMenuItem( - text = { Text(stringResource(id = R.string.force_stop_app)) }, - onClick = { - expanded = false - forceStopApp(packageName) - }, - ) - DropdownMenuItem( - text = { Text(stringResource(id = R.string.restart_app)) }, - onClick = { - expanded = false - restartApp(packageName) - }, - ) - } - } - - -} - -@Preview -@Composable -private fun AppProfilePreview() { - var profile by remember { mutableStateOf(Natives.Profile("")) } - AppProfileInner( - packageName = "icu.nullptr.test", - appLabel = "Test", - appIcon = { Icon(Icons.Filled.Android, null) }, - profile = profile, - onProfileChange = { - profile = it - }, - ) -} - 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 deleted file mode 100644 index 9345ced5..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt +++ /dev/null @@ -1,24 +0,0 @@ -package me.weishu.kernelsu.ui.screen - -import androidx.annotation.StringRes -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.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, - @StringRes val label: Int, - val iconSelected: ImageVector, - val iconNotSelected: ImageVector, - val rootRequired: Boolean, -) { - Home(HomeScreenDestination, R.string.home, Icons.Filled.Home, Icons.Outlined.Home, false), - SuperUser(SuperUserScreenDestination, R.string.superuser, Icons.Filled.Security, Icons.Outlined.Security, true), - Module(ModuleScreenDestination, R.string.module, Icons.Filled.Apps, Icons.Outlined.Apps, true) -} 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 deleted file mode 100644 index 1e3d48fd..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt +++ /dev/null @@ -1,238 +0,0 @@ -package me.weishu.kernelsu.ui.screen - -import android.net.Uri -import android.os.Environment -import android.os.Parcelable -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.Refresh -import androidx.compose.material.icons.filled.Save -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExtendedFloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -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.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.ramcosta.composedestinations.annotation.Destination -import com.ramcosta.composedestinations.navigation.DestinationsNavigator -import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import kotlinx.parcelize.Parcelize -import me.weishu.kernelsu.R -import me.weishu.kernelsu.ui.component.KeyEventBlocker -import me.weishu.kernelsu.ui.util.LkmSelection -import me.weishu.kernelsu.ui.util.LocalSnackbarHost -import me.weishu.kernelsu.ui.util.flashModule -import me.weishu.kernelsu.ui.util.installBoot -import me.weishu.kernelsu.ui.util.reboot -import me.weishu.kernelsu.ui.util.restoreBoot -import me.weishu.kernelsu.ui.util.uninstallPermanently -import java.io.File -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale - -enum class FlashingStatus { - FLASHING, - SUCCESS, - FAILED -} - -/** - * @author weishu - * @date 2023/1/1. - */ -@Composable -@Destination -fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { - - var text by rememberSaveable { mutableStateOf("") } - val logContent = rememberSaveable { StringBuilder() } - var showFloatAction by rememberSaveable { mutableStateOf(false) } - - val snackBarHost = LocalSnackbarHost.current - val scope = rememberCoroutineScope() - val scrollState = rememberScrollState() - var flashing by rememberSaveable { - mutableStateOf(FlashingStatus.FLASHING) - } - - LaunchedEffect(Unit) { - if (text.isNotEmpty()) { - return@LaunchedEffect - } - withContext(Dispatchers.IO) { - flashIt(flashIt, onFinish = { showReboot, code -> - if (code != 0) { - text += "Error: exit code = $code.\nPlease save and check the log.\n" - } - if (showReboot) { - text += "\n\n\n" - showFloatAction = true - } - flashing = if (code == 0) FlashingStatus.SUCCESS else FlashingStatus.FAILED - }, onStdout = { - text += "$it\n" - logContent.append(it).append("\n") - }, onStderr = { - logContent.append(it).append("\n") - }) - } - } - - Scaffold( - topBar = { - TopBar( - flashing, - 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_install_log_${date}.log" - ) - file.writeText(logContent.toString()) - snackBarHost.showSnackbar("Log saved to ${file.absolutePath}") - } - } - ) - }, - floatingActionButton = { - if (showFloatAction) { - val reboot = stringResource(id = R.string.reboot) - ExtendedFloatingActionButton( - onClick = { - scope.launch { - withContext(Dispatchers.IO) { - reboot() - } - } - }, - icon = { Icon(Icons.Filled.Refresh, reboot) }, - text = { Text(text = reboot) }, - ) - } - - } - ) { 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, - ) - } - } -} - -@Parcelize -sealed class FlashIt : Parcelable { - data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean) : - FlashIt() - - data class FlashModule(val uri: Uri) : FlashIt() - - data object FlashRestore : FlashIt() - - data object FlashUninstall : FlashIt() -} - -fun flashIt( - flashIt: FlashIt, onFinish: (Boolean, Int) -> Unit, - onStdout: (String) -> Unit, - onStderr: (String) -> Unit -) { - when (flashIt) { - is FlashIt.FlashBoot -> installBoot( - flashIt.boot, - flashIt.lkm, - flashIt.ota, - onFinish, - onStdout, - onStderr - ) - - is FlashIt.FlashModule -> flashModule(flashIt.uri, onFinish, onStdout, onStderr) - - FlashIt.FlashRestore -> restoreBoot(onFinish, onStdout, onStderr) - - FlashIt.FlashUninstall -> uninstallPermanently(onFinish, onStdout, onStderr) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar(status: FlashingStatus, onBack: () -> Unit = {}, onSave: () -> Unit = {}) { - TopAppBar( - title = { - Text( - stringResource( - when (status) { - FlashingStatus.FLASHING -> R.string.flashing - FlashingStatus.SUCCESS -> R.string.flash_success - FlashingStatus.FAILED -> R.string.flash_failed - } - ) - ) - }, - navigationIcon = { - IconButton( - onClick = onBack - ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) } - }, - actions = { - IconButton(onClick = onSave) { - Icon( - imageVector = Icons.Filled.Save, - contentDescription = "Localized description" - ) - } - } - ) -} - -@Preview -@Composable -fun InstallPreview() { - InstallScreen(EmptyDestinationsNavigator) -} \ No newline at end of file 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 deleted file mode 100644 index 6ecf53a8..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt +++ /dev/null @@ -1,444 +0,0 @@ -package me.weishu.kernelsu.ui.screen - -import android.content.Context -import android.os.Build -import android.os.PowerManager -import android.system.Os -import androidx.annotation.StringRes -import androidx.compose.animation.* -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Archive -import androidx.compose.material.icons.filled.Refresh -import androidx.compose.material.icons.filled.Settings -import androidx.compose.material.icons.outlined.Block -import androidx.compose.material.icons.outlined.CheckCircle -import androidx.compose.material.icons.outlined.Warning -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -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 com.ramcosta.composedestinations.annotation.Destination -import com.ramcosta.composedestinations.annotation.RootNavGraph -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 -@Composable -fun HomeScreen(navigator: DestinationsNavigator) { - val kernelVersion = getKernelVersion() - - Scaffold(topBar = { - TopBar(kernelVersion, onSettingsClick = { - navigator.navigate(SettingScreenDestination) - }, onInstallClick = { - navigator.navigate(InstallScreenDestination) - }) - }) { innerPadding -> - Column( - modifier = Modifier - .padding(innerPadding) - .padding(horizontal = 16.dp) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - val isManager = Natives.becomeManager(ksuApp.packageName) - SideEffect { - if (isManager) install() - } - val ksuVersion = if (isManager) Natives.version else null - val lkmMode = ksuVersion?.let { - if (it >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && kernelVersion.isGKI()) Natives.isLkmMode else null - } - - StatusCard(kernelVersion, ksuVersion, lkmMode) { - navigator.navigate(InstallScreenDestination) - } - if (isManager && Natives.requireNewKernel()) { - WarningCard( - stringResource(id = R.string.require_kernel_version).format( - ksuVersion, Natives.MINIMAL_SUPPORTED_KERNEL - ) - ) - } - if (ksuVersion != null && !rootAvailable()) { - WarningCard( - stringResource(id = R.string.grant_root_failed) - ) - } - val checkUpdate = - LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE) - .getBoolean("check_update", true) - if (checkUpdate) { - UpdateCard() - } - InfoCard() - DonateCard() - LearnMoreCard() - Spacer(Modifier) - } - } -} - -@Composable -fun UpdateCard() { - val context = LocalContext.current - val latestVersionInfo = LatestVersionInfo() - val newVersion by produceState(initialValue = latestVersionInfo) { - value = withContext(Dispatchers.IO){ - checkNewVersion() - } - } - - - val currentVersionCode = getManagerVersion(context).second - val newVersionCode = newVersion.versionCode - val newVersionUrl = newVersion.downloadUrl - val changelog = newVersion.changelog - - val uriHandler = LocalUriHandler.current - val title = stringResource(id = R.string.module_changelog) - val updateText = stringResource(id = R.string.module_update) - - AnimatedVisibility( - visible = newVersionCode > currentVersionCode, - enter = fadeIn() + expandVertically(), - exit = shrinkVertically() + fadeOut() - ) { - val updateDialog = rememberConfirmDialog(onConfirm = { uriHandler.openUri(newVersionUrl) }) - WarningCard( - message = stringResource(id = R.string.new_version_available).format(newVersionCode), - MaterialTheme.colorScheme.outlineVariant - ) { - if (changelog.isEmpty()) { - uriHandler.openUri(newVersionUrl) - } else { - updateDialog.showConfirm( - title = title, - content = changelog, - markdown = true, - confirm = updateText - ) - } - } - } -} - -@Composable -fun RebootDropdownItem(@StringRes id: Int, reason: String = "") { - DropdownMenuItem(text = { - Text(stringResource(id)) - }, onClick = { - reboot(reason) - }) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar( - kernelVersion: KernelVersion, - onInstallClick: () -> Unit, - onSettingsClick: () -> Unit -) { - 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 - }) { - - 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") - } - 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) - ) - } - }) -} - -@Composable -private fun StatusCard( - kernelVersion: KernelVersion, - ksuVersion: Int?, - lkmMode: Boolean?, - onClickInstall: () -> Unit = {} -) { - ElevatedCard( - colors = CardDefaults.elevatedCardColors(containerColor = run { - if (ksuVersion != null) MaterialTheme.colorScheme.secondaryContainer - else MaterialTheme.colorScheme.errorContainer - }) - ) { - Row(modifier = Modifier - .fillMaxWidth() - .clickable { - if (kernelVersion.isGKI()) { - onClickInstall() - } - } - .padding(24.dp), verticalAlignment = Alignment.CenterVertically) { - when { - ksuVersion != null -> { - val safeMode = when { - Natives.isSafeMode -> " [${stringResource(id = R.string.safe_mode)}]" - else -> "" - } - - val workingMode = when (lkmMode) { - null -> "" - true -> " " - else -> " " - } - - val workingText = - "${stringResource(id = R.string.home_working)}$workingMode$safeMode" - - Icon(Icons.Outlined.CheckCircle, stringResource(R.string.home_working)) - Column(Modifier.padding(start = 20.dp)) { - Text( - text = workingText, - style = MaterialTheme.typography.titleMedium - ) - Spacer(Modifier.height(4.dp)) - Text( - text = stringResource(R.string.home_working_version, ksuVersion), - style = MaterialTheme.typography.bodyMedium - ) - Spacer(Modifier.height(4.dp)) - Text( - text = stringResource( - R.string.home_superuser_count, getSuperuserCount() - ), style = MaterialTheme.typography.bodyMedium - ) - Spacer(Modifier.height(4.dp)) - Text( - text = stringResource(R.string.home_module_count, getModuleCount()), - style = MaterialTheme.typography.bodyMedium - ) - } - } - - kernelVersion.isGKI() -> { - Icon(Icons.Outlined.Warning, stringResource(R.string.home_not_installed)) - Column(Modifier.padding(start = 20.dp)) { - Text( - text = stringResource(R.string.home_not_installed), - style = MaterialTheme.typography.titleMedium - ) - Spacer(Modifier.height(4.dp)) - Text( - text = stringResource(R.string.home_click_to_install), - style = MaterialTheme.typography.bodyMedium - ) - } - } - - else -> { - Icon(Icons.Outlined.Block, stringResource(R.string.home_unsupported)) - Column(Modifier.padding(start = 20.dp)) { - Text( - text = stringResource(R.string.home_unsupported), - style = MaterialTheme.typography.titleMedium - ) - Spacer(Modifier.height(4.dp)) - Text( - text = stringResource(R.string.home_unsupported_reason), - style = MaterialTheme.typography.bodyMedium - ) - } - } - } - } - } -} - -@Composable -fun WarningCard( - message: String, color: Color = MaterialTheme.colorScheme.error, onClick: (() -> Unit)? = null -) { - ElevatedCard( - colors = CardDefaults.elevatedCardColors( - containerColor = color - ) - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .then(onClick?.let { Modifier.clickable { it() } } ?: Modifier) - .padding(24.dp) - ) { - Text( - text = message, style = MaterialTheme.typography.bodyMedium - ) - } - } -} - -@Composable -fun LearnMoreCard() { - val uriHandler = LocalUriHandler.current - val url = stringResource(R.string.home_learn_kernelsu_url) - - ElevatedCard { - - Row(modifier = Modifier - .fillMaxWidth() - .clickable { - uriHandler.openUri(url) - } - .padding(24.dp), verticalAlignment = Alignment.CenterVertically) { - Column { - Text( - text = stringResource(R.string.home_learn_kernelsu), - style = MaterialTheme.typography.titleSmall - ) - Spacer(Modifier.height(4.dp)) - Text( - text = stringResource(R.string.home_click_to_learn_kernelsu), - style = MaterialTheme.typography.bodyMedium - ) - } - } - } -} - -@Composable -fun DonateCard() { - val uriHandler = LocalUriHandler.current - - ElevatedCard { - - Row(modifier = Modifier - .fillMaxWidth() - .clickable { - uriHandler.openUri("https://patreon.com/weishu") - } - .padding(24.dp), verticalAlignment = Alignment.CenterVertically) { - Column { - Text( - text = stringResource(R.string.home_support_title), - style = MaterialTheme.typography.titleSmall - ) - Spacer(Modifier.height(4.dp)) - Text( - text = stringResource(R.string.home_support_content), - style = MaterialTheme.typography.bodyMedium - ) - } - } - } -} - -@Composable -private fun InfoCard() { - val context = LocalContext.current - - ElevatedCard { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp, top = 24.dp, end = 24.dp, bottom = 16.dp) - ) { - val contents = StringBuilder() - val uname = Os.uname() - - @Composable - fun InfoCardItem(label: String, content: String) { - contents.appendLine(label).appendLine(content).appendLine() - Text(text = label, style = MaterialTheme.typography.bodyLarge) - Text(text = content, style = MaterialTheme.typography.bodyMedium) - } - - InfoCardItem(stringResource(R.string.home_kernel), uname.release) - - Spacer(Modifier.height(16.dp)) - val managerVersion = getManagerVersion(context) - InfoCardItem( - stringResource(R.string.home_manager_version), - "${managerVersion.first} (${managerVersion.second})" - ) - - Spacer(Modifier.height(16.dp)) - InfoCardItem(stringResource(R.string.home_fingerprint), Build.FINGERPRINT) - - Spacer(Modifier.height(16.dp)) - InfoCardItem(stringResource(R.string.home_selinux_status), getSELinuxStatus()) - } - } -} - -fun getManagerVersion(context: Context): Pair { - val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) - return Pair(packageInfo.versionName, packageInfo.versionCode) -} - -@Preview -@Composable -private fun StatusCardPreview() { - Column { - StatusCard(KernelVersion(5, 10, 101), 1, null) - StatusCard(KernelVersion(5, 10, 101), 20000, true) - StatusCard(KernelVersion(5, 10, 101), null, true) - StatusCard(KernelVersion(4, 10, 101), null, false) - } -} - -@Preview -@Composable -private fun WarningCardPreview() { - Column { - WarningCard(message = "Warning message") - WarningCard( - message = "Warning message ", - 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 deleted file mode 100644 index 71b5c975..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt +++ /dev/null @@ -1,311 +0,0 @@ -package me.weishu.kernelsu.ui.screen - -import android.app.Activity -import android.content.Intent -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.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.FileUpload -import androidx.compose.material3.Button -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.maxkeppeker.sheets.core.models.base.Header -import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState -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.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 -import me.weishu.kernelsu.ui.util.isAbDevice -import me.weishu.kernelsu.ui.util.isInitBoot -import me.weishu.kernelsu.ui.util.rootAvailable - -/** - * @author weishu - * @date 2024/3/12. - */ -@Destination -@Composable -fun InstallScreen(navigator: DestinationsNavigator) { - var installMethod by remember { - mutableStateOf(null) - } - - var lkmSelection by remember { - mutableStateOf(LkmSelection.KmiNone) - } - - val onInstall = { - installMethod?.let { method -> - val flashIt = FlashIt.FlashBoot( - boot = if (method is InstallMethod.SelectFile) method.uri else null, - lkm = lkmSelection, - ota = method is InstallMethod.DirectInstallToInactiveSlot - ) - navigator.navigate(FlashScreenDestination(flashIt)) - } - } - - val currentKmi by produceState(initialValue = "") { value = getCurrentKmi() } - - val selectKmiDialog = rememberSelectKmiDialog { kmi -> - kmi?.let { - lkmSelection = LkmSelection.KmiString(it) - onInstall() - } - } - - val onClickNext = { - if (lkmSelection == LkmSelection.KmiNone && currentKmi.isBlank()) { - // no lkm file selected and cannot get current kmi - selectKmiDialog.show() - } else { - onInstall() - } - } - - val selectLkmLauncher = - rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - it.data?.data?.let { uri -> - lkmSelection = LkmSelection.LkmUri(uri) - } - } - } - - val onLkmUpload = { - selectLkmLauncher.launch(Intent(Intent.ACTION_GET_CONTENT).apply { - type = "application/octet-stream" - }) - } - - Scaffold(topBar = { - TopBar( - onBack = { navigator.popBackStack() }, onLkmUpload = onLkmUpload - ) - }) { - Column(modifier = Modifier.padding(it)) { - SelectInstallMethod { method -> - installMethod = method - } - - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - ) { - (lkmSelection as? LkmSelection.LkmUri)?.let { - Text( - stringResource( - id = R.string.selected_lkm, - it.uri.lastPathSegment ?: "(file)" - ) - ) - } - Button(modifier = Modifier.fillMaxWidth(), - enabled = installMethod != null, - onClick = { - onClickNext() - }) { - Text( - stringResource(id = R.string.install_next), - fontSize = MaterialTheme.typography.bodyMedium.fontSize - ) - } - } - } - } -} - -sealed class InstallMethod { - data class SelectFile( - val uri: Uri? = null, - @StringRes override val label: Int = R.string.select_file, - override val summary: String? - ) : InstallMethod() - - data object DirectInstall : InstallMethod() { - override val label: Int - get() = R.string.direct_install - } - - data object DirectInstallToInactiveSlot : InstallMethod() { - override val label: Int - get() = R.string.install_inactive_slot - } - - abstract val label: Int - open val summary: String? = null -} - -@Composable -private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) { - val rootAvailable = rootAvailable() - val isAbDevice = isAbDevice() - val selectFileTip = stringResource( - id = R.string.select_file_tip, if (isInitBoot()) "init_boot" else "boot" - ) - val radioOptions = - mutableListOf(InstallMethod.SelectFile(summary = selectFileTip)) - if (rootAvailable) { - radioOptions.add(InstallMethod.DirectInstall) - - if (isAbDevice) { - radioOptions.add(InstallMethod.DirectInstallToInactiveSlot) - } - } - - var selectedOption by remember { mutableStateOf(null) } - val selectImageLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult() - ) { - if (it.resultCode == Activity.RESULT_OK) { - it.data?.data?.let { uri -> - val option = InstallMethod.SelectFile(uri, summary = selectFileTip) - selectedOption = option - onSelected(option) - } - } - } - - val confirmDialog = rememberConfirmDialog(onConfirm = { - selectedOption = InstallMethod.DirectInstallToInactiveSlot - onSelected(InstallMethod.DirectInstallToInactiveSlot) - }, onDismiss = null) - val dialogTitle = stringResource(id = android.R.string.dialog_alert_title) - val dialogContent = stringResource(id = R.string.install_inactive_slot_warning) - - val onClick = { option: InstallMethod -> - - when (option) { - is InstallMethod.SelectFile -> { - selectImageLauncher.launch(Intent(Intent.ACTION_GET_CONTENT).apply { - type = "application/octet-stream" - }) - } - - is InstallMethod.DirectInstall -> { - selectedOption = option - onSelected(option) - } - - is InstallMethod.DirectInstallToInactiveSlot -> { - confirmDialog.showConfirm(dialogTitle, dialogContent) - } - } - } - - Column { - radioOptions.forEach { option -> - Row(verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .clickable { - onClick(option) - }) { - RadioButton(selected = option.javaClass == selectedOption?.javaClass, onClick = { - onClick(option) - }) - Column { - Text( - text = stringResource(id = option.label), - fontSize = MaterialTheme.typography.titleMedium.fontSize, - fontFamily = MaterialTheme.typography.titleMedium.fontFamily, - fontStyle = MaterialTheme.typography.titleMedium.fontStyle - ) - option.summary?.let { - Text( - text = it, - fontSize = MaterialTheme.typography.bodySmall.fontSize, - fontFamily = MaterialTheme.typography.bodySmall.fontFamily, - fontStyle = MaterialTheme.typography.bodySmall.fontStyle - ) - } - } - } - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle { - return rememberCustomDialog { dismiss -> - val supportedKmi by produceState(initialValue = emptyList()) { - value = getSupportedKmis() - } - val options = supportedKmi.map { value -> - ListOption( - titleText = value - ) - } - - var selection by remember { mutableStateOf(null) } - ListDialog(state = rememberUseCaseState(visible = true, onFinishedRequest = { - onSelected(selection) - }, onCloseRequest = { - dismiss() - }), header = Header.Default( - title = stringResource(R.string.select_kmi), - ), selection = ListSelection.Single( - showRadioButtons = true, - options = options, - ) { _, option -> - selection = option.titleText - }) - } -} - -@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) - } - }) -} - -@Composable -@Preview -fun SelectInstall_Preview() { - InstallScreen(EmptyDestinationsNavigator) -} \ No newline at end of file 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 deleted file mode 100644 index 9812e87e..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt +++ /dev/null @@ -1,576 +0,0 @@ -package me.weishu.kernelsu.ui.screen - -import android.app.Activity.RESULT_OK -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.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.defaultMinSize -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -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.material.icons.Icons -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.material3.Button -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.ElevatedCard -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExtendedFloatingActionButton -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -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.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -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.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextDecoration -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -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.navigation.DestinationsNavigator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import me.weishu.kernelsu.Natives -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 -import me.weishu.kernelsu.ui.util.hasMagisk -import me.weishu.kernelsu.ui.util.reboot -import me.weishu.kernelsu.ui.util.toggleModule -import me.weishu.kernelsu.ui.util.uninstallModule -import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel -import me.weishu.kernelsu.ui.webui.WebUIActivity -import okhttp3.OkHttpClient - -@Destination -@Composable -fun ModuleScreen(navigator: DestinationsNavigator) { - val viewModel = viewModel() - val context = LocalContext.current - - LaunchedEffect(Unit) { - if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) { - viewModel.fetchModuleList() - } - } - - val isSafeMode = Natives.isSafeMode - val hasMagisk = hasMagisk() - - 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 - - navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri))) - - viewModel.markNeedRefresh() - - Log.i("ModuleScreen", "select zip result: ${it.data}") - } - - 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 -> - - when { - hasMagisk -> { - Box( - modifier = Modifier - .fillMaxSize() - .padding(24.dp), - contentAlignment = Alignment.Center - ) { - Text( - stringResource(R.string.module_magisk_conflict), - textAlign = TextAlign.Center, - ) - } - } - - else -> { - ModuleList( - viewModel = viewModel, modifier = Modifier - .padding(innerPadding) - .fillMaxSize(), - onInstallModule = - { - navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it))) - }, 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) - ) - } - }) - } - } - } -} - -@OptIn(ExperimentalMaterialApi::class) -@Composable -private fun ModuleList( - viewModel: ModuleViewModel, - modifier: Modifier = Modifier, - onInstallModule: (Uri) -> Unit, - onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit -) { - 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 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() - - suspend fun onModuleUpdate( - module: ModuleViewModel.ModuleInfo, - changelogUrl: String, - downloadUrl: String, - fileName: String - ) { - val changelogResult = loadingDialog.withLoading { - withContext(Dispatchers.IO) { - runCatching { - OkHttpClient().newCall( - okhttp3.Request.Builder().url(changelogUrl).build() - ).execute().body!!.string() - } - } - } - - val showToast: suspend (String) -> Unit = { msg -> - withContext(Dispatchers.Main) { - Toast.makeText( - context, - msg, - Toast.LENGTH_SHORT - ).show() - } - } - - val changelog = changelogResult.getOrElse { - showToast(fetchChangeLogFailed.format(it.message)) - return - }.ifBlank { - showToast(fetchChangeLogFailed.format(module.name)) - return - } - - // changelog is not empty, show it and wait for confirm - val confirmResult = confirmDialog.awaitConfirm( - changelogText, - content = changelog, - markdown = true, - confirm = updateText, - ) - - if (confirmResult != ConfirmResult.Confirmed) { - return - } - - showToast(startDownloadingText.format(module.name)) - - val downloading = downloadingText.format(module.name) - withContext(Dispatchers.IO) { - download( - context, - downloadUrl, - fileName, - downloading, - onDownloaded = onInstallModule, - onDownloading = { - launch(Dispatchers.Main) { - Toast.makeText(context, downloading, Toast.LENGTH_SHORT).show() - } - } - ) - } - } - - suspend fun onModuleUninstall(module: ModuleViewModel.ModuleInfo) { - val confirmResult = confirmDialog.awaitConfirm( - moduleStr, - content = moduleUninstallConfirm.format(module.name), - confirm = uninstall, - dismiss = cancel - ) - if (confirmResult != ConfirmResult.Confirmed) { - return - } - - val success = loadingDialog.withLoading { - withContext(Dispatchers.IO) { - uninstallModule(module.id) - } - } - - if (success) { - viewModel.fetchModuleList() - } - val message = if (success) { - successUninstall.format(module.name) - } else { - failedUninstall.format(module.name) - } - val actionLabel = if (success) { - reboot - } else { - null - } - val result = snackBarHost.showSnackbar(message, actionLabel = actionLabel) - if (result == SnackbarResult.ActionPerformed) { - reboot() - } - } - - val refreshState = rememberPullRefreshState(refreshing = viewModel.isRefreshing, - onRefresh = { viewModel.fetchModuleList() }) - Box(modifier.pullRefresh(refreshState)) { - val context = LocalContext.current - - LazyColumn( - modifier = Modifier.fillMaxSize(), - 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 */ - ) - }, - ) { - when { - !viewModel.isOverlayAvailable -> { - item { - Box( - modifier = Modifier.fillParentMaxSize(), - contentAlignment = Alignment.Center - ) { - Text( - stringResource(R.string.module_overlay_fs_not_available), - textAlign = TextAlign.Center - ) - } - } - } - - viewModel.moduleList.isEmpty() -> { - item { - Box( - modifier = Modifier.fillParentMaxSize(), - contentAlignment = Alignment.Center - ) { - Text( - stringResource(R.string.module_empty), - textAlign = TextAlign.Center - ) - } - } - } - - else -> { - items(viewModel.moduleList) { module -> - var isChecked by rememberSaveable(module) { mutableStateOf(module.enabled) } - val scope = rememberCoroutineScope() - val updatedModule by produceState(initialValue = Triple("", "", "")) { - scope.launch(Dispatchers.IO) { - value = viewModel.checkUpdate(module) - } - } - - ModuleItem(module, isChecked, 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( - rebootToApply, actionLabel = reboot - ) - if (result == SnackbarResult.ActionPerformed) { - reboot() - } - } else { - val message = if (isChecked) failedDisable else failedEnable - snackBarHost.showSnackbar(message.format(module.name)) - } - } - }, 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)) - } - } - } - } - - 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( - module: ModuleViewModel.ModuleInfo, - isChecked: Boolean, - updateUrl: String, - onUninstall: (ModuleViewModel.ModuleInfo) -> Unit, - onCheckChanged: (Boolean) -> Unit, - onUpdate: (ModuleViewModel.ModuleInfo) -> Unit, - onClick: (ModuleViewModel.ModuleInfo) -> Unit -) { - ElevatedCard( - modifier = Modifier.fillMaxWidth(), - colors = CardDefaults.elevatedCardColors(containerColor = MaterialTheme.colorScheme.surface) - ) { - - val textDecoration = if (!module.remove) null else TextDecoration.LineThrough - - Column(modifier = Modifier.clickable { onClick(module) }.padding(24.dp, 16.dp, 24.dp, 0.dp)) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - ) { - val moduleVersion = stringResource(id = R.string.module_version) - val moduleAuthor = stringResource(id = R.string.module_author) - - Column(modifier = Modifier.fillMaxWidth(0.8f)) { - Text( - text = module.name, - fontSize = MaterialTheme.typography.titleMedium.fontSize, - fontWeight = FontWeight.SemiBold, - lineHeight = MaterialTheme.typography.bodySmall.lineHeight, - fontFamily = MaterialTheme.typography.titleMedium.fontFamily, - textDecoration = textDecoration, - ) - - Text( - text = "$moduleVersion: ${module.version}", - fontSize = MaterialTheme.typography.bodySmall.fontSize, - lineHeight = MaterialTheme.typography.bodySmall.lineHeight, - fontFamily = MaterialTheme.typography.bodySmall.fontFamily, - textDecoration = textDecoration - ) - - Text( - text = "$moduleAuthor: ${module.author}", - fontSize = MaterialTheme.typography.bodySmall.fontSize, - lineHeight = MaterialTheme.typography.bodySmall.lineHeight, - fontFamily = MaterialTheme.typography.bodySmall.fontFamily, - textDecoration = textDecoration - ) - } - - Spacer(modifier = Modifier.weight(1f)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.End, - ) { - Switch( - enabled = !module.update, - checked = isChecked, - onCheckedChange = onCheckChanged - ) - } - } - - Spacer(modifier = Modifier.height(12.dp)) - - Text( - text = module.description, - fontSize = MaterialTheme.typography.bodySmall.fontSize, - fontFamily = MaterialTheme.typography.bodySmall.fontFamily, - lineHeight = MaterialTheme.typography.bodySmall.lineHeight, - fontWeight = MaterialTheme.typography.bodySmall.fontWeight, - overflow = TextOverflow.Ellipsis, - maxLines = 4, - textDecoration = textDecoration - ) - - - Spacer(modifier = Modifier.height(16.dp)) - - HorizontalDivider(thickness = Dp.Hairline) - - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Spacer(modifier = Modifier.weight(1f, true)) - - if (updateUrl.isNotEmpty()) { - Button( - modifier = Modifier - .padding(0.dp) - .defaultMinSize(52.dp, 32.dp), - onClick = { onUpdate(module) }, - shape = RoundedCornerShape(6.dp), - contentPadding = PaddingValues(0.dp) - ) { - Text( - fontFamily = MaterialTheme.typography.labelMedium.fontFamily, - fontSize = MaterialTheme.typography.labelMedium.fontSize, - text = stringResource(R.string.module_update), - ) - } - } - - TextButton( - enabled = !module.remove, - onClick = { onUninstall(module) }, - ) { - Text( - fontFamily = MaterialTheme.typography.labelMedium.fontFamily, - fontSize = MaterialTheme.typography.labelMedium.fontSize, - 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), - ) - } - } - } - } - } -} - -@Preview -@Composable -fun ModuleItemPreview() { - val module = ModuleViewModel.ModuleInfo( - id = "id", - name = "name", - version = "version", - versionCode = 1, - author = "author", - description = "I am a test module and i do nothing but show a very long description", - enabled = true, - update = true, - remove = true, - updateJson = "", - hasWebUi = false, - ) - ModuleItem(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 deleted file mode 100644 index 4f970f7e..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt +++ /dev/null @@ -1,474 +0,0 @@ -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.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.automirrored.filled.Undo -import androidx.compose.material.icons.filled.BugReport -import androidx.compose.material.icons.filled.Compress -import androidx.compose.material.icons.filled.ContactPage -import androidx.compose.material.icons.filled.Delete -import androidx.compose.material.icons.filled.DeleteForever -import androidx.compose.material.icons.filled.DeveloperMode -import androidx.compose.material.icons.filled.Fence -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 -import androidx.compose.material3.ListItem -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -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.graphics.vector.ImageVector -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.LineHeightStyle -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.core.content.FileProvider -import com.maxkeppeker.sheets.core.models.base.Header -import com.maxkeppeker.sheets.core.models.base.IconSource -import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState -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.navigation.DestinationsNavigator -import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import me.weishu.kernelsu.BuildConfig -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.R -import me.weishu.kernelsu.ui.component.AboutDialog -import me.weishu.kernelsu.ui.component.ConfirmResult -import me.weishu.kernelsu.ui.component.DialogHandle -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 -@Composable -fun SettingScreen(navigator: DestinationsNavigator) { - Scaffold( - topBar = { - TopBar(onBack = { - navigator.popBackStack() - }) - } - ) { paddingValues -> - val aboutDialog = rememberCustomDialog { - AboutDialog(it) - } - val loadingDialog = rememberLoadingDialog() - val shrinkDialog = rememberConfirmDialog() - - Column( - modifier = Modifier - .padding(paddingValues) - .verticalScroll(rememberScrollState()) - ) { - - val context = LocalContext.current - val scope = rememberCoroutineScope() - - val profileTemplate = stringResource(id = R.string.settings_profile_template) - ListItem( - leadingContent = { Icon(Icons.Filled.Fence, profileTemplate) }, - headlineContent = { Text(profileTemplate) }, - supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary)) }, - modifier = Modifier.clickable { - navigator.navigate(AppProfileTemplateScreenDestination) - } - ) - - var umountChecked by rememberSaveable { - mutableStateOf(Natives.isDefaultUmountModules()) - } - SwitchItem( - icon = Icons.Filled.RemoveModerator, - title = stringResource(id = R.string.settings_umount_modules_default), - summary = stringResource(id = R.string.settings_umount_modules_default_summary), - checked = umountChecked - ) { - if (Natives.setDefaultUmountModules(it)) { - umountChecked = it - } - } - - 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) - ) - } - SwitchItem( - icon = Icons.Filled.DeveloperMode, - title = stringResource(id = R.string.enable_web_debugging), - summary = stringResource(id = R.string.enable_web_debugging_summary), - checked = enableWebDebugging - ) { - prefs.edit().putBoolean("enable_web_debugging", it).apply() - enableWebDebugging = it - } - - var showBottomsheet by remember { mutableStateOf(false) } - - ListItem( - leadingContent = { - Icon( - Icons.Filled.BugReport, - stringResource(id = R.string.send_log) - ) - }, - headlineContent = { Text(stringResource(id = R.string.send_log)) }, - modifier = Modifier.clickable { - showBottomsheet = true - } - ) - if (showBottomsheet){ - ModalBottomSheet( - onDismissRequest = { showBottomsheet = false }, - content = { - Row(modifier = Modifier.padding(10.dp) - .align(Alignment.CenterHorizontally) - - ) { - Box{ - Column( - modifier = Modifier.padding(16.dp) - .clickable { - scope.launch { - val bugreport = loadingDialog.withLoading { - withContext(Dispatchers.IO) { - getBugreportFile(context) - } - } - - val uri: Uri = - FileProvider.getUriForFile( - context, - "${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 - } - context.startActivity( - Intent.createChooser( - savefile, - context.getString(R.string.save_log) - ) - ) - } - } - ) { - Icon( - Icons.Filled.Save, - contentDescription = null, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - Text( - text = stringResource(id = R.string.save_log), - modifier = Modifier.padding(top = 16.dp), - textAlign = TextAlign.Center.also { - LineHeightStyle( - alignment = LineHeightStyle.Alignment.Center, - trim = LineHeightStyle.Trim.None - ) - } - - ) - } - - } - Box{ - Column( - modifier = Modifier.padding(16.dp) - .clickable { - scope.launch { - val bugreport = loadingDialog.withLoading { - withContext(Dispatchers.IO) { - getBugreportFile(context) - } - } - - val uri: Uri = - FileProvider.getUriForFile( - context, - "${BuildConfig.APPLICATION_ID}.fileprovider", - bugreport - ) - - val shareIntent = Intent(Intent.ACTION_SEND) - shareIntent.putExtra(Intent.EXTRA_STREAM, uri) - shareIntent.setDataAndType(uri, "application/zip") - shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - - context.startActivity( - Intent.createChooser( - shareIntent, - context.getString(R.string.send_log) - ) - ) - } - } - ) { - Icon( - Icons.Filled.Share, - contentDescription = null, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - Text( - text = stringResource(id = R.string.send_log), - modifier = Modifier.padding(top = 16.dp), - textAlign = TextAlign.Center.also { - LineHeightStyle( - alignment = LineHeightStyle.Alignment.Center, - trim = LineHeightStyle.Trim.None - ) - } - - ) - } - - } - } - } - ) - - - } - - val shrink = stringResource(id = R.string.shrink_sparse_image) - val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message) - ListItem( - leadingContent = { - Icon( - Icons.Filled.Compress, - shrink - ) - }, - headlineContent = { Text(shrink) }, - modifier = Modifier.clickable { - scope.launch { - val result = - shrinkDialog.awaitConfirm(title = shrink, content = shrinkMessage) - if (result == ConfirmResult.Confirmed) { - loadingDialog.withLoading { - shrinkModules() - } - } - } - } - ) - - val lkmMode = - Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode - if (lkmMode) { - UninstallItem(navigator) { - loadingDialog.withLoading(it) - } - } - - val about = stringResource(id = R.string.about) - ListItem( - leadingContent = { - Icon( - Icons.Filled.ContactPage, - stringResource(id = R.string.about) - ) - }, - headlineContent = { Text(about) }, - modifier = Modifier.clickable { - aboutDialog.show() - } - ) - } - } -} -@Composable -fun UninstallItem( - navigator: DestinationsNavigator, - withLoading: suspend (suspend () -> Unit) -> Unit -) { - val context = LocalContext.current - val scope = rememberCoroutineScope() - val uninstallConfirmDialog = rememberConfirmDialog() - val showTodo = { - Toast.makeText(context, "TODO", Toast.LENGTH_SHORT).show() - } - val uninstallDialog = rememberUninstallDialog { uninstallType -> - scope.launch { - val result = uninstallConfirmDialog.awaitConfirm( - title = context.getString(uninstallType.title), - content = context.getString(uninstallType.message) - ) - if (result == ConfirmResult.Confirmed) { - withLoading { - when (uninstallType) { - UninstallType.TEMPORARY -> showTodo() - UninstallType.PERMANENT -> navigator.navigate( - FlashScreenDestination(FlashIt.FlashUninstall) - ) - - UninstallType.RESTORE_STOCK_IMAGE -> navigator.navigate( - FlashScreenDestination(FlashIt.FlashRestore) - ) - - UninstallType.NONE -> Unit - } - } - } - } - } - val uninstall = stringResource(id = R.string.settings_uninstall) - ListItem( - leadingContent = { - Icon( - Icons.Filled.Delete, - uninstall - ) - }, - headlineContent = { Text(uninstall) }, - modifier = Modifier.clickable { - uninstallDialog.show() - } - ) -} - -enum class UninstallType(val title: Int, val message: Int, val icon: ImageVector) { - TEMPORARY( - R.string.settings_uninstall_temporary, - R.string.settings_uninstall_temporary_message, - Icons.Filled.Delete - ), - PERMANENT( - R.string.settings_uninstall_permanent, - R.string.settings_uninstall_permanent_message, - Icons.Filled.DeleteForever - ), - RESTORE_STOCK_IMAGE( - R.string.settings_restore_stock_image, - R.string.settings_restore_stock_image_message, - Icons.AutoMirrored.Filled.Undo - ), - NONE(0, 0, Icons.Filled.Delete) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun rememberUninstallDialog(onSelected: (UninstallType) -> Unit): DialogHandle { - return rememberCustomDialog { dismiss -> - val options = listOf( - // UninstallType.TEMPORARY, - UninstallType.PERMANENT, - UninstallType.RESTORE_STOCK_IMAGE - ) - val listOptions = options.map { - ListOption( - titleText = stringResource(it.title), - subtitleText = if (it.message != 0) stringResource(it.message) else null, - icon = IconSource(it.icon) - ) - } - - var selection = UninstallType.NONE - ListDialog(state = rememberUseCaseState(visible = true, onFinishedRequest = { - if (selection != UninstallType.NONE) { - onSelected(selection) - } - }, onCloseRequest = { - dismiss() - }), header = Header.Default( - title = stringResource(R.string.settings_uninstall), - ), selection = ListSelection.Single( - showRadioButtons = false, - options = listOptions, - ) { index, _ -> - selection = options[index] - }) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar(onBack: () -> Unit = {}) { - TopAppBar( - title = { Text(stringResource(R.string.settings)) }, - navigationIcon = { - IconButton( - onClick = onBack - ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) } - }, - ) -} - -@Preview -@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 deleted file mode 100644 index 2eb2e770..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt +++ /dev/null @@ -1,185 +0,0 @@ -package me.weishu.kernelsu.ui.screen - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -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.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.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.lifecycle.viewmodel.compose.viewModel -import coil.compose.AsyncImage -import coil.request.ImageRequest -import com.ramcosta.composedestinations.annotation.Destination -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 -@Composable -fun SuperUserScreen(navigator: DestinationsNavigator) { - val viewModel = viewModel() - val scope = rememberCoroutineScope() - - LaunchedEffect(Unit) { - if (viewModel.appList.isEmpty()) { - viewModel.fetchAppList() - } - } - - Scaffold( - topBar = { - SearchAppBar( - title = { Text(stringResource(R.string.superuser)) }, - searchText = viewModel.search, - onSearchTextChange = { viewModel.search = it }, - onClearClick = { viewModel.search = "" }, - dropdownContent = { - var showDropdown by remember { mutableStateOf(false) } - - IconButton( - onClick = { showDropdown = true }, - ) { - Icon( - imageVector = Icons.Filled.MoreVert, - contentDescription = stringResource(id = R.string.settings) - ) - - DropdownMenu(expanded = showDropdown, onDismissRequest = { - showDropdown = false - }) { - DropdownMenuItem(text = { - Text(stringResource(R.string.refresh)) - }, onClick = { - scope.launch { - viewModel.fetchAppList() - } - showDropdown = false - }) - DropdownMenuItem(text = { - Text( - if (viewModel.showSystemApps) { - stringResource(R.string.hide_system_apps) - } else { - stringResource(R.string.show_system_apps) - } - ) - }, onClick = { - viewModel.showSystemApps = !viewModel.showSystemApps - showDropdown = false - }) - } - } - }, - ) - } - ) { innerPadding -> - val refreshState = rememberPullRefreshState( - refreshing = viewModel.isRefreshing, - onRefresh = { scope.launch { viewModel.fetchAppList() } }, - ) - Box( - modifier = Modifier - .padding(innerPadding) - .pullRefresh(refreshState) - ) { - LazyColumn(Modifier.fillMaxSize()) { - 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) - ) - } - } -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -private fun AppItem( - app: SuperUserViewModel.AppInfo, - onClickListener: () -> Unit, -) { - ListItem( - modifier = Modifier.clickable(onClick = onClickListener), - headlineContent = { Text(app.label) }, - supportingContent = { - Column { - Text(app.packageName) - FlowRow { - if (app.allowSu) { - LabelText(label = "ROOT") - } else { - if (Natives.uidShouldUmount(app.uid)) { - LabelText(label = "UMOUNT") - } - } - if (app.hasCustomProfile) { - LabelText(label = "CUSTOM") - } - } - } - }, - leadingContent = { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(app.packageInfo) - .crossfade(true) - .build(), - contentDescription = app.label, - modifier = Modifier - .padding(4.dp) - .width(48.dp) - .height(48.dp) - ) - }, - ) -} - -@Composable -fun LabelText(label: String) { - Box( - modifier = Modifier - .padding(top = 4.dp, end = 4.dp) - .background( - Color.Black, - shape = RoundedCornerShape(4.dp) - ) - ) { - Text( - text = label, - modifier = Modifier.padding(vertical = 2.dp, horizontal = 5.dp), - style = TextStyle( - fontSize = 8.sp, - color = Color.White, - ) - ) - } -} \ No newline at end of file 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 deleted file mode 100644 index bf353b0a..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt +++ /dev/null @@ -1,259 +0,0 @@ -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.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.icons.Icons -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 -import androidx.compose.material3.ExtendedFloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -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.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.platform.LocalClipboardManager -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -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.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 - -/** - * @author weishu - * @date 2023/10/20. - */ - -@OptIn(ExperimentalMaterialApi::class) -@Destination -@Composable -fun AppProfileTemplateScreen( - navigator: DestinationsNavigator, - resultRecipient: ResultRecipient -) { - val viewModel = viewModel() - val scope = rememberCoroutineScope() - - LaunchedEffect(Unit) { - if (viewModel.templateList.isEmpty()) { - viewModel.fetchTemplates() - } - } - - // handle result from TemplateEditorScreen, refresh if needed - resultRecipient.onNavResult { result -> - if (result.getOr { false }) { - scope.launch { viewModel.fetchTemplates() } - } - } - - Scaffold( - topBar = { - val clipboardManager = LocalClipboardManager.current - val context = LocalContext.current - val showToast = fun(msg: String) { - scope.launch(Dispatchers.Main) { - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() - } - } - TopBar(onBack = { navigator.popBackStack() }, - onSync = { - scope.launch { viewModel.fetchTemplates(true) } - }, - onImport = { - clipboardManager.getText()?.text?.let { - if (it.isEmpty()) { - showToast(context.getString(R.string.app_profile_template_import_empty)) - return@let - } - scope.launch { - viewModel.importTemplates( - it, { - showToast(context.getString(R.string.app_profile_template_import_success)) - viewModel.fetchTemplates(false) - }, - showToast - ) - } - } - }, - onExport = { - scope.launch { - viewModel.exportTemplates( - { - showToast(context.getString(R.string.app_profile_template_export_empty)) - } - ) { - clipboardManager.setText(AnnotatedString(it)) - } - } - } - ) - }, - floatingActionButton = { - ExtendedFloatingActionButton( - onClick = { - navigator.navigate( - TemplateEditorScreenDestination( - TemplateViewModel.TemplateInfo(), - false - ) - ) - }, - icon = { Icon(Icons.Filled.Add, null) }, - text = { Text(stringResource(id = R.string.app_profile_template_create)) }, - ) - }, - ) { innerPadding -> - val refreshState = rememberPullRefreshState( - refreshing = viewModel.isRefreshing, - onRefresh = { scope.launch { viewModel.fetchTemplates() } }, - ) - Box( - modifier = Modifier - .padding(innerPadding) - .pullRefresh(refreshState) - ) { - LazyColumn(Modifier.fillMaxSize(), contentPadding = remember { - PaddingValues(bottom = 16.dp + 16.dp + 56.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) - ) - } - } -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -private fun TemplateItem( - navigator: DestinationsNavigator, - template: TemplateViewModel.TemplateInfo -) { - ListItem( - modifier = Modifier - .clickable { - navigator.navigate(TemplateEditorScreenDestination(template, !template.local)) - }, - headlineContent = { Text(template.name) }, - supportingContent = { - Column { - Text( - text = "${template.id}${if (template.author.isEmpty()) "" else "@${template.author}"}", - style = MaterialTheme.typography.bodySmall, - fontSize = MaterialTheme.typography.bodySmall.fontSize, - ) - Text(template.description) - FlowRow { - LabelText(label = "UID: ${template.uid}") - LabelText(label = "GID: ${template.gid}") - LabelText(label = template.context) - if (template.local) { - LabelText(label = "local") - } else { - LabelText(label = "remote") - } - } - } - }, - ) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar( - onBack: () -> Unit, - onSync: () -> Unit = {}, - onImport: () -> Unit = {}, - onExport: () -> Unit = {} -) { - TopAppBar( - title = { - Text(stringResource(R.string.settings_profile_template)) - }, - navigationIcon = { - IconButton( - onClick = onBack - ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) } - }, - actions = { - IconButton(onClick = onSync) { - Icon( - Icons.Filled.Sync, - contentDescription = stringResource(id = R.string.app_profile_template_sync) - ) - } - - var showDropdown by remember { mutableStateOf(false) } - IconButton(onClick = { - showDropdown = true - }) { - Icon( - imageVector = Icons.Filled.ImportExport, - contentDescription = stringResource(id = R.string.app_profile_import_export) - ) - - DropdownMenu(expanded = showDropdown, onDismissRequest = { - showDropdown = false - }) { - DropdownMenuItem(text = { - Text(stringResource(id = R.string.app_profile_import_from_clipboard)) - }, onClick = { - onImport() - showDropdown = false - }) - DropdownMenuItem(text = { - Text(stringResource(id = R.string.app_profile_export_to_clipboard)) - }, onClick = { - onExport() - showDropdown = false - }) - } - } - } - ) -} \ 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 deleted file mode 100644 index b6b7cc80..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt +++ /dev/null @@ -1,322 +0,0 @@ -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.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -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.DeleteForever -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.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -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.pointer.pointerInteropFilter -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -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.result.ResultBackNavigator -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.R -import me.weishu.kernelsu.ui.component.profile.RootProfileConfig -import me.weishu.kernelsu.ui.util.deleteAppProfileTemplate -import me.weishu.kernelsu.ui.util.getAppProfileTemplate -import me.weishu.kernelsu.ui.util.setAppProfileTemplate -import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel -import me.weishu.kernelsu.ui.viewmodel.toJSON - -/** - * @author weishu - * @date 2023/10/20. - */ -@OptIn(ExperimentalComposeUiApi::class) -@Destination -@Composable -fun TemplateEditorScreen( - navigator: ResultBackNavigator, - initialTemplate: TemplateViewModel.TemplateInfo, - readOnly: Boolean = true, -) { - - val isCreation = initialTemplate.id.isBlank() - val autoSave = !isCreation - - var template by rememberSaveable { - mutableStateOf(initialTemplate) - } - - BackHandler { - navigator.navigateBack(result = !readOnly) - } - - Scaffold( - topBar = { - val author = - if (initialTemplate.author.isNotEmpty()) "@${initialTemplate.author}" else "" - val readOnlyHint = if (readOnly) { - " - ${stringResource(id = R.string.app_profile_template_readonly)}" - } else { - "" - } - val titleSummary = "${initialTemplate.id}$author$readOnlyHint" - val saveTemplateFailed = stringResource(id = R.string.app_profile_template_save_failed) - val context = LocalContext.current - - TopBar( - title = if (isCreation) { - stringResource(R.string.app_profile_template_create) - } else if (readOnly) { - stringResource(R.string.app_profile_template_view) - } else { - stringResource(R.string.app_profile_template_edit) - }, - readOnly = readOnly, - summary = titleSummary, - onBack = { navigator.navigateBack(result = !readOnly) }, - onDelete = { - if (deleteAppProfileTemplate(template.id)) { - navigator.navigateBack(result = true) - } - }, - onSave = { - if (saveTemplate(template, isCreation)) { - navigator.navigateBack(result = true) - } else { - Toast.makeText(context, saveTemplateFailed, Toast.LENGTH_SHORT).show() - } - }) - }, - ) { innerPadding -> - Column( - modifier = Modifier - .padding(innerPadding) - .verticalScroll(rememberScrollState()) - .pointerInteropFilter { - // disable click and ripple if readOnly - readOnly - } - ) { - if (isCreation) { - var errorHint by remember { - mutableStateOf("") - } - val idConflictError = stringResource(id = R.string.app_profile_template_id_exist) - val idInvalidError = stringResource(id = R.string.app_profile_template_id_invalid) - TextEdit( - label = stringResource(id = R.string.app_profile_template_id), - text = template.id, - errorHint = errorHint, - isError = errorHint.isNotEmpty() - ) { value -> - errorHint = if (isTemplateExist(value)) { - idConflictError - } else if (!isValidTemplateId(value)) { - idInvalidError - } else { - "" - } - template = template.copy(id = value) - } - } - - TextEdit( - label = stringResource(id = R.string.app_profile_template_name), - text = template.name - ) { value -> - template.copy(name = value).run { - if (autoSave) { - if (!saveTemplate(this)) { - // failed - return@run - } - } - template = this - } - } - TextEdit( - label = stringResource(id = R.string.app_profile_template_description), - text = template.description - ) { value -> - template.copy(description = value).run { - if (autoSave) { - if (!saveTemplate(this)) { - // failed - return@run - } - } - template = this - } - } - - RootProfileConfig(fixedName = true, - profile = toNativeProfile(template), - onProfileChange = { - template.copy( - uid = it.uid, - gid = it.gid, - groups = it.groups, - capabilities = it.capabilities, - context = it.context, - namespace = it.namespace, - rules = it.rules.split("\n") - ).run { - if (autoSave) { - if (!saveTemplate(this)) { - // failed - return@run - } - } - template = this - } - }) - } - } -} - -fun toNativeProfile(templateInfo: TemplateViewModel.TemplateInfo): Natives.Profile { - return Natives.Profile().copy(rootTemplate = templateInfo.id, - uid = templateInfo.uid, - gid = templateInfo.gid, - groups = templateInfo.groups, - capabilities = templateInfo.capabilities, - context = templateInfo.context, - namespace = templateInfo.namespace, - rules = templateInfo.rules.joinToString("\n").ifBlank { "" }) -} - -fun isTemplateValid(template: TemplateViewModel.TemplateInfo): Boolean { - if (template.id.isBlank()) { - return false - } - - if (!isValidTemplateId(template.id)) { - return false - } - - return true -} - -fun saveTemplate(template: TemplateViewModel.TemplateInfo, isCreation: Boolean = false): Boolean { - if (!isTemplateValid(template)) { - return false - } - - if (isCreation && isTemplateExist(template.id)) { - return false - } - - val json = template.toJSON() - json.put("local", true) - return setAppProfileTemplate(template.id, json.toString()) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar( - title: String, - readOnly: Boolean, - summary: String = "", - onBack: () -> Unit, - onDelete: () -> Unit = {}, - onSave: () -> Unit = {} -) { - 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) - ) - } - IconButton(onClick = onSave) { - Icon( - imageVector = Icons.Filled.Save, - contentDescription = stringResource(id = R.string.app_profile_template_save) - ) - } - }) -} - -@Composable -private fun TextEdit( - label: String, - text: String, - errorHint: String = "", - isError: Boolean = false, - onValueChange: (String) -> Unit = {} -) { - ListItem(headlineContent = { - val keyboardController = LocalSoftwareKeyboardController.current - OutlinedTextField( - value = text, - modifier = Modifier.fillMaxWidth(), - label = { Text(label) }, - suffix = - if (errorHint.isNotBlank()) { - { - Text( - text = if (isError) errorHint else "", - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.error - ) - } - } else { - null - }, - isError = isError, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Next - ), - keyboardActions = KeyboardActions(onDone = { - keyboardController?.hide() - }), - onValueChange = onValueChange - ) - }) -} - -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) -} - -private fun isTemplateExist(id: String): Boolean { - return getAppProfileTemplate(id).isNotBlank() -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Color.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Color.kt deleted file mode 100644 index 155cf4e2..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Color.kt +++ /dev/null @@ -1,10 +0,0 @@ -package me.weishu.kernelsu.ui.theme - -import androidx.compose.ui.graphics.Color - -val YELLOW = Color(0xFFeed502) -val YELLOW_LIGHT = Color(0xFFffff52) -val SECONDARY_LIGHT = Color(0xffa9817f) - -val YELLOW_DARK = Color(0xFFb7a400) -val SECONDARY_DARK = Color(0xFF4c2b2b) \ No newline at end of file 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 deleted file mode 100644 index 3b3945d0..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt +++ /dev/null @@ -1,64 +0,0 @@ -package me.weishu.kernelsu.ui.theme - -import android.os.Build -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.MaterialTheme -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, - secondary = YELLOW_DARK, - tertiary = SECONDARY_DARK -) - -private val LightColorScheme = lightColorScheme( - primary = YELLOW, - secondary = YELLOW_LIGHT, - tertiary = SECONDARY_LIGHT -) - -@Composable -fun KernelSUTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, - content: @Composable () -> Unit -) { - val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - darkTheme -> DarkColorScheme - 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, - content = content - ) -} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Type.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Type.kt deleted file mode 100644 index e8d73313..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Type.kt +++ /dev/null @@ -1,33 +0,0 @@ -package me.weishu.kernelsu.ui.theme - -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.sp - -// Set of Material typography styles to start with -val Typography = androidx.compose.material3.Typography( - bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp - ) - /* Other default text styles to override - titleLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - labelSmall = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Medium, - fontSize = 11.sp, - lineHeight = 16.sp, - letterSpacing = 0.5.sp - ) - */ -) \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/CompositionProvider.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/CompositionProvider.kt deleted file mode 100644 index c1b57483..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/CompositionProvider.kt +++ /dev/null @@ -1,8 +0,0 @@ -package me.weishu.kernelsu.ui.util - -import androidx.compose.material3.SnackbarHostState -import androidx.compose.runtime.compositionLocalOf - -val LocalSnackbarHost = compositionLocalOf { - error("CompositionLocal LocalSnackbarController not present") -} \ No newline at end of file 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 deleted file mode 100644 index 954cac50..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt +++ /dev/null @@ -1,149 +0,0 @@ -package me.weishu.kernelsu.ui.util - -import android.annotation.SuppressLint -import android.app.DownloadManager -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.net.Uri -import android.os.Build -import android.os.Environment -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import me.weishu.kernelsu.ui.util.module.LatestVersionInfo - -/** - * @author weishu - * @date 2023/6/22. - */ -@SuppressLint("Range") -fun download( - context: Context, - url: String, - fileName: String, - description: String, - onDownloaded: (Uri) -> Unit = {}, - onDownloading: () -> Unit = {} -) { - val downloadManager = - context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager - - val query = DownloadManager.Query() - query.setFilterByStatus(DownloadManager.STATUS_RUNNING or DownloadManager.STATUS_PAUSED or DownloadManager.STATUS_PENDING) - downloadManager.query(query).use { cursor -> - while (cursor.moveToNext()) { - val uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI)) - val localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)) - val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) - val columnTitle = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE)) - if (url == uri || fileName == columnTitle) { - if (status == DownloadManager.STATUS_RUNNING || status == DownloadManager.STATUS_PENDING) { - onDownloading() - return - } else if (status == DownloadManager.STATUS_SUCCESSFUL) { - onDownloaded(Uri.parse(localUri)) - return - } - } - } - } - - val request = DownloadManager.Request(Uri.parse(url)) - .setDestinationInExternalPublicDir( - Environment.DIRECTORY_DOWNLOADS, - fileName - ) - .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) - .setMimeType("application/zip") - .setTitle(fileName) - .setDescription(description) - - downloadManager.enqueue(request) -} - -fun checkNewVersion(): LatestVersionInfo { - val url = "https://api.github.com/repos/tiann/KernelSU/releases/latest" - // default null value if failed - val defaultValue = LatestVersionInfo() - runCatching { - okhttp3.OkHttpClient().newCall(okhttp3.Request.Builder().url(url).build()).execute() - .use { response -> - if (!response.isSuccessful) { - return defaultValue - } - val body = response.body?.string() ?: return defaultValue - val json = org.json.JSONObject(body) - val changelog = json.optString("body") - - val assets = json.getJSONArray("assets") - for (i in 0 until assets.length()) { - val asset = assets.getJSONObject(i) - val name = asset.getString("name") - if (!name.endsWith(".apk")) { - continue - } - - val regex = Regex("v(.+?)_(\\d+)-") - val matchResult = regex.find(name) ?: continue - val versionName = matchResult.groupValues[1] - val versionCode = matchResult.groupValues[2].toInt() - val downloadUrl = asset.getString("browser_download_url") - - return LatestVersionInfo( - versionCode, - downloadUrl, - changelog - ) - } - - } - } - return defaultValue -} - -@Composable -fun DownloadListener(context: Context, onDownloaded: (Uri) -> Unit) { - DisposableEffect(context) { - val receiver = object : BroadcastReceiver() { - @SuppressLint("Range") - override fun onReceive(context: Context?, intent: Intent?) { - if (intent?.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) { - val id = intent.getLongExtra( - DownloadManager.EXTRA_DOWNLOAD_ID, -1 - ) - val query = DownloadManager.Query().setFilterById(id) - val downloadManager = - context?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager - val cursor = downloadManager.query(query) - if (cursor.moveToFirst()) { - val status = cursor.getInt( - cursor.getColumnIndex(DownloadManager.COLUMN_STATUS) - ) - if (status == DownloadManager.STATUS_SUCCESSFUL) { - val uri = cursor.getString( - cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) - ) - onDownloaded(Uri.parse(uri)) - } - } - } - } - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - context.registerReceiver( - receiver, - IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), - Context.RECEIVER_EXPORTED - ) - } else { - context.registerReceiver( - receiver, - IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) - ) - } - onDispose { - context.unregisterReceiver(receiver) - } - } -} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HanziToPinyin.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HanziToPinyin.java deleted file mode 100644 index d3d57cef..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HanziToPinyin.java +++ /dev/null @@ -1,576 +0,0 @@ -package me.weishu.kernelsu.ui.util; -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import android.text.TextUtils; -import android.util.Log; - -import java.text.Collator; -import java.util.ArrayList; -import java.util.Locale; - -/** - * An object to convert Chinese character to its corresponding pinyin string. For characters with - * multiple possible pinyin string, only one is selected according to collator. Polyphone is not - * supported in this implementation. This class is implemented to achieve the best runtime - * performance and minimum runtime resources with tolerable sacrifice of accuracy. This - * implementation highly depends on zh_CN ICU collation data and must be always synchronized with - * ICU. - *

- * Currently this file is aligned to zh.txt in ICU 4.6 - */ -public class HanziToPinyin { - private static final String TAG = "HanziToPinyin"; - - // Turn on this flag when we want to check internal data structure. - private static final boolean DEBUG = false; - - /** - * Unihans array. - *

- * Each unihans is the first one within same pinyin when collator is zh_CN. - */ - public static final char[] UNIHANS = { - '\u963f', '\u54ce', '\u5b89', '\u80ae', '\u51f9', '\u516b', - '\u6300', '\u6273', '\u90a6', '\u52f9', '\u9642', '\u5954', - '\u4f3b', '\u5c44', '\u8fb9', '\u706c', '\u618b', '\u6c43', - '\u51ab', '\u7676', '\u5cec', '\u5693', '\u5072', '\u53c2', - '\u4ed3', '\u64a1', '\u518a', '\u5d7e', '\u66fd', '\u66fe', - '\u5c64', '\u53c9', '\u8286', '\u8fbf', '\u4f25', '\u6284', - '\u8f66', '\u62bb', '\u6c88', '\u6c89', '\u9637', '\u5403', - '\u5145', '\u62bd', '\u51fa', '\u6b3b', '\u63e3', '\u5ddb', - '\u5205', '\u5439', '\u65fe', '\u9034', '\u5472', '\u5306', - '\u51d1', '\u7c97', '\u6c46', '\u5d14', '\u90a8', '\u6413', - '\u5491', '\u5446', '\u4e39', '\u5f53', '\u5200', '\u561a', - '\u6265', '\u706f', '\u6c10', '\u55f2', '\u7538', '\u5201', - '\u7239', '\u4e01', '\u4e1f', '\u4e1c', '\u543a', '\u53be', - '\u8011', '\u8968', '\u5428', '\u591a', '\u59b8', '\u8bf6', - '\u5940', '\u97a5', '\u513f', '\u53d1', '\u5e06', '\u531a', - '\u98de', '\u5206', '\u4e30', '\u8985', '\u4ecf', '\u7d11', - '\u4f15', '\u65ee', '\u4f85', '\u7518', '\u5188', '\u768b', - '\u6208', '\u7ed9', '\u6839', '\u522f', '\u5de5', '\u52fe', - '\u4f30', '\u74dc', '\u4e56', '\u5173', '\u5149', '\u5f52', - '\u4e28', '\u5459', '\u54c8', '\u548d', '\u4f44', '\u592f', - '\u8320', '\u8bc3', '\u9ed2', '\u62eb', '\u4ea8', '\u5677', - '\u53ff', '\u9f41', '\u4e6f', '\u82b1', '\u6000', '\u72bf', - '\u5ddf', '\u7070', '\u660f', '\u5419', '\u4e0c', '\u52a0', - '\u620b', '\u6c5f', '\u827d', '\u9636', '\u5dfe', '\u5755', - '\u5182', '\u4e29', '\u51e5', '\u59e2', '\u5658', '\u519b', - '\u5494', '\u5f00', '\u520a', '\u5ffc', '\u5c3b', '\u533c', - '\u808e', '\u52a5', '\u7a7a', '\u62a0', '\u625d', '\u5938', - '\u84af', '\u5bbd', '\u5321', '\u4e8f', '\u5764', '\u6269', - '\u5783', '\u6765', '\u5170', '\u5577', '\u635e', '\u808b', - '\u52d2', '\u5d1a', '\u5215', '\u4fe9', '\u5941', '\u826f', - '\u64a9', '\u5217', '\u62ce', '\u5222', '\u6e9c', '\u56d6', - '\u9f99', '\u779c', '\u565c', '\u5a08', '\u7567', '\u62a1', - '\u7f57', '\u5463', '\u5988', '\u57cb', '\u5ada', '\u7264', - '\u732b', '\u4e48', '\u5445', '\u95e8', '\u753f', '\u54aa', - '\u5b80', '\u55b5', '\u4e5c', '\u6c11', '\u540d', '\u8c2c', - '\u6478', '\u54de', '\u6bea', '\u55ef', '\u62cf', '\u8149', - '\u56e1', '\u56d4', '\u5b6c', '\u7592', '\u5a1e', '\u6041', - '\u80fd', '\u59ae', '\u62c8', '\u5b22', '\u9e1f', '\u634f', - '\u56dc', '\u5b81', '\u599e', '\u519c', '\u7fba', '\u5974', - '\u597b', '\u759f', '\u9ec1', '\u90cd', '\u5594', '\u8bb4', - '\u5991', '\u62cd', '\u7705', '\u4e53', '\u629b', '\u5478', - '\u55b7', '\u5309', '\u4e15', '\u56e8', '\u527d', '\u6c15', - '\u59d8', '\u4e52', '\u948b', '\u5256', '\u4ec6', '\u4e03', - '\u6390', '\u5343', '\u545b', '\u6084', '\u767f', '\u4eb2', - '\u72c5', '\u828e', '\u4e18', '\u533a', '\u5cd1', '\u7f3a', - '\u590b', '\u5465', '\u7a63', '\u5a06', '\u60f9', '\u4eba', - '\u6254', '\u65e5', '\u8338', '\u53b9', '\u909a', '\u633c', - '\u5827', '\u5a51', '\u77a4', '\u637c', '\u4ee8', '\u6be2', - '\u4e09', '\u6852', '\u63bb', '\u95aa', '\u68ee', '\u50e7', - '\u6740', '\u7b5b', '\u5c71', '\u4f24', '\u5f30', '\u5962', - '\u7533', '\u8398', '\u6552', '\u5347', '\u5c38', '\u53ce', - '\u4e66', '\u5237', '\u8870', '\u95e9', '\u53cc', '\u8c01', - '\u542e', '\u8bf4', '\u53b6', '\u5fea', '\u635c', '\u82cf', - '\u72fb', '\u590a', '\u5b59', '\u5506', '\u4ed6', '\u56fc', - '\u574d', '\u6c64', '\u5932', '\u5fd1', '\u71a5', '\u5254', - '\u5929', '\u65eb', '\u5e16', '\u5385', '\u56f2', '\u5077', - '\u51f8', '\u6e4d', '\u63a8', '\u541e', '\u4e47', '\u7a75', - '\u6b6a', '\u5f2f', '\u5c23', '\u5371', '\u6637', '\u7fc1', - '\u631d', '\u4e4c', '\u5915', '\u8672', '\u4eda', '\u4e61', - '\u7071', '\u4e9b', '\u5fc3', '\u661f', '\u51f6', '\u4f11', - '\u5401', '\u5405', '\u524a', '\u5743', '\u4e2b', '\u6079', - '\u592e', '\u5e7a', '\u503b', '\u4e00', '\u56d9', '\u5e94', - '\u54df', '\u4f63', '\u4f18', '\u625c', '\u56e6', '\u66f0', - '\u6655', '\u7b60', '\u7b7c', '\u5e00', '\u707d', '\u5142', - '\u5328', '\u50ae', '\u5219', '\u8d3c', '\u600e', '\u5897', - '\u624e', '\u635a', '\u6cbe', '\u5f20', '\u957f', '\u9577', - '\u4f4b', '\u8707', '\u8d1e', '\u4e89', '\u4e4b', '\u5cd9', - '\u5ea2', '\u4e2d', '\u5dde', '\u6731', '\u6293', '\u62fd', - '\u4e13', '\u5986', '\u96b9', '\u5b92', '\u5353', '\u4e72', - '\u5b97', '\u90b9', '\u79df', '\u94bb', '\u539c', '\u5c0a', - '\u6628', '\u5159', '\u9fc3', '\u9fc4',}; - - /** - * Pinyin array. - *

- * Each pinyin is corresponding to unihans of same - * offset in the unihans array. - */ - public static final byte[][] PINYINS = { - {65, 0, 0, 0, 0, 0}, {65, 73, 0, 0, 0, 0}, - {65, 78, 0, 0, 0, 0}, {65, 78, 71, 0, 0, 0}, - {65, 79, 0, 0, 0, 0}, {66, 65, 0, 0, 0, 0}, - {66, 65, 73, 0, 0, 0}, {66, 65, 78, 0, 0, 0}, - {66, 65, 78, 71, 0, 0}, {66, 65, 79, 0, 0, 0}, - {66, 69, 73, 0, 0, 0}, {66, 69, 78, 0, 0, 0}, - {66, 69, 78, 71, 0, 0}, {66, 73, 0, 0, 0, 0}, - {66, 73, 65, 78, 0, 0}, {66, 73, 65, 79, 0, 0}, - {66, 73, 69, 0, 0, 0}, {66, 73, 78, 0, 0, 0}, - {66, 73, 78, 71, 0, 0}, {66, 79, 0, 0, 0, 0}, - {66, 85, 0, 0, 0, 0}, {67, 65, 0, 0, 0, 0}, - {67, 65, 73, 0, 0, 0}, {67, 65, 78, 0, 0, 0}, - {67, 65, 78, 71, 0, 0}, {67, 65, 79, 0, 0, 0}, - {67, 69, 0, 0, 0, 0}, {67, 69, 78, 0, 0, 0}, - {67, 69, 78, 71, 0, 0}, {90, 69, 78, 71, 0, 0}, - {67, 69, 78, 71, 0, 0}, {67, 72, 65, 0, 0, 0}, - {67, 72, 65, 73, 0, 0}, {67, 72, 65, 78, 0, 0}, - {67, 72, 65, 78, 71, 0}, {67, 72, 65, 79, 0, 0}, - {67, 72, 69, 0, 0, 0}, {67, 72, 69, 78, 0, 0}, - {83, 72, 69, 78, 0, 0}, {67, 72, 69, 78, 0, 0}, - {67, 72, 69, 78, 71, 0}, {67, 72, 73, 0, 0, 0}, - {67, 72, 79, 78, 71, 0}, {67, 72, 79, 85, 0, 0}, - {67, 72, 85, 0, 0, 0}, {67, 72, 85, 65, 0, 0}, - {67, 72, 85, 65, 73, 0}, {67, 72, 85, 65, 78, 0}, - {67, 72, 85, 65, 78, 71}, {67, 72, 85, 73, 0, 0}, - {67, 72, 85, 78, 0, 0}, {67, 72, 85, 79, 0, 0}, - {67, 73, 0, 0, 0, 0}, {67, 79, 78, 71, 0, 0}, - {67, 79, 85, 0, 0, 0}, {67, 85, 0, 0, 0, 0}, - {67, 85, 65, 78, 0, 0}, {67, 85, 73, 0, 0, 0}, - {67, 85, 78, 0, 0, 0}, {67, 85, 79, 0, 0, 0}, - {68, 65, 0, 0, 0, 0}, {68, 65, 73, 0, 0, 0}, - {68, 65, 78, 0, 0, 0}, {68, 65, 78, 71, 0, 0}, - {68, 65, 79, 0, 0, 0}, {68, 69, 0, 0, 0, 0}, - {68, 69, 78, 0, 0, 0}, {68, 69, 78, 71, 0, 0}, - {68, 73, 0, 0, 0, 0}, {68, 73, 65, 0, 0, 0}, - {68, 73, 65, 78, 0, 0}, {68, 73, 65, 79, 0, 0}, - {68, 73, 69, 0, 0, 0}, {68, 73, 78, 71, 0, 0}, - {68, 73, 85, 0, 0, 0}, {68, 79, 78, 71, 0, 0}, - {68, 79, 85, 0, 0, 0}, {68, 85, 0, 0, 0, 0}, - {68, 85, 65, 78, 0, 0}, {68, 85, 73, 0, 0, 0}, - {68, 85, 78, 0, 0, 0}, {68, 85, 79, 0, 0, 0}, - {69, 0, 0, 0, 0, 0}, {69, 73, 0, 0, 0, 0}, - {69, 78, 0, 0, 0, 0}, {69, 78, 71, 0, 0, 0}, - {69, 82, 0, 0, 0, 0}, {70, 65, 0, 0, 0, 0}, - {70, 65, 78, 0, 0, 0}, {70, 65, 78, 71, 0, 0}, - {70, 69, 73, 0, 0, 0}, {70, 69, 78, 0, 0, 0}, - {70, 69, 78, 71, 0, 0}, {70, 73, 65, 79, 0, 0}, - {70, 79, 0, 0, 0, 0}, {70, 79, 85, 0, 0, 0}, - {70, 85, 0, 0, 0, 0}, {71, 65, 0, 0, 0, 0}, - {71, 65, 73, 0, 0, 0}, {71, 65, 78, 0, 0, 0}, - {71, 65, 78, 71, 0, 0}, {71, 65, 79, 0, 0, 0}, - {71, 69, 0, 0, 0, 0}, {71, 69, 73, 0, 0, 0}, - {71, 69, 78, 0, 0, 0}, {71, 69, 78, 71, 0, 0}, - {71, 79, 78, 71, 0, 0}, {71, 79, 85, 0, 0, 0}, - {71, 85, 0, 0, 0, 0}, {71, 85, 65, 0, 0, 0}, - {71, 85, 65, 73, 0, 0}, {71, 85, 65, 78, 0, 0}, - {71, 85, 65, 78, 71, 0}, {71, 85, 73, 0, 0, 0}, - {71, 85, 78, 0, 0, 0}, {71, 85, 79, 0, 0, 0}, - {72, 65, 0, 0, 0, 0}, {72, 65, 73, 0, 0, 0}, - {72, 65, 78, 0, 0, 0}, {72, 65, 78, 71, 0, 0}, - {72, 65, 79, 0, 0, 0}, {72, 69, 0, 0, 0, 0}, - {72, 69, 73, 0, 0, 0}, {72, 69, 78, 0, 0, 0}, - {72, 69, 78, 71, 0, 0}, {72, 77, 0, 0, 0, 0}, - {72, 79, 78, 71, 0, 0}, {72, 79, 85, 0, 0, 0}, - {72, 85, 0, 0, 0, 0}, {72, 85, 65, 0, 0, 0}, - {72, 85, 65, 73, 0, 0}, {72, 85, 65, 78, 0, 0}, - {72, 85, 65, 78, 71, 0}, {72, 85, 73, 0, 0, 0}, - {72, 85, 78, 0, 0, 0}, {72, 85, 79, 0, 0, 0}, - {74, 73, 0, 0, 0, 0}, {74, 73, 65, 0, 0, 0}, - {74, 73, 65, 78, 0, 0}, {74, 73, 65, 78, 71, 0}, - {74, 73, 65, 79, 0, 0}, {74, 73, 69, 0, 0, 0}, - {74, 73, 78, 0, 0, 0}, {74, 73, 78, 71, 0, 0}, - {74, 73, 79, 78, 71, 0}, {74, 73, 85, 0, 0, 0}, - {74, 85, 0, 0, 0, 0}, {74, 85, 65, 78, 0, 0}, - {74, 85, 69, 0, 0, 0}, {74, 85, 78, 0, 0, 0}, - {75, 65, 0, 0, 0, 0}, {75, 65, 73, 0, 0, 0}, - {75, 65, 78, 0, 0, 0}, {75, 65, 78, 71, 0, 0}, - {75, 65, 79, 0, 0, 0}, {75, 69, 0, 0, 0, 0}, - {75, 69, 78, 0, 0, 0}, {75, 69, 78, 71, 0, 0}, - {75, 79, 78, 71, 0, 0}, {75, 79, 85, 0, 0, 0}, - {75, 85, 0, 0, 0, 0}, {75, 85, 65, 0, 0, 0}, - {75, 85, 65, 73, 0, 0}, {75, 85, 65, 78, 0, 0}, - {75, 85, 65, 78, 71, 0}, {75, 85, 73, 0, 0, 0}, - {75, 85, 78, 0, 0, 0}, {75, 85, 79, 0, 0, 0}, - {76, 65, 0, 0, 0, 0}, {76, 65, 73, 0, 0, 0}, - {76, 65, 78, 0, 0, 0}, {76, 65, 78, 71, 0, 0}, - {76, 65, 79, 0, 0, 0}, {76, 69, 0, 0, 0, 0}, - {76, 69, 73, 0, 0, 0}, {76, 69, 78, 71, 0, 0}, - {76, 73, 0, 0, 0, 0}, {76, 73, 65, 0, 0, 0}, - {76, 73, 65, 78, 0, 0}, {76, 73, 65, 78, 71, 0}, - {76, 73, 65, 79, 0, 0}, {76, 73, 69, 0, 0, 0}, - {76, 73, 78, 0, 0, 0}, {76, 73, 78, 71, 0, 0}, - {76, 73, 85, 0, 0, 0}, {76, 79, 0, 0, 0, 0}, - {76, 79, 78, 71, 0, 0}, {76, 79, 85, 0, 0, 0}, - {76, 85, 0, 0, 0, 0}, {76, 85, 65, 78, 0, 0}, - {76, 85, 69, 0, 0, 0}, {76, 85, 78, 0, 0, 0}, - {76, 85, 79, 0, 0, 0}, {77, 0, 0, 0, 0, 0}, - {77, 65, 0, 0, 0, 0}, {77, 65, 73, 0, 0, 0}, - {77, 65, 78, 0, 0, 0}, {77, 65, 78, 71, 0, 0}, - {77, 65, 79, 0, 0, 0}, {77, 69, 0, 0, 0, 0}, - {77, 69, 73, 0, 0, 0}, {77, 69, 78, 0, 0, 0}, - {77, 69, 78, 71, 0, 0}, {77, 73, 0, 0, 0, 0}, - {77, 73, 65, 78, 0, 0}, {77, 73, 65, 79, 0, 0}, - {77, 73, 69, 0, 0, 0}, {77, 73, 78, 0, 0, 0}, - {77, 73, 78, 71, 0, 0}, {77, 73, 85, 0, 0, 0}, - {77, 79, 0, 0, 0, 0}, {77, 79, 85, 0, 0, 0}, - {77, 85, 0, 0, 0, 0}, {78, 0, 0, 0, 0, 0}, - {78, 65, 0, 0, 0, 0}, {78, 65, 73, 0, 0, 0}, - {78, 65, 78, 0, 0, 0}, {78, 65, 78, 71, 0, 0}, - {78, 65, 79, 0, 0, 0}, {78, 69, 0, 0, 0, 0}, - {78, 69, 73, 0, 0, 0}, {78, 69, 78, 0, 0, 0}, - {78, 69, 78, 71, 0, 0}, {78, 73, 0, 0, 0, 0}, - {78, 73, 65, 78, 0, 0}, {78, 73, 65, 78, 71, 0}, - {78, 73, 65, 79, 0, 0}, {78, 73, 69, 0, 0, 0}, - {78, 73, 78, 0, 0, 0}, {78, 73, 78, 71, 0, 0}, - {78, 73, 85, 0, 0, 0}, {78, 79, 78, 71, 0, 0}, - {78, 79, 85, 0, 0, 0}, {78, 85, 0, 0, 0, 0}, - {78, 85, 65, 78, 0, 0}, {78, 85, 69, 0, 0, 0}, - {78, 85, 78, 0, 0, 0}, {78, 85, 79, 0, 0, 0}, - {79, 0, 0, 0, 0, 0}, {79, 85, 0, 0, 0, 0}, - {80, 65, 0, 0, 0, 0}, {80, 65, 73, 0, 0, 0}, - {80, 65, 78, 0, 0, 0}, {80, 65, 78, 71, 0, 0}, - {80, 65, 79, 0, 0, 0}, {80, 69, 73, 0, 0, 0}, - {80, 69, 78, 0, 0, 0}, {80, 69, 78, 71, 0, 0}, - {80, 73, 0, 0, 0, 0}, {80, 73, 65, 78, 0, 0}, - {80, 73, 65, 79, 0, 0}, {80, 73, 69, 0, 0, 0}, - {80, 73, 78, 0, 0, 0}, {80, 73, 78, 71, 0, 0}, - {80, 79, 0, 0, 0, 0}, {80, 79, 85, 0, 0, 0}, - {80, 85, 0, 0, 0, 0}, {81, 73, 0, 0, 0, 0}, - {81, 73, 65, 0, 0, 0}, {81, 73, 65, 78, 0, 0}, - {81, 73, 65, 78, 71, 0}, {81, 73, 65, 79, 0, 0}, - {81, 73, 69, 0, 0, 0}, {81, 73, 78, 0, 0, 0}, - {81, 73, 78, 71, 0, 0}, {81, 73, 79, 78, 71, 0}, - {81, 73, 85, 0, 0, 0}, {81, 85, 0, 0, 0, 0}, - {81, 85, 65, 78, 0, 0}, {81, 85, 69, 0, 0, 0}, - {81, 85, 78, 0, 0, 0}, {82, 65, 78, 0, 0, 0}, - {82, 65, 78, 71, 0, 0}, {82, 65, 79, 0, 0, 0}, - {82, 69, 0, 0, 0, 0}, {82, 69, 78, 0, 0, 0}, - {82, 69, 78, 71, 0, 0}, {82, 73, 0, 0, 0, 0}, - {82, 79, 78, 71, 0, 0}, {82, 79, 85, 0, 0, 0}, - {82, 85, 0, 0, 0, 0}, {82, 85, 65, 0, 0, 0}, - {82, 85, 65, 78, 0, 0}, {82, 85, 73, 0, 0, 0}, - {82, 85, 78, 0, 0, 0}, {82, 85, 79, 0, 0, 0}, - {83, 65, 0, 0, 0, 0}, {83, 65, 73, 0, 0, 0}, - {83, 65, 78, 0, 0, 0}, {83, 65, 78, 71, 0, 0}, - {83, 65, 79, 0, 0, 0}, {83, 69, 0, 0, 0, 0}, - {83, 69, 78, 0, 0, 0}, {83, 69, 78, 71, 0, 0}, - {83, 72, 65, 0, 0, 0}, {83, 72, 65, 73, 0, 0}, - {83, 72, 65, 78, 0, 0}, {83, 72, 65, 78, 71, 0}, - {83, 72, 65, 79, 0, 0}, {83, 72, 69, 0, 0, 0}, - {83, 72, 69, 78, 0, 0}, {88, 73, 78, 0, 0, 0}, - {83, 72, 69, 78, 0, 0}, {83, 72, 69, 78, 71, 0}, - {83, 72, 73, 0, 0, 0}, {83, 72, 79, 85, 0, 0}, - {83, 72, 85, 0, 0, 0}, {83, 72, 85, 65, 0, 0}, - {83, 72, 85, 65, 73, 0}, {83, 72, 85, 65, 78, 0}, - {83, 72, 85, 65, 78, 71}, {83, 72, 85, 73, 0, 0}, - {83, 72, 85, 78, 0, 0}, {83, 72, 85, 79, 0, 0}, - {83, 73, 0, 0, 0, 0}, {83, 79, 78, 71, 0, 0}, - {83, 79, 85, 0, 0, 0}, {83, 85, 0, 0, 0, 0}, - {83, 85, 65, 78, 0, 0}, {83, 85, 73, 0, 0, 0}, - {83, 85, 78, 0, 0, 0}, {83, 85, 79, 0, 0, 0}, - {84, 65, 0, 0, 0, 0}, {84, 65, 73, 0, 0, 0}, - {84, 65, 78, 0, 0, 0}, {84, 65, 78, 71, 0, 0}, - {84, 65, 79, 0, 0, 0}, {84, 69, 0, 0, 0, 0}, - {84, 69, 78, 71, 0, 0}, {84, 73, 0, 0, 0, 0}, - {84, 73, 65, 78, 0, 0}, {84, 73, 65, 79, 0, 0}, - {84, 73, 69, 0, 0, 0}, {84, 73, 78, 71, 0, 0}, - {84, 79, 78, 71, 0, 0}, {84, 79, 85, 0, 0, 0}, - {84, 85, 0, 0, 0, 0}, {84, 85, 65, 78, 0, 0}, - {84, 85, 73, 0, 0, 0}, {84, 85, 78, 0, 0, 0}, - {84, 85, 79, 0, 0, 0}, {87, 65, 0, 0, 0, 0}, - {87, 65, 73, 0, 0, 0}, {87, 65, 78, 0, 0, 0}, - {87, 65, 78, 71, 0, 0}, {87, 69, 73, 0, 0, 0}, - {87, 69, 78, 0, 0, 0}, {87, 69, 78, 71, 0, 0}, - {87, 79, 0, 0, 0, 0}, {87, 85, 0, 0, 0, 0}, - {88, 73, 0, 0, 0, 0}, {88, 73, 65, 0, 0, 0}, - {88, 73, 65, 78, 0, 0}, {88, 73, 65, 78, 71, 0}, - {88, 73, 65, 79, 0, 0}, {88, 73, 69, 0, 0, 0}, - {88, 73, 78, 0, 0, 0}, {88, 73, 78, 71, 0, 0}, - {88, 73, 79, 78, 71, 0}, {88, 73, 85, 0, 0, 0}, - {88, 85, 0, 0, 0, 0}, {88, 85, 65, 78, 0, 0}, - {88, 85, 69, 0, 0, 0}, {88, 85, 78, 0, 0, 0}, - {89, 65, 0, 0, 0, 0}, {89, 65, 78, 0, 0, 0}, - {89, 65, 78, 71, 0, 0}, {89, 65, 79, 0, 0, 0}, - {89, 69, 0, 0, 0, 0}, {89, 73, 0, 0, 0, 0}, - {89, 73, 78, 0, 0, 0}, {89, 73, 78, 71, 0, 0}, - {89, 79, 0, 0, 0, 0}, {89, 79, 78, 71, 0, 0}, - {89, 79, 85, 0, 0, 0}, {89, 85, 0, 0, 0, 0}, - {89, 85, 65, 78, 0, 0}, {89, 85, 69, 0, 0, 0}, - {89, 85, 78, 0, 0, 0}, {74, 85, 78, 0, 0, 0}, - {89, 85, 78, 0, 0, 0}, {90, 65, 0, 0, 0, 0}, - {90, 65, 73, 0, 0, 0}, {90, 65, 78, 0, 0, 0}, - {90, 65, 78, 71, 0, 0}, {90, 65, 79, 0, 0, 0}, - {90, 69, 0, 0, 0, 0}, {90, 69, 73, 0, 0, 0}, - {90, 69, 78, 0, 0, 0}, {90, 69, 78, 71, 0, 0}, - {90, 72, 65, 0, 0, 0}, {90, 72, 65, 73, 0, 0}, - {90, 72, 65, 78, 0, 0}, {90, 72, 65, 78, 71, 0}, - {67, 72, 65, 78, 71, 0}, {90, 72, 65, 78, 71, 0}, - {90, 72, 65, 79, 0, 0}, {90, 72, 69, 0, 0, 0}, - {90, 72, 69, 78, 0, 0}, {90, 72, 69, 78, 71, 0}, - {90, 72, 73, 0, 0, 0}, {83, 72, 73, 0, 0, 0}, - {90, 72, 73, 0, 0, 0}, {90, 72, 79, 78, 71, 0}, - {90, 72, 79, 85, 0, 0}, {90, 72, 85, 0, 0, 0}, - {90, 72, 85, 65, 0, 0}, {90, 72, 85, 65, 73, 0}, - {90, 72, 85, 65, 78, 0}, {90, 72, 85, 65, 78, 71}, - {90, 72, 85, 73, 0, 0}, {90, 72, 85, 78, 0, 0}, - {90, 72, 85, 79, 0, 0}, {90, 73, 0, 0, 0, 0}, - {90, 79, 78, 71, 0, 0}, {90, 79, 85, 0, 0, 0}, - {90, 85, 0, 0, 0, 0}, {90, 85, 65, 78, 0, 0}, - {90, 85, 73, 0, 0, 0}, {90, 85, 78, 0, 0, 0}, - {90, 85, 79, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0},}; - - /** - * First and last Chinese character with known Pinyin according to zh collation - */ - private static final String FIRST_PINYIN_UNIHAN = "\u963F"; - private static final String LAST_PINYIN_UNIHAN = "\u9FFF"; - - private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA); - - private static HanziToPinyin sInstance; - private final boolean mHasChinaCollator; - - public static class Token { - /** - * Separator between target string for each source char - */ - public static final String SEPARATOR = " "; - - public static final int LATIN = 1; - public static final int PINYIN = 2; - public static final int UNKNOWN = 3; - - public Token() { - } - - public Token(int type, String source, String target) { - this.type = type; - this.source = source; - this.target = target; - } - - /** - * Type of this token, ASCII, PINYIN or UNKNOWN. - */ - public int type; - /** - * Original string before translation. - */ - public String source; - /** - * Translated string of source. For Han, target is corresponding Pinyin. Otherwise target is - * original string in source. - */ - public String target; - } - - protected HanziToPinyin(boolean hasChinaCollator) { - mHasChinaCollator = hasChinaCollator; - } - - public static HanziToPinyin getInstance() { - synchronized (HanziToPinyin.class) { - if (sInstance != null) { - return sInstance; - } - // Check if zh_CN collation data is available - final Locale[] locale = Collator.getAvailableLocales(); - for (Locale value : locale) { - if (value.equals(Locale.CHINA) || value.getLanguage().contains("zh")) { - // Do self validation just once. - if (DEBUG) { - Log.d(TAG, "Self validation. Result: " + doSelfValidation()); - } - sInstance = new HanziToPinyin(true); - return sInstance; - } - } - if (sInstance == null){//这个判断是用于处理国产ROM的兼容性问题 - if (Locale.CHINA.equals(Locale.getDefault())){ - sInstance = new HanziToPinyin(true); - return sInstance; - } - } - Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled"); - sInstance = new HanziToPinyin(false); - return sInstance; - } - } - - /** - * Validate if our internal table has some wrong value. - * - * @return true when the table looks correct. - */ - private static boolean doSelfValidation() { - char lastChar = UNIHANS[0]; - String lastString = Character.toString(lastChar); - for (char c : UNIHANS) { - if (lastChar == c) { - continue; - } - final String curString = Character.toString(c); - int cmp = COLLATOR.compare(lastString, curString); - if (cmp >= 0) { - Log.e(TAG, "Internal error in Unihan table. " + "The last string \"" + lastString - + "\" is greater than current string \"" + curString + "\"."); - return false; - } - lastString = curString; - } - return true; - } - - private Token getToken(char character) { - Token token = new Token(); - final String letter = Character.toString(character); - token.source = letter; - int offset = -1; - int cmp; - if (character < 256) { - token.type = Token.LATIN; - token.target = letter; - return token; - } else { - cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN); - if (cmp < 0) { - token.type = Token.UNKNOWN; - token.target = letter; - return token; - } else if (cmp == 0) { - token.type = Token.PINYIN; - offset = 0; - } else { - cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN); - if (cmp > 0) { - token.type = Token.UNKNOWN; - token.target = letter; - return token; - } else if (cmp == 0) { - token.type = Token.PINYIN; - offset = UNIHANS.length - 1; - } - } - } - - token.type = Token.PINYIN; - if (offset < 0) { - int begin = 0; - int end = UNIHANS.length - 1; - while (begin <= end) { - offset = (begin + end) / 2; - final String unihan = Character.toString(UNIHANS[offset]); - cmp = COLLATOR.compare(letter, unihan); - if (cmp == 0) { - break; - } else if (cmp > 0) { - begin = offset + 1; - } else { - end = offset - 1; - } - } - } - if (cmp < 0) { - offset--; - } - StringBuilder pinyin = new StringBuilder(); - for (int j = 0; j < PINYINS[offset].length && PINYINS[offset][j] != 0; j++) { - pinyin.append((char) PINYINS[offset][j]); - } - token.target = pinyin.toString(); - if (TextUtils.isEmpty(token.target)) { - token.type = Token.UNKNOWN; - token.target = token.source; - } - return token; - } - - /** - * Convert the input to a array of tokens. The sequence of ASCII or Unknown characters without - * space will be put into a Token, One Hanzi character which has pinyin will be treated as a - * Token. If these is no China collator, the empty token array is returned. - */ - public ArrayList get(final String input) { - ArrayList tokens = new ArrayList<>(); - if (!mHasChinaCollator || TextUtils.isEmpty(input)) { - // return empty tokens. - return tokens; - } - final int inputLength = input.length(); - final StringBuilder sb = new StringBuilder(); - int tokenType = Token.LATIN; - // Go through the input, create a new token when - // a. Token type changed - // b. Get the Pinyin of current charater. - // c. current character is space. - for (int i = 0; i < inputLength; i++) { - final char character = input.charAt(i); - if (character == ' ') { - if (sb.length() > 0) { - addToken(sb, tokens, tokenType); - } - } else if (character < 256) { - if (tokenType != Token.LATIN && sb.length() > 0) { - addToken(sb, tokens, tokenType); - } - tokenType = Token.LATIN; - sb.append(character); - } else { - Token t = getToken(character); - if (t.type == Token.PINYIN) { - if (sb.length() > 0) { - addToken(sb, tokens, tokenType); - } - tokens.add(t); - tokenType = Token.PINYIN; - } else { - if (tokenType != t.type && sb.length() > 0) { - addToken(sb, tokens, tokenType); - } - tokenType = t.type; - sb.append(character); - } - } - } - if (sb.length() > 0) { - addToken(sb, tokens, tokenType); - } - return tokens; - } - - private void addToken( - final StringBuilder sb, final ArrayList tokens, final int tokenType) { - String str = sb.toString(); - tokens.add(new Token(tokenType, str, str)); - sb.setLength(0); - } - - public String toPinyinString(String string) { - if (string == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - ArrayList tokens = get(string); - for (Token token : tokens) { - sb.append(token.target); - } - return sb.toString().toLowerCase(); - } -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HyperlinkText.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HyperlinkText.kt deleted file mode 100644 index 4473b828..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HyperlinkText.kt +++ /dev/null @@ -1,87 +0,0 @@ -package me.weishu.kernelsu.ui.util - -import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextLayoutResult -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.style.TextDecoration -import java.util.regex.Pattern - -@Composable -fun LinkifyText( - text: String, - modifier: Modifier = Modifier -) { - val uriHandler = LocalUriHandler.current - val layoutResult = remember { - mutableStateOf(null) - } - val linksList = extractUrls(text) - val annotatedString = buildAnnotatedString { - append(text) - linksList.forEach { - addStyle( - style = SpanStyle( - color = MaterialTheme.colorScheme.primary, - textDecoration = TextDecoration.Underline - ), - start = it.start, - end = it.end - ) - addStringAnnotation( - tag = "URL", - annotation = it.url, - start = it.start, - end = it.end - ) - } - } - Text( - text = annotatedString, - modifier = modifier.pointerInput(Unit) { - detectTapGestures { offsetPosition -> - layoutResult.value?.let { - val position = it.getOffsetForPosition(offsetPosition) - annotatedString.getStringAnnotations(position, position).firstOrNull() - ?.let { result -> - if (result.tag == "URL") { - uriHandler.openUri(result.item) - } - } - } - } - }, - onTextLayout = { layoutResult.value = it } - ) -} - -private val urlPattern: Pattern = Pattern.compile( - "(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)" - + "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*" - + "[\\p{Alnum}.,%_=?&#\\-+()\\[\\]\\*$~@!:/{};']*)", - Pattern.CASE_INSENSITIVE or Pattern.MULTILINE or Pattern.DOTALL -) - -private data class LinkInfo( - val url: String, - val start: Int, - val end: Int -) - -private fun extractUrls(text: String): List = buildList { - val matcher = urlPattern.matcher(text) - while (matcher.find()) { - val matchStart = matcher.start(1) - val matchEnd = matcher.end() - val url = text.substring(matchStart, matchEnd).replaceFirst("http://", "https://") - add(LinkInfo(url, matchStart, matchEnd)) - } -} 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 deleted file mode 100644 index 108e08f2..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt +++ /dev/null @@ -1,428 +0,0 @@ -package me.weishu.kernelsu.ui.util - -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.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 -import me.weishu.kernelsu.BuildConfig -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.ksuApp -import org.json.JSONArray -import java.io.File - - -/** - * @author weishu - * @date 2023/1/1. - */ -private const val TAG = "KsuCli" - -private fun getKsuDaemonPath(): String { - return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud.so" -} - -object KsuCli { - val SHELL: Shell = createRootShell() - val GLOBAL_MNT_SHELL: Shell = createRootShell(true) -} - -fun getRootShell(globalMnt: Boolean = false): Shell { - return if (globalMnt) KsuCli.GLOBAL_MNT_SHELL else { - KsuCli.SHELL - } -} - -inline fun withNewRootShell( - globalMnt: Boolean = false, - block: Shell.() -> T -): T { - return createRootShell(globalMnt).use(block) -} - -fun getFileNameFromUri(context: Context, uri: Uri): String? { - var fileName: String? = null - val contentResolver: ContentResolver = context.contentResolver - val cursor: Cursor? = contentResolver.query(uri, null, null, null, null) - cursor?.use { - if (it.moveToFirst()) { - fileName = it.getString(it.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)) - } - } - return fileName -} - -fun createRootShell(globalMnt: Boolean = false): Shell { - Shell.enableVerboseLogging = BuildConfig.DEBUG - val builder = Shell.Builder.create() - return try { - if (globalMnt) { - builder.build(getKsuDaemonPath(), "debug", "su", "-g") - } else { - builder.build(getKsuDaemonPath(), "debug", "su") - } - } catch (e: Throwable) { - Log.w(TAG, "ksu failed: ", e) - try { - if (globalMnt) { - builder.build("su") - } else { - builder.build("su", "-mm") - } - } catch (e: Throwable) { - Log.e(TAG, "su failed: ", e) - builder.build("sh") - } - } -} - -fun execKsud(args: String, newShell: Boolean = false): Boolean { - return if (newShell) { - withNewRootShell { - ShellUtils.fastCmdResult(this, "${getKsuDaemonPath()} $args") - } - } else { - ShellUtils.fastCmdResult(getRootShell(), "${getKsuDaemonPath()} $args") - } -} - -fun install() { - val start = SystemClock.elapsedRealtime() - val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so").absolutePath - val result = execKsud("install --magiskboot $magiskboot", true) - Log.w(TAG, "install result: $result, cost: ${SystemClock.elapsedRealtime() - start}ms") -} - -fun listModules(): String { - val shell = getRootShell() - - val out = - shell.newJob().add("${getKsuDaemonPath()} module list").to(ArrayList(), null).exec().out - return out.joinToString("\n").ifBlank { "[]" } -} - -fun getModuleCount(): Int { - val result = listModules() - runCatching { - val array = JSONArray(result) - return array.length() - }.getOrElse { return 0 } -} - -fun getSuperuserCount(): Int { - return Natives.allowList.size -} - -fun toggleModule(id: String, enable: Boolean): Boolean { - val cmd = if (enable) { - "module enable $id" - } else { - "module disable $id" - } - val result = execKsud(cmd, true) - Log.i(TAG, "$cmd result: $result") - return result -} - -fun uninstallModule(id: String): Boolean { - val cmd = "module uninstall $id" - val result = execKsud(cmd, true) - Log.i(TAG, "uninstall module $id result: $result") - return result -} - -private fun flashWithIO( - cmd: String, - onStdout: (String) -> Unit, - onStderr: (String) -> Unit -): Shell.Result { - - val stdoutCallback: CallbackList = object : CallbackList() { - override fun onAddElement(s: String?) { - onStdout(s ?: "") - } - } - - val stderrCallback: CallbackList = object : CallbackList() { - override fun onAddElement(s: String?) { - onStderr(s ?: "") - } - } - - return withNewRootShell { - newJob().add(cmd).to(stdoutCallback, stderrCallback).exec() - } -} - -fun flashModule( - uri: Uri, - onFinish: (Boolean, Int) -> Unit, - onStdout: (String) -> Unit, - onStderr: (String) -> Unit -): Boolean { - val resolver = ksuApp.contentResolver - with(resolver.openInputStream(uri)) { - val file = File(ksuApp.cacheDir, "module.zip") - file.outputStream().use { output -> - this?.copyTo(output) - } - val cmd = "module install ${file.absolutePath}" - val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr) - Log.i("KernelSU", "install module $uri result: $result") - - file.delete() - - onFinish(result.isSuccess, result.code) - return result.isSuccess - } -} - -fun restoreBoot( - onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit -): Boolean { - val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") - val result = flashWithIO("${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot", onStdout, onStderr) - onFinish(result.isSuccess, result.code) - return result.isSuccess -} - -fun uninstallPermanently( - onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit -): Boolean { - val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") - val result = flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr) - onFinish(result.isSuccess, result.code) - return result.isSuccess -} - -suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) { - execKsud("module shrink", true) -} - -@Parcelize -sealed class LkmSelection : Parcelable { - data class LkmUri(val uri: Uri) : LkmSelection() - data class KmiString(val value: String) : LkmSelection() - data object KmiNone : LkmSelection() -} - -fun installBoot( - bootUri: Uri?, - lkm: LkmSelection, - ota: Boolean, - onFinish: (Boolean, Int) -> Unit, - onStdout: (String) -> Unit, - onStderr: (String) -> Unit, -): Boolean { - val resolver = ksuApp.contentResolver - - val bootFile = bootUri?.let { uri -> - with(resolver.openInputStream(uri)) { - val bootFile = File(ksuApp.cacheDir, "boot.img") - bootFile.outputStream().use { output -> - this?.copyTo(output) - } - - bootFile - } - } - - val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") - var cmd = "boot-patch --magiskboot ${magiskboot.absolutePath}" - - cmd += if (bootFile == null) { - // no boot.img, use -f to force install - " -f" - } else { - " -b ${bootFile.absolutePath}" - } - - if (ota) { - cmd += " -u" - } - - var lkmFile: File? = null - when (lkm) { - is LkmSelection.LkmUri -> { - lkmFile = with(resolver.openInputStream(lkm.uri)) { - val file = File(ksuApp.cacheDir, "kernelsu-tmp-lkm.ko") - file.outputStream().use { output -> - this?.copyTo(output) - } - - file - } - cmd += " -m ${lkmFile.absolutePath}" - } - - is LkmSelection.KmiString -> { - cmd += " --kmi ${lkm.value}" - } - - LkmSelection.KmiNone -> { - // do nothing - } - } - - // output dir - val downloadsDir = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) - cmd += " -o $downloadsDir" - - val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr) - Log.i("KernelSU", "install boot result: ${result.isSuccess}") - - bootFile?.delete() - lkmFile?.delete() - - // if boot uri is empty, it is direct install, when success, we should show reboot button - onFinish(bootUri == null && result.isSuccess, result.code) - return result.isSuccess -} - -fun reboot(reason: String = "") { - val shell = getRootShell() - if (reason == "recovery") { - // KEYCODE_POWER = 26, hide incorrect "Factory data reset" message - ShellUtils.fastCmd(shell, "/system/bin/input keyevent 26") - } - ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason") -} - -fun rootAvailable(): Boolean { - val shell = getRootShell() - return shell.isRoot -} - -fun isAbDevice(): Boolean { - val shell = getRootShell() - return ShellUtils.fastCmd(shell, "getprop ro.build.ab_update").trim().toBoolean() -} - -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 -} - -suspend fun getCurrentKmi(): String = withContext(Dispatchers.IO) { - val shell = getRootShell() - val cmd = "boot-info current-kmi" - ShellUtils.fastCmd(shell, "${getKsuDaemonPath()} $cmd") -} - -suspend fun getSupportedKmis(): List = withContext(Dispatchers.IO) { - val shell = getRootShell() - val cmd = "boot-info supported-kmi" - val out = shell.newJob().add("${getKsuDaemonPath()} $cmd").to(ArrayList(), null).exec().out - out.filter { it.isNotBlank() }.map { it.trim() } -} - -fun overlayFsAvailable(): Boolean { - val shell = getRootShell() - // check /proc/filesystems - return ShellUtils.fastCmdResult(shell, "cat /proc/filesystems | grep overlay") -} - -fun hasMagisk(): Boolean { - val shell = getRootShell(true) - val result = shell.newJob().add("which magisk").exec() - Log.i(TAG, "has magisk: ${result.isSuccess}") - return result.isSuccess -} - -fun isSepolicyValid(rules: String?): Boolean { - if (rules == null) { - return true - } - val shell = getRootShell() - val result = - shell.newJob().add("${getKsuDaemonPath()} sepolicy check '$rules'").to(ArrayList(), null) - .exec() - return result.isSuccess -} - -fun getSepolicy(pkg: String): String { - val shell = getRootShell() - val result = - shell.newJob().add("${getKsuDaemonPath()} profile get-sepolicy $pkg").to(ArrayList(), null) - .exec() - Log.i(TAG, "code: ${result.code}, out: ${result.out}, err: ${result.err}") - return result.out.joinToString("\n") -} - -fun setSepolicy(pkg: String, rules: String): Boolean { - val shell = getRootShell() - val result = shell.newJob().add("${getKsuDaemonPath()} profile set-sepolicy $pkg '$rules'") - .to(ArrayList(), null).exec() - Log.i(TAG, "set sepolicy result: ${result.code}") - return result.isSuccess -} - -fun listAppProfileTemplates(): List { - val shell = getRootShell() - return shell.newJob().add("${getKsuDaemonPath()} profile list-templates").to(ArrayList(), null) - .exec().out -} - -fun getAppProfileTemplate(id: String): String { - val shell = getRootShell() - return shell.newJob().add("${getKsuDaemonPath()} profile get-template '${id}'") - .to(ArrayList(), null).exec().out.joinToString("\n") -} - -fun setAppProfileTemplate(id: String, template: String): Boolean { - val shell = getRootShell() - val escapedTemplate = template.replace("\"", "\\\"") - val cmd = """${getKsuDaemonPath()} profile set-template "$id" "$escapedTemplate'"""" - return shell.newJob().add(cmd) - .to(ArrayList(), null).exec().isSuccess -} - -fun deleteAppProfileTemplate(id: String): Boolean { - val shell = getRootShell() - return shell.newJob().add("${getKsuDaemonPath()} profile delete-template '${id}'") - .to(ArrayList(), null).exec().isSuccess -} - -fun forceStopApp(packageName: String) { - val shell = getRootShell() - val result = shell.newJob().add("am force-stop $packageName").exec() - Log.i(TAG, "force stop $packageName result: $result") -} - -fun launchApp(packageName: String) { - - val shell = getRootShell() - val result = - shell.newJob() - .add("cmd package resolve-activity --brief $packageName | tail -n 1 | xargs cmd activity start-activity -n") - .exec() - Log.i(TAG, "launch $packageName result: $result") -} - -fun restartApp(packageName: String) { - forceStopApp(packageName) - launchApp(packageName) -} 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 deleted file mode 100644 index 19eb1df1..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt +++ /dev/null @@ -1,115 +0,0 @@ -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 -import java.time.format.DateTimeFormatter - -fun getBugreportFile(context: Context): File { - - val bugreportDir = File(context.cacheDir, "bugreport") - bugreportDir.mkdirs() - - val dmesgFile = File(bugreportDir, "dmesg.txt") - val logcatFile = File(bugreportDir, "logcat.txt") - val tombstonesFile = File(bugreportDir, "tombstones.tar.gz") - val dropboxFile = File(bugreportDir, "dropbox.tar.gz") - val pstoreFile = File(bugreportDir, "pstore.tar.gz") - // Xiaomi/Readmi devices have diag in /data/vendor/diag - val diagFile = File(bugreportDir, "diag.tar.gz") - val opulsFile = File(bugreportDir, "opuls.tar.gz") - val bootlogFile = File(bugreportDir, "bootlog.tar.gz") - val mountsFile = File(bugreportDir, "mounts.txt") - val fileSystemsFile = File(bugreportDir, "filesystems.txt") - val adbFileTree = File(bugreportDir, "adb_tree.txt") - val adbFileDetails = File(bugreportDir, "adb_details.txt") - val ksuFileSize = File(bugreportDir, "ksu_size.txt") - val appListFile = File(bugreportDir, "packages.txt") - val propFile = File(bugreportDir, "props.txt") - val allowListFile = File(bugreportDir, "allowlist.bin") - val procModules = File(bugreportDir, "proc_modules.txt") - val bootConfig = File(bugreportDir, "boot_config.txt") - val kernelConfig = File(bugreportDir, "defconfig.gz") - - val shell = getRootShell(true) - - shell.newJob().add("dmesg > ${dmesgFile.absolutePath}").exec() - shell.newJob().add("logcat -d > ${logcatFile.absolutePath}").exec() - shell.newJob().add("tar -czf ${tombstonesFile.absolutePath} -C /data/tombstones .").exec() - shell.newJob().add("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec() - shell.newJob().add("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec() - shell.newJob().add("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag . --exclude=./minidump.gz").exec() - shell.newJob().add("tar -czf ${opulsFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec() - shell.newJob().add("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec() - - shell.newJob().add("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec() - shell.newJob().add("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec() - shell.newJob().add("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec() - shell.newJob().add("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec() - shell.newJob().add("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec() - shell.newJob().add("cp /data/system/packages.list ${appListFile.absolutePath}").exec() - shell.newJob().add("getprop > ${propFile.absolutePath}").exec() - shell.newJob().add("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec() - shell.newJob().add("cp /proc/modules ${procModules.absolutePath}").exec() - shell.newJob().add("cp /proc/bootconfig ${bootConfig.absolutePath}").exec() - shell.newJob().add("cp /proc/config.gz ${kernelConfig.absolutePath}").exec() - - val selinux = ShellUtils.fastCmd(shell, "getenforce") - - // basic information - val buildInfo = File(bugreportDir, "basic.txt") - PrintWriter(FileWriter(buildInfo)).use { pw -> - pw.println("Kernel: ${System.getProperty("os.version")}") - pw.println("BRAND: " + Build.BRAND) - pw.println("MODEL: " + Build.MODEL) - pw.println("PRODUCT: " + Build.PRODUCT) - pw.println("MANUFACTURER: " + Build.MANUFACTURER) - pw.println("SDK: " + Build.VERSION.SDK_INT) - pw.println("PREVIEW_SDK: " + Build.VERSION.PREVIEW_SDK_INT) - pw.println("FINGERPRINT: " + Build.FINGERPRINT) - pw.println("DEVICE: " + Build.DEVICE) - pw.println("Manager: " + getManagerVersion(context)) - pw.println("SELinux: $selinux") - - val uname = Os.uname() - pw.println("KernelRelease: ${uname.release}") - pw.println("KernelVersion: ${uname.version}") - pw.println("Machine: ${uname.machine}") - pw.println("Nodename: ${uname.nodename}") - pw.println("Sysname: ${uname.sysname}") - - val ksuKernel = Natives.version - pw.println("KernelSU: $ksuKernel") - val safeMode = Natives.isSafeMode - pw.println("SafeMode: $safeMode") - val lkmMode = Natives.isLkmMode - pw.println("LKM: $lkmMode") - } - - // modules - val modulesFile = File(bugreportDir, "modules.json") - modulesFile.writeText(listModules()) - - val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH_mm") - val current = LocalDateTime.now().format(formatter) - - val targetFile = File(context.cacheDir, "KernelSU_bugreport_${current}.tar.gz") - - shell.newJob().add("tar czf ${targetFile.absolutePath} -C ${bugreportDir.absolutePath} .").exec() - shell.newJob().add("rm -rf ${bugreportDir.absolutePath}").exec() - shell.newJob().add("chmod 0644 ${targetFile.absolutePath}").exec() - - return targetFile -} - 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 deleted file mode 100644 index 78346dd9..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt +++ /dev/null @@ -1,34 +0,0 @@ -package me.weishu.kernelsu.ui.util - -import androidx.compose.ui.res.stringResource -import androidx.compose.runtime.Composable -import com.topjohnwu.superuser.Shell -import me.weishu.kernelsu.R - -@Composable -fun getSELinuxStatus(): String { - val shell = Shell.Builder.create() - .setFlags(Shell.FLAG_REDIRECT_STDERR) - .build("sh") - - val list = ArrayList() - val result = shell.use { - it.newJob().add("getenforce").to(list, list).exec() - } - val output = result.out.joinToString("\n").trim() - - if (result.isSuccess) { - return when (output) { - "Enforcing" -> stringResource(R.string.selinux_status_enforcing) - "Permissive" -> stringResource(R.string.selinux_status_permissive) - "Disabled" -> stringResource(R.string.selinux_status_disabled) - else -> stringResource(R.string.selinux_status_unknown) - } - } - - return if (output.endsWith("Permission denied")) { - stringResource(R.string.selinux_status_enforcing) - } else { - stringResource(R.string.selinux_status_unknown) - } -} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/LatestVersionInfo.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/LatestVersionInfo.kt deleted file mode 100644 index 374b3853..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/LatestVersionInfo.kt +++ /dev/null @@ -1,7 +0,0 @@ -package me.weishu.kernelsu.ui.util.module - -data class LatestVersionInfo( - val versionCode : Int = 0, - val downloadUrl : String = "", - val changelog : String = "" -) 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 deleted file mode 100644 index 013453fb..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt +++ /dev/null @@ -1,161 +0,0 @@ -package me.weishu.kernelsu.ui.viewmodel - -import android.os.SystemClock -import android.util.Log -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import me.weishu.kernelsu.ui.util.listModules -import me.weishu.kernelsu.ui.util.overlayFsAvailable -import org.json.JSONArray -import org.json.JSONObject -import java.text.Collator -import java.util.Locale - -class ModuleViewModel : ViewModel() { - - companion object { - private const val TAG = "ModuleViewModel" - private var modules by mutableStateOf>(emptyList()) - } - - class ModuleInfo( - val id: String, - val name: String, - val author: String, - val version: String, - val versionCode: Int, - val description: String, - val enabled: Boolean, - val update: Boolean, - val remove: Boolean, - val updateJson: String, - val hasWebUi: Boolean, - ) - - data class ModuleUpdateInfo( - val version: String, - val versionCode: Int, - val zipUrl: String, - val changelog: String, - ) - - var isRefreshing by mutableStateOf(false) - private set - - var isOverlayAvailable by mutableStateOf(overlayFsAvailable()) - private set - - val moduleList by derivedStateOf { - val comparator = compareBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id) - modules.sortedWith(comparator).also { - isRefreshing = false - } - } - - var isNeedRefresh by mutableStateOf(false) - private set - - fun markNeedRefresh() { - isNeedRefresh = true - } - - fun fetchModuleList() { - viewModelScope.launch(Dispatchers.IO) { - isRefreshing = true - - val oldModuleList = modules - - val start = SystemClock.elapsedRealtime() - - kotlin.runCatching { - isOverlayAvailable = overlayFsAvailable() - - val result = listModules() - - Log.i(TAG, "result: $result") - - val array = JSONArray(result) - modules = (0 until array.length()) - .asSequence() - .map { array.getJSONObject(it) } - .map { obj -> - ModuleInfo( - obj.getString("id"), - - obj.optString("name"), - obj.optString("author", "Unknown"), - obj.optString("version", "Unknown"), - obj.optInt("versionCode", 0), - obj.optString("description"), - obj.getBoolean("enabled"), - obj.getBoolean("update"), - obj.getBoolean("remove"), - obj.optString("updateJson"), - obj.optBoolean("web") - ) - }.toList() - isNeedRefresh = false - }.onFailure { e -> - Log.e(TAG, "fetchModuleList: ", e) - isRefreshing = false - } - - // when both old and new is kotlin.collections.EmptyList - // moduleList update will don't trigger - if (oldModuleList === modules) { - isRefreshing = false - } - - Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules") - } - } - - fun checkUpdate(m: ModuleInfo): Triple { - val empty = Triple("", "", "") - if (m.updateJson.isEmpty() || m.remove || m.update || !m.enabled) { - return empty - } - // download updateJson - val result = kotlin.runCatching { - val url = m.updateJson - Log.i(TAG, "checkUpdate url: $url") - val response = okhttp3.OkHttpClient() - .newCall( - okhttp3.Request.Builder() - .url(url) - .build() - ).execute() - Log.d(TAG, "checkUpdate code: ${response.code}") - if (response.isSuccessful) { - response.body?.string() ?: "" - } else { - "" - } - }.getOrDefault("") - Log.i(TAG, "checkUpdate result: $result") - - if (result.isEmpty()) { - return empty - } - - val updateJson = kotlin.runCatching { - JSONObject(result) - }.getOrNull() ?: return empty - - val version = updateJson.optString("version", "") - val versionCode = updateJson.optInt("versionCode", 0) - val zipUrl = updateJson.optString("zipUrl", "") - val changelog = updateJson.optString("changelog", "") - if (versionCode <= m.versionCode || zipUrl.isEmpty()) { - return empty - } - - return Triple(zipUrl, version, changelog) - } -} 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 deleted file mode 100644 index 37e05aa8..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt +++ /dev/null @@ -1,160 +0,0 @@ -package me.weishu.kernelsu.ui.viewmodel - -import android.content.ComponentName -import android.content.Intent -import android.content.ServiceConnection -import android.content.pm.ApplicationInfo -import android.content.pm.PackageInfo -import android.os.IBinder -import android.os.Parcelable -import android.os.SystemClock -import android.util.Log -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import com.topjohnwu.superuser.Shell -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.parcelize.Parcelize -import me.weishu.kernelsu.IKsuInterface -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.ksuApp -import me.weishu.kernelsu.ui.KsuService -import me.weishu.kernelsu.ui.util.HanziToPinyin -import me.weishu.kernelsu.ui.util.KsuCli -import java.text.Collator -import java.util.* -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine - -class SuperUserViewModel : ViewModel() { - - companion object { - private const val TAG = "SuperUserViewModel" - private var apps by mutableStateOf>(emptyList()) - } - - @Parcelize - data class AppInfo( - val label: String, - val packageInfo: PackageInfo, - val profile: Natives.Profile?, - ) : Parcelable { - val packageName: String - get() = packageInfo.packageName - val uid: Int - get() = packageInfo.applicationInfo.uid - - val allowSu: Boolean - get() = profile != null && profile.allowSu - val hasCustomProfile: Boolean - get() { - if (profile == null) { - return false - } - - return if (profile.allowSu) { - !profile.rootUseDefault - } else { - !profile.nonRootUseDefault - } - } - } - - var search by mutableStateOf("") - var showSystemApps by mutableStateOf(false) - var isRefreshing by mutableStateOf(false) - private set - - private val sortedList by derivedStateOf { - val comparator = compareBy { - when { - it.allowSu -> 0 - it.hasCustomProfile -> 1 - else -> 2 - } - }.then(compareBy(Collator.getInstance(Locale.getDefault()), AppInfo::label)) - apps.sortedWith(comparator).also { - isRefreshing = false - } - } - - val appList by derivedStateOf { - sortedList.filter { - it.label.contains(search, true) || it.packageName.contains( - search, - true - ) || HanziToPinyin.getInstance() - .toPinyinString(it.label).contains(search, true) - }.filter { - it.uid == 2000 // Always show shell - || showSystemApps || it.packageInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0 - } - } - - private suspend inline fun connectKsuService( - crossinline onDisconnect: () -> Unit = {} - ): Pair = suspendCoroutine { - val connection = object : ServiceConnection { - override fun onServiceDisconnected(name: ComponentName?) { - onDisconnect() - } - - override fun onServiceConnected(name: ComponentName?, binder: IBinder?) { - it.resume(binder as IBinder to this) - } - } - - val intent = Intent(ksuApp, KsuService::class.java) - - val task = KsuService.bindOrTask( - intent, - Shell.EXECUTOR, - connection, - ) - val shell = KsuCli.SHELL - task?.let { it1 -> shell.execTask(it1) } - } - - private fun stopKsuService() { - val intent = Intent(ksuApp, KsuService::class.java) - KsuService.stop(intent) - } - - suspend fun fetchAppList() { - - isRefreshing = true - - val result = connectKsuService { - Log.w(TAG, "KsuService disconnected") - } - - withContext(Dispatchers.IO) { - val pm = ksuApp.packageManager - val start = SystemClock.elapsedRealtime() - - val binder = result.first - val allPackages = IKsuInterface.Stub.asInterface(binder).getPackages(0) - - withContext(Dispatchers.Main) { - stopKsuService() - } - - val packages = allPackages.list - - apps = packages.map { - val appInfo = it.applicationInfo - val uid = appInfo.uid - val profile = Natives.getAppProfile(it.packageName, uid) - AppInfo( - label = appInfo.loadLabel(pm).toString(), - packageInfo = it, - profile = profile, - ) - }.filter { it.packageName != ksuApp.packageName } - Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}") - } - } -} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/TemplateViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/TemplateViewModel.kt deleted file mode 100644 index cbed82f2..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/TemplateViewModel.kt +++ /dev/null @@ -1,328 +0,0 @@ -package me.weishu.kernelsu.ui.viewmodel - -import android.os.Parcelable -import android.util.Log -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.parcelize.Parcelize -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.profile.Capabilities -import me.weishu.kernelsu.profile.Groups -import me.weishu.kernelsu.ui.util.getAppProfileTemplate -import me.weishu.kernelsu.ui.util.listAppProfileTemplates -import me.weishu.kernelsu.ui.util.setAppProfileTemplate -import okhttp3.OkHttpClient -import okhttp3.Request -import org.json.JSONArray -import org.json.JSONObject -import java.text.Collator -import java.util.Locale -import java.util.concurrent.TimeUnit - - -/** - * @author weishu - * @date 2023/10/20. - */ -const val TEMPLATE_INDEX_URL = "https://kernelsu.org/templates/index.json" -const val TEMPLATE_URL = "https://kernelsu.org/templates/%s" - -const val TAG = "TemplateViewModel" - -class TemplateViewModel : ViewModel() { - companion object { - - private var templates by mutableStateOf>(emptyList()) - } - - @Parcelize - data class TemplateInfo( - val id: String = "", - val name: String = "", - val description: String = "", - val author: String = "", - val local: Boolean = true, - - val namespace: Int = Natives.Profile.Namespace.INHERITED.ordinal, - val uid: Int = Natives.ROOT_UID, - val gid: Int = Natives.ROOT_GID, - val groups: List = mutableListOf(), - val capabilities: List = mutableListOf(), - val context: String = Natives.KERNEL_SU_DOMAIN, - val rules: List = mutableListOf(), - ) : Parcelable - - var isRefreshing by mutableStateOf(false) - private set - - val templateList by derivedStateOf { - val comparator = compareBy(TemplateInfo::local).reversed().then( - compareBy( - Collator.getInstance(Locale.getDefault()), TemplateInfo::id - ) - ) - templates.sortedWith(comparator).apply { - isRefreshing = false - } - } - - suspend fun fetchTemplates(sync: Boolean = false) { - isRefreshing = true - withContext(Dispatchers.IO) { - val localTemplateIds = listAppProfileTemplates() - Log.i(TAG, "localTemplateIds: $localTemplateIds") - if (localTemplateIds.isEmpty() || sync) { - // if no templates, fetch remote templates - fetchRemoteTemplates() - } - - // fetch templates again - templates = listAppProfileTemplates().mapNotNull(::getTemplateInfoById) - - isRefreshing = false - } - } - - suspend fun importTemplates( - templates: String, - onSuccess: suspend () -> Unit, - onFailure: suspend (String) -> Unit - ) { - withContext(Dispatchers.IO) { - runCatching { - JSONArray(templates) - }.getOrElse { - runCatching { - val json = JSONObject(templates) - JSONArray().apply { put(json) } - }.getOrElse { - onFailure("invalid templates: $templates") - return@withContext - } - }.let { - 0.until(it.length()).forEach { i -> - runCatching { - val template = it.getJSONObject(i) - val id = template.getString("id") - template.put("local", true) - setAppProfileTemplate(id, template.toString()) - }.onFailure { e -> - Log.e(TAG, "ignore invalid template: $it", e) - } - } - onSuccess() - } - } - } - - suspend fun exportTemplates(onTemplateEmpty: () -> Unit, callback: (String) -> Unit) { - withContext(Dispatchers.IO) { - val templates = listAppProfileTemplates().mapNotNull(::getTemplateInfoById).filter { - it.local - } - templates.ifEmpty { - onTemplateEmpty() - return@withContext - } - JSONArray(templates.map { - it.toJSON() - }).toString().let(callback) - } - } -} - -private fun fetchRemoteTemplates() { - runCatching { - val client: OkHttpClient = OkHttpClient.Builder() - .connectTimeout(5, TimeUnit.SECONDS) - .writeTimeout(5, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) - .build() - - client.newCall( - Request.Builder().url(TEMPLATE_INDEX_URL).build() - ).execute().use { response -> - if (!response.isSuccessful) { - return - } - val remoteTemplateIds = JSONArray(response.body!!.string()) - Log.i(TAG, "fetchRemoteTemplates: $remoteTemplateIds") - 0.until(remoteTemplateIds.length()).forEach { i -> - val id = remoteTemplateIds.getString(i) - Log.i(TAG, "fetch template: $id") - val templateJson = client.newCall( - Request.Builder().url(TEMPLATE_URL.format(id)).build() - ).runCatching { - execute().use { response -> - if (!response.isSuccessful) { - return@forEach - } - response.body!!.string() - } - }.getOrNull() ?: return@forEach - Log.i(TAG, "template: $templateJson") - - // validate remote template - runCatching { - val json = JSONObject(templateJson) - fromJSON(json)?.let { - // force local template - json.put("local", false) - setAppProfileTemplate(id, json.toString()) - } - }.onFailure { - Log.e(TAG, "ignore invalid template: $it", it) - return@forEach - } - } - } - }.onFailure { Log.e(TAG, "fetchRemoteTemplates: $it", it) } -} - -@Suppress("UNCHECKED_CAST") -private fun JSONArray.mapCatching( - transform: (T) -> R, onFail: (Throwable) -> Unit -): List { - return List(length()) { i -> get(i) as T }.mapNotNull { element -> - runCatching { - transform(element) - }.onFailure(onFail).getOrNull() - } -} - -private inline fun > getEnumOrdinals( - jsonArray: JSONArray?, enumClass: Class -): List { - return jsonArray?.mapCatching({ name -> - enumValueOf(name.uppercase()) - }, { - Log.e(TAG, "ignore invalid enum ${enumClass.simpleName}: $it", it) - }).orEmpty() -} - -fun getTemplateInfoById(id: String): TemplateViewModel.TemplateInfo? { - return runCatching { - fromJSON(JSONObject(getAppProfileTemplate(id))) - }.onFailure { - Log.e(TAG, "ignore invalid template: $it", it) - }.getOrNull() -} - -private fun getLocaleString(json: JSONObject, key: String): String { - val fallback = json.getString(key) - val locale = Locale.getDefault() - val localeKey = "${locale.language}_${locale.country}" - json.optJSONObject("locales")?.let { - // check locale first - it.optJSONObject(localeKey)?.let { json-> - return json.optString(key, fallback) - } - // fallback to language - it.optJSONObject(locale.language)?.let { json-> - return json.optString(key, fallback) - } - } - return fallback -} - -private fun fromJSON(templateJson: JSONObject): TemplateViewModel.TemplateInfo? { - return runCatching { - val groupsJsonArray = templateJson.optJSONArray("groups") - val capabilitiesJsonArray = templateJson.optJSONArray("capabilities") - val context = templateJson.optString("context").takeIf { it.isNotEmpty() } - ?: Natives.KERNEL_SU_DOMAIN - val namespace = templateJson.optString("namespace").takeIf { it.isNotEmpty() } - ?: Natives.Profile.Namespace.INHERITED.name - - val rulesJsonArray = templateJson.optJSONArray("rules") - val templateInfo = TemplateViewModel.TemplateInfo( - id = templateJson.getString("id"), - name = getLocaleString(templateJson, "name"), - description = getLocaleString(templateJson, "description"), - author = templateJson.optString("author"), - local = templateJson.optBoolean("local"), - namespace = Natives.Profile.Namespace.valueOf( - namespace.uppercase() - ).ordinal, - uid = templateJson.optInt("uid", Natives.ROOT_UID), - gid = templateJson.optInt("gid", Natives.ROOT_GID), - groups = getEnumOrdinals(groupsJsonArray, Groups::class.java).map { it.gid }, - capabilities = getEnumOrdinals( - capabilitiesJsonArray, Capabilities::class.java - ).map { it.cap }, - context = context, - rules = rulesJsonArray?.mapCatching({ it }, { - Log.e(TAG, "ignore invalid rule: $it", it) - }).orEmpty() - ) - templateInfo - }.onFailure { - Log.e(TAG, "ignore invalid template: $it", it) - }.getOrNull() -} - -fun TemplateViewModel.TemplateInfo.toJSON(): JSONObject { - val template = this - return JSONObject().apply { - - put("id", template.id) - put("name", template.name.ifBlank { template.id }) - put("description", template.description.ifBlank { template.id }) - if (template.author.isNotEmpty()) { - put("author", template.author) - } - put("namespace", Natives.Profile.Namespace.entries[template.namespace].name) - put("uid", template.uid) - put("gid", template.gid) - - if (template.groups.isNotEmpty()) { - put("groups", JSONArray( - Groups.entries.filter { - template.groups.contains(it.gid) - }.map { - it.name - } - )) - } - - if (template.capabilities.isNotEmpty()) { - put("capabilities", JSONArray( - Capabilities.entries.filter { - template.capabilities.contains(it.cap) - }.map { - it.name - } - )) - } - - if (template.context.isNotEmpty()) { - put("context", template.context) - } - - if (template.rules.isNotEmpty()) { - put("rules", JSONArray(template.rules)) - } - } -} - -@Suppress("unused") -fun generateTemplates() { - val templateJson = JSONObject() - templateJson.put("id", "com.example") - templateJson.put("name", "Example") - templateJson.put("description", "This is an example template") - templateJson.put("local", true) - templateJson.put("namespace", Natives.Profile.Namespace.INHERITED.name) - templateJson.put("uid", 0) - templateJson.put("gid", 0) - - templateJson.put("groups", JSONArray().apply { put(Groups.INET.name) }) - templateJson.put("capabilities", JSONArray().apply { put(Capabilities.CAP_NET_RAW.name) }) - templateJson.put("context", "u:r:su:s0") - Log.i(TAG, "$templateJson") -} \ No newline at end of file diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/MimeUtil.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/MimeUtil.java deleted file mode 100644 index 1fc2f4a4..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/MimeUtil.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package me.weishu.kernelsu.ui.webui; - -import java.net.URLConnection; - -class MimeUtil { - - public static String getMimeFromFileName(String fileName) { - if (fileName == null) { - return null; - } - - // Copying the logic and mapping that Chromium follows. - // First we check against the OS (this is a limited list by default) - // but app developers can extend this. - // We then check against a list of hardcoded mime types above if the - // OS didn't provide a result. - String mimeType = URLConnection.guessContentTypeFromName(fileName); - - if (mimeType != null) { - return mimeType; - } - - return guessHardcodedMime(fileName); - } - - // We should keep this map in sync with the lists under - // //net/base/mime_util.cc in Chromium. - // A bunch of the mime types don't really apply to Android land - // like word docs so feel free to filter out where necessary. - private static String guessHardcodedMime(String fileName) { - int finalFullStop = fileName.lastIndexOf('.'); - if (finalFullStop == -1) { - return null; - } - - final String extension = fileName.substring(finalFullStop + 1).toLowerCase(); - - return switch (extension) { - case "webm" -> "video/webm"; - case "mpeg", "mpg" -> "video/mpeg"; - case "mp3" -> "audio/mpeg"; - case "wasm" -> "application/wasm"; - case "xhtml", "xht", "xhtm" -> "application/xhtml+xml"; - case "flac" -> "audio/flac"; - case "ogg", "oga", "opus" -> "audio/ogg"; - case "wav" -> "audio/wav"; - case "m4a" -> "audio/x-m4a"; - case "gif" -> "image/gif"; - case "jpeg", "jpg", "jfif", "pjpeg", "pjp" -> "image/jpeg"; - case "png" -> "image/png"; - case "apng" -> "image/apng"; - case "svg", "svgz" -> "image/svg+xml"; - case "webp" -> "image/webp"; - case "mht", "mhtml" -> "multipart/related"; - case "css" -> "text/css"; - case "html", "htm", "shtml", "shtm", "ehtml" -> "text/html"; - case "js", "mjs" -> "application/javascript"; - case "xml" -> "text/xml"; - case "mp4", "m4v" -> "video/mp4"; - case "ogv", "ogm" -> "video/ogg"; - case "ico" -> "image/x-icon"; - case "woff" -> "application/font-woff"; - case "gz", "tgz" -> "application/gzip"; - case "json" -> "application/json"; - case "pdf" -> "application/pdf"; - case "zip" -> "application/zip"; - case "bmp" -> "image/bmp"; - case "tiff", "tif" -> "image/tiff"; - default -> null; - }; - } -} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java deleted file mode 100644 index ff450e8e..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java +++ /dev/null @@ -1,191 +0,0 @@ -package me.weishu.kernelsu.ui.webui; - -import android.content.Context; -import android.util.Log; -import android.webkit.WebResourceResponse; - -import androidx.annotation.NonNull; -import androidx.annotation.WorkerThread; -import androidx.webkit.WebViewAssetLoader; - -import com.topjohnwu.superuser.Shell; -import com.topjohnwu.superuser.io.SuFile; -import com.topjohnwu.superuser.io.SuFileInputStream; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.GZIPInputStream; - -/** - * Handler class to open files from file system by root access - * For more information about android storage please refer to - * Android Developers - * Docs: Data and file storage overview. - *

- * To avoid leaking user or app data to the web, make sure to choose {@code directory} - * carefully, and assume any file under this directory could be accessed by any web page subject - * to same-origin rules. - *

- * A typical usage would be like: - *

- * File publicDir = new File(context.getFilesDir(), "public");
- * // Host "files/public/" in app's data directory under:
- * // http://appassets.androidplatform.net/public/...
- * WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
- *          .addPathHandler("/public/", new InternalStoragePathHandler(context, publicDir))
- *          .build();
- * 
- */ -public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler { - private static final String TAG = "SuFilePathHandler"; - - /** - * Default value to be used as MIME type if guessing MIME type failed. - */ - public static final String DEFAULT_MIME_TYPE = "text/plain"; - - /** - * Forbidden subdirectories of {@link Context#getDataDir} that cannot be exposed by this - * handler. They are forbidden as they often contain sensitive information. - *

- * Note: Any future addition to this list will be considered breaking changes to the API. - */ - private static final String[] FORBIDDEN_DATA_DIRS = - new String[] {"/data/data", "/data/system"}; - - @NonNull - private final File mDirectory; - - private final Shell mShell; - - /** - * Creates PathHandler for app's internal storage. - * The directory to be exposed must be inside either the application's internal data - * directory {@link Context#getDataDir} or cache directory {@link Context#getCacheDir}. - * External storage is not supported for security reasons, as other apps with - * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} may be able to modify the - * files. - *

- * Exposing the entire data or cache directory is not permitted, to avoid accidentally - * exposing sensitive application files to the web. Certain existing subdirectories of - * {@link Context#getDataDir} are also not permitted as they are often sensitive. - * These files are ({@code "app_webview/"}, {@code "databases/"}, {@code "lib/"}, - * {@code "shared_prefs/"} and {@code "code_cache/"}). - *

- * The application should typically use a dedicated subdirectory for the files it intends to - * expose and keep them separate from other files. - * - * @param context {@link Context} that is used to access app's internal storage. - * @param directory the absolute path of the exposed app internal storage directory from - * which files can be loaded. - * @throws IllegalArgumentException if the directory is not allowed. - */ - public SuFilePathHandler(@NonNull Context context, @NonNull File directory, Shell rootShell) { - try { - mDirectory = new File(getCanonicalDirPath(directory)); - if (!isAllowedInternalStorageDir(context)) { - throw new IllegalArgumentException("The given directory \"" + directory - + "\" doesn't exist under an allowed app internal storage directory"); - } - mShell = rootShell; - } catch (IOException e) { - throw new IllegalArgumentException( - "Failed to resolve the canonical path for the given directory: " - + directory.getPath(), e); - } - } - - private boolean isAllowedInternalStorageDir(@NonNull Context context) throws IOException { - String dir = getCanonicalDirPath(mDirectory); - - for (String forbiddenPath : FORBIDDEN_DATA_DIRS) { - if (dir.startsWith(forbiddenPath)) { - return false; - } - } - return true; - } - - /** - * Opens the requested file from the exposed data directory. - *

- * The matched prefix path used shouldn't be a prefix of a real web path. Thus, if the - * requested file cannot be found or is outside the mounted directory a - * {@link WebResourceResponse} object with a {@code null} {@link InputStream} will be - * returned instead of {@code null}. This saves the time of falling back to network and - * trying to resolve a path that doesn't exist. A {@link WebResourceResponse} with - * {@code null} {@link InputStream} will be received as an HTTP response with status code - * {@code 404} and no body. - *

- * The MIME type for the file will be determined from the file's extension using - * {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that - * files are named using standard file extensions. If the file does not have a - * recognised extension, {@code "text/plain"} will be used by default. - * - * @param path the suffix path to be handled. - * @return {@link WebResourceResponse} for the requested file. - */ - @Override - @WorkerThread - @NonNull - public WebResourceResponse handle(@NonNull String path) { - try { - File file = getCanonicalFileIfChild(mDirectory, path); - if (file != null) { - InputStream is = openFile(file, mShell); - String mimeType = guessMimeType(path); - return new WebResourceResponse(mimeType, null, is); - } else { - Log.e(TAG, String.format( - "The requested file: %s is outside the mounted directory: %s", path, - mDirectory)); - } - } catch (IOException e) { - Log.e(TAG, "Error opening the requested path: " + path, e); - } - return new WebResourceResponse(null, null, null); - } - - public static String getCanonicalDirPath(@NonNull File file) throws IOException { - String canonicalPath = file.getCanonicalPath(); - if (!canonicalPath.endsWith("/")) canonicalPath += "/"; - return canonicalPath; - } - - public static File getCanonicalFileIfChild(@NonNull File parent, @NonNull String child) - throws IOException { - String parentCanonicalPath = getCanonicalDirPath(parent); - String childCanonicalPath = new File(parent, child).getCanonicalPath(); - if (childCanonicalPath.startsWith(parentCanonicalPath)) { - return new File(childCanonicalPath); - } - return null; - } - - @NonNull - private static InputStream handleSvgzStream(@NonNull String path, - @NonNull InputStream stream) throws IOException { - return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream; - } - - public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws IOException { - SuFile suFile = new SuFile(file.getAbsolutePath()); - suFile.setShell(shell); - InputStream fis = SuFileInputStream.open(suFile); - return handleSvgzStream(file.getPath(), fis); - } - - /** - * Use {@link MimeUtil#getMimeFromFileName} to guess MIME type or return the - * {@link #DEFAULT_MIME_TYPE} if it can't guess. - * - * @param filePath path of the file to guess its MIME type. - * @return MIME type guessed from file extension or {@link #DEFAULT_MIME_TYPE}. - */ - @NonNull - public static String guessMimeType(@NonNull String filePath) { - String mimeType = MimeUtil.getMimeFromFileName(filePath); - return mimeType == null ? DEFAULT_MIME_TYPE : mimeType; - } -} 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 deleted file mode 100644 index eccb002a..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt +++ /dev/null @@ -1,68 +0,0 @@ -package me.weishu.kernelsu.ui.webui - -import android.annotation.SuppressLint -import android.app.ActivityManager -import android.content.Context -import android.os.Bundle -import android.webkit.WebResourceRequest -import android.webkit.WebResourceResponse -import android.webkit.WebView -import android.webkit.WebViewClient -import androidx.activity.ComponentActivity -import androidx.webkit.WebViewAssetLoader -import com.topjohnwu.superuser.Shell -import me.weishu.kernelsu.ui.util.createRootShell -import java.io.File - -@SuppressLint("SetJavaScriptEnabled") -class WebUIActivity : ComponentActivity() { - private lateinit var webviewInterface: WebViewInterface - - private var rootShell: Shell? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val moduleId = intent.getStringExtra("id")!! - val name = intent.getStringExtra("name")!! - setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name")) - - val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE) - WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", false)) - - val webRoot = File("/data/adb/modules/${moduleId}/webroot") - val rootShell = createRootShell(true).also { this.rootShell = it } - val webViewAssetLoader = WebViewAssetLoader.Builder() - .setDomain("mui.kernelsu.org") - .addPathHandler( - "/", - SuFilePathHandler(this, webRoot, rootShell) - ) - .build() - - val webViewClient = object : WebViewClient() { - override fun shouldInterceptRequest( - view: WebView, - request: WebResourceRequest - ): WebResourceResponse? { - return webViewAssetLoader.shouldInterceptRequest(request.url) - } - } - - val webView = WebView(this).apply { - settings.javaScriptEnabled = true - settings.domStorageEnabled = true - settings.allowFileAccess = false - webviewInterface = WebViewInterface(this@WebUIActivity, this) - addJavascriptInterface(webviewInterface, "ksu") - setWebViewClient(webViewClient) - loadUrl("https://mui.kernelsu.org/index.html") - } - - setContentView(webView) - } - - override fun onDestroy() { - super.onDestroy() - runCatching { rootShell?.close() } - } -} \ No newline at end of file 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 deleted file mode 100644 index 4b6a3c8f..00000000 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt +++ /dev/null @@ -1,190 +0,0 @@ -package me.weishu.kernelsu.ui.webui - -import android.app.Activity -import android.content.Context -import android.os.Handler -import android.os.Looper -import android.text.TextUtils -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 me.weishu.kernelsu.ui.util.createRootShell -import me.weishu.kernelsu.ui.util.withNewRootShell -import org.json.JSONArray -import org.json.JSONObject -import java.util.concurrent.CompletableFuture - -class WebViewInterface(val context: Context, private val webView: WebView) { - - @JavascriptInterface - fun exec(cmd: String): String { - return withNewRootShell(true) { ShellUtils.fastCmd(this, cmd) } - } - - @JavascriptInterface - fun exec(cmd: String, callbackFunc: String) { - exec(cmd, null, callbackFunc) - } - - private fun processOptions(sb: StringBuilder, options: String?) { - val opts = if (options == null) JSONObject() else { - JSONObject(options) - } - - val cwd = opts.optString("cwd") - if (!TextUtils.isEmpty(cwd)) { - sb.append("cd ${cwd};") - } - - opts.optJSONObject("env")?.let { env -> - env.keys().forEach { key -> - sb.append("export ${key}=${env.getString(key)};") - } - } - } - - @JavascriptInterface - fun exec( - cmd: String, - options: String?, - callbackFunc: String - ) { - val finalCommand = StringBuilder() - processOptions(finalCommand, options) - finalCommand.append(cmd) - - val result = withNewRootShell(true) { - newJob().add(finalCommand.toString()).to(ArrayList(), ArrayList()).exec() - } - val stdout = result.out.joinToString(separator = "\n") - val stderr = result.err.joinToString(separator = "\n") - - val jsCode = - "javascript: (function() { try { ${callbackFunc}(${result.code}, ${ - JSONObject.quote( - stdout - ) - }, ${JSONObject.quote(stderr)}); } catch(e) { console.error(e); } })();" - webView.post { - webView.loadUrl(jsCode) - } - } - - @JavascriptInterface - fun spawn(command: String, args: String, options: String?, callbackFunc: String) { - val finalCommand = StringBuilder() - - processOptions(finalCommand, options) - - if (!TextUtils.isEmpty(args)) { - finalCommand.append(command).append(" ") - JSONArray(args).let { argsArray -> - for (i in 0 until argsArray.length()) { - finalCommand.append(argsArray.getString(i)) - finalCommand.append(" ") - } - } - } else { - finalCommand.append(command) - } - - val shell = createRootShell(true) - - val emitData = fun(name: String, data: String) { - val jsCode = - "javascript: (function() { try { ${callbackFunc}.${name}.emit('data', ${ - JSONObject.quote( - data - ) - }); } catch(e) { console.error('emitData', e); } })();" - webView.post { - webView.loadUrl(jsCode) - } - } - - val stdout = object : CallbackList() { - override fun onAddElement(s: String) { - emitData("stdout", s) - } - } - - val stderr = object : CallbackList() { - override fun onAddElement(s: String) { - emitData("stderr", s) - } - } - - val future = shell.newJob().add(finalCommand.toString()).to(stdout, stderr).enqueue() - val completableFuture = CompletableFuture.supplyAsync { - future.get() - } - - completableFuture.thenAccept { result -> - val emitExitCode = - "javascript: (function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();" - webView.post { - webView.loadUrl(emitExitCode) - } - - if (result.code != 0) { - val emitErrCode = - "javascript: (function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${ - JSONObject.quote( - result.err.joinToString( - "\n" - ) - ) - };${callbackFunc}.emit('error', err); } catch(e) { console.error('emitErr', e); } })();" - webView.post { - webView.loadUrl(emitErrCode) - } - } - }.whenComplete { _, _ -> - runCatching { shell.close() } - } - } - - @JavascriptInterface - fun toast(msg: String) { - webView.post { - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() - } - } - - @JavascriptInterface - fun fullScreen(enable: Boolean) { - if (context is Activity) { - Handler(Looper.getMainLooper()).post { - if (enable) { - hideSystemUI(context.window) - } else { - showSystemUI(context.window) - } - } - } - } - -} - -fun hideSystemUI(window: Window) { - WindowCompat.setDecorFitsSystemWindows(window, false) - WindowInsetsControllerCompat(window, window.decorView).let { controller -> - controller.hide(WindowInsetsCompat.Type.systemBars()) - 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 diff --git a/manager/app/src/main/jniLibs/.gitignore b/manager/app/src/main/jniLibs/.gitignore deleted file mode 100644 index 311f7299..00000000 --- a/manager/app/src/main/jniLibs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -libksud.so \ No newline at end of file diff --git a/manager/app/src/main/jniLibs/arm64-v8a/libmagiskboot.so b/manager/app/src/main/jniLibs/arm64-v8a/libmagiskboot.so deleted file mode 100644 index 451ca81c..00000000 Binary files a/manager/app/src/main/jniLibs/arm64-v8a/libmagiskboot.so and /dev/null differ 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 900e2d8c..00000000 --- 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/drawable/ic_launcher_foreground.xml b/manager/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index c9ad0ad4..00000000 --- a/manager/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/manager/app/src/main/res/drawable/ic_launcher_monochrome.xml b/manager/app/src/main/res/drawable/ic_launcher_monochrome.xml deleted file mode 100644 index e4dc522e..00000000 --- a/manager/app/src/main/res/drawable/ic_launcher_monochrome.xml +++ /dev/null @@ -1,22 +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 deleted file mode 100644 index b070c763..00000000 --- a/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/manager/app/src/main/res/mipmap-hdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 485b815d..00000000 Binary files a/manager/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/manager/app/src/main/res/mipmap-ldpi/ic_launcher.png b/manager/app/src/main/res/mipmap-ldpi/ic_launcher.png deleted file mode 100644 index 5c18cc79..00000000 Binary files a/manager/app/src/main/res/mipmap-ldpi/ic_launcher.png and /dev/null differ diff --git a/manager/app/src/main/res/mipmap-mdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 9df35253..00000000 Binary files a/manager/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/manager/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index f8dc01c5..00000000 Binary files a/manager/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/manager/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index ba22bf82..00000000 Binary files a/manager/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/manager/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index cddff920..00000000 Binary files a/manager/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/manager/app/src/main/res/values-ar/strings.xml b/manager/app/src/main/res/values-ar/strings.xml deleted file mode 100644 index c38c4fc8..00000000 --- a/manager/app/src/main/res/values-ar/strings.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - الرئيسية - غير مثبت - إضغط للتثبيت - يعمل - الإصدار: %d - مستخدمين الجذر: %d - الإضافات: %d - غير مدعوم - KernelSU يدعم GKI kernels فقط - إصدار النواة - إصدار المدير - البصمة - وضع SELinux - معطل - مفروض - متساهل - مجهول - مستخدم خارق - فشل في تمكين الإضافة: %s - فشل تعطيل الإضافة : %s - لا توجد إضافات مثبتة - الإضافات - إلغاء التثبيت - تثبيت الوحدة - تثبيت - إعادة تشغيل - الإعدادات - إعادة تشغيل سريعة - إعادة تشغيل إلى وضع Recovery - إعادة تشغيل إلى وضع Bootloader - إعادة تشغيل إلى وضع Download - إعادة تشغيل إلى وضع EDL - من نحن - هل أنت متأكد أنك تريد إلغاء تثبيت الإضافة %s ? - تم إلغاء تثبيتها %s - فشل إلغاء التثبيت: %s - الإصدار - المطور - التراكبات غير متوفرة ، لا يمكن للإضافة أن تعمل! - إنعاش - إظهار تطبيقات النظام - إخفاء تطبيقات النظام - إرسال السجلات - الوضع الآمن - إعادة التشغيل لتطبيق التغييرات - تم تعطيل الإضافات لأنها تتعارض مع Magisk! - تعلم KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - تعرف على كيفية تثبيت KernelSU واستخدام الإضافات - إدعمنا - KernelSU سيظل دائماً مجانياً ومفتوح المصدر. مع ذلك، يمكنك أن تظهر لنا أنك تهتم بالتبرع. - إنضم إلى قناتنا في %2$s ]]> - القدرات - تحديث - تحميل الإضافة: %s - ابدأ التنزيل: %s - الإصدار الجديد: %s متاح ، انقر للتحديث - تشغيل - الإفتراضي - نموذج - موروث - عالمي - فردي - مجموعات - مُخصّص - تركيب مساحة الاسم - الغاء تحميل الإضافات - فشل تحديث ملف تعريف التطبيق لـ %s - سياق SELinux - ايقاف إجباري - الغاء تحميل الإضافات بشكل افتراضي - القيمة الافتراضية العامة لـ\"إلغاء تحميل الإضافات\" في ملفات تعريف التطبيقات. إذا تم تمكينه، إزالة جميع تعديلات الإضافات على النظام للتطبيقات التي لا تحتوي على مجموعة ملف تعريف. - سيسمح تمكين هذا الخيار لـKernelSU باستعادة أي ملفات معدلة بواسطة الإضافات لهذا التطبيق. - المجال - القواعد - إعادة تشغيل التطبيق - فشل تحديث قواعد SELinux لما يلي: %s - اسم الملف الشخصي - إصدار KernelSU الحالي %d منخفض جدًا بحيث لا يعمل المدير بشكل صحيح. الرجاء الترقية إلى الإصدار %d أو أعلى! - سجل التغييرات - تم الاستيراد بنجاح - تصدير إلى الحافظة - لا يمكن العثور على القالب المحلي للتصدير! - معرف القالب موجود بالفعل! - استيراد من الحافظة - فشل في جلب سجل التغيير: %s - الاسم - معرف القالب غير صالح - مزامنة القوالب عبر الإنترنت - إنشاء قالب - للقراءة فقط - استيراد / تصدير - فشل في حفظ القالب - تحرير القالب - المعرف - قالب ملف تعريف التطبيق - الوصف - حفظ - إدارة القالب المحلي وعبر الإنترنت لملف تعريف التطبيق - حذف - الحافظة فارغة! - عرض القالب - فشل في منح صلاحية الجذر! - فتح - التحقق تلقائيًا من وجود تحديثات عند فتح التطبيق - التحقق من التحديث - تمكين تصحيح أخطاء WebView - يمكن استخدامه لتصحيح أخطاء WebUI، يرجى تمكينه فقط عند الحاجة. - التالي - اختيار ملف - تثبيت مباشر (موصى به) - التثبيت على فتحة غير نشطة (بعد OTA) - سيتم **إجبار** جهازك على التمهيد إلى الفتحة غير النشطة الحالية بعد إعادة التشغيل! -\nاستخدم هذا الخيار فقط بعد انتهاء التحديث. -\nأستمرار؟ - اختر KMI - يوصى باستخدام صورة القسم %1$s - تصغير الصورة المتفرقة - قم بتغيير حجم الصورة المتفرقة حيث توجد الإضافة إلى حجمها الفعلي. لاحظ أن هذا قد يتسبب في عمل الإضافة بشكل غير طبيعي، لذا يرجى استخدامها فقط عند الضرورة (مثل النسخ الاحتياطي) - إلغاء التثبيت - إلغاء التثبيت مؤقتًا - إلغاء التثبيت بشكل دائم - استعادة الصورة الاصلية - ‬إلغاء تثبيت KernelSU (الجذر وجميع الوحدات) بشكل كامل ودائم. - تركيب - نجح التركيب - فشل التركيب - صورة lkm المحددة: %s - استعادة صورة المصنع المخزنة (في حالة وجود نسخة احتياطية)، والتي تُستخدم عادة قبل OTA؛ إذا كنت بحاجة إلى إلغاء تثبيت KernelSU، فيرجى استخدام \"إلغاء التثبيت الدائم\". - قم بإلغاء تثبيت KernelSU مؤقتًا، واستعد إلى حالته الأصلية بعد إعادة التشغيل التالية. - حفظ السجلات - \ No newline at end of file diff --git a/manager/app/src/main/res/values-az/strings.xml b/manager/app/src/main/res/values-az/strings.xml deleted file mode 100644 index 21ec189f..00000000 --- a/manager/app/src/main/res/values-az/strings.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - Ana səhifə - Super istifadəçilər: %d - Nüvə - Yüklənmədi - Yükləmək üçün toxunun - İşləyir - Versiya: %d - Modullar: %d - Hal-hazırda KernelSU yalnız GKI nüvələrini dəstəkləyir - Dəstəklənmir - Yüklə - Yüklə - Naməlum - Barmaq izi - Menecer versiyası - Qeyri-aktiv - SELinux vəziyyəti - Sərbəst - Məcburi - Super istifadəçi - Sil - Modulu aktiv etmək mümkün olmadı: %s - Modulu deaktiv etmək mümkün olmadı: %s - Heç bir modul quraşdırılmayıb - Modul - Yenidən başlat - Parametrlər - Bərpa rejimində yenidən başlat - Yüngül vəziyyətdə yenodən başlat - Bootloader rejimində yenidən başlat - Yükləmə rejimində yenidən başlat - Versiya - Sahib - Modulu silmək istədiyinizdən əminsiniz %s\? - Sistem proqramlarını göstər - Haqqında - EDL rejimində yenidən başlat - Silmək mümkün olmadı: %s - %s silindi - Sistem proqramlarını gizlət - overlayfs mövcud deyil,modul işləyə bilməyəcək! - Log-u göndər - Yenilə - Təhlükəsiz rejimi - Qüvvəyə minməsi üçün yenidən başlat - Modular deaktiv edilir,çünki o Magisk-in modulları ilə toqquşur! - KernelSU-yu öyrən - https://kernelsu.org/guide/what-is-kernelsu.html - Bizi dəstəkləyin - KernelSU-yu necə quraşdırılacağını və modulların necə istifadə ediləcəyini öyrən - Şablon - Defolt - Özəl - KernelSU pulsuz və açıq mənbəlidir,həmişə belə olacaqdır. Bununla belə, ianə etməklə bizə qayğı göstərdiyinizi göstərə bilərsiniz. - Mənbə kodlarımıza baxın %1$s
Kanalımıza %2$s qoşulun
- Profil adı - Bacarıqlar - Modulları umount et - Miras qalmış - Qlobal - Bölmənin ad sahəsi - Fərdi - Qruplar - Defolt olaraq modulları umount et - SELinux konteksi - %s görə tətbiq profillərini güncəlləmək mümkün olmadı - Tətbiq Profillərində \"Umount modulları\" üçün qlobal standart dəyər. Aktivləşdirilərsə, o, Profil dəsti olmayan proqramlar üçün sistemdəki bütün modul dəyişikliklərini siləcək. - Domen - Qaydalar - Güncəllə - Endirməni başlat: %s - Yeni versiya: %s əlçatandır, endirmək üçün toxunun - Modul yüklənir: %s - Bu seçimi aktivləşdirmək KernelSU-ya bu proqram üçün modullar tərəfindən hər hansı dəyişdirilmiş faylları bərpa etməyə imkan verəcək. - - Məcburi dayandır - Yenidən başlat - %s görə SELinux qaydalarını güncəlləmək mümkün olmadı - Girişləri Saxla -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-bn-rBD/strings.xml b/manager/app/src/main/res/values-bn-rBD/strings.xml deleted file mode 100644 index 078d88fe..00000000 --- a/manager/app/src/main/res/values-bn-rBD/strings.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - কর্নেল এস ইউ কেবল মাত্র জিকআই কর্নেল সাপোর্ট করে - এসইলিনাক্স স্টেটাস - আননোন - মোডিউল ইনেবল করা যায়নি: %s - ইন্সটল করটে চাপুন - কাজ করছে - মোডিউল: %d - অমূলক - কর্নেল - ম্যানেজার ভারসন - ফিঙ্গারপ্রিন্ট - ডিসেবল - এনফোর্সিং - সুপার ইউজার - মোডিউল - আনইন্সটল - ইন্সটল - ইন্সটল - রিবুট - সেটিংস - সফট রিবুট - গ্লোবাল - গ্রুপস - এসইলিনাক্স কন্টেক্সট - %s এর জন্য অ্যাপ প্রফাইল আপডেট করা যায়নি - বাইডিফল্ট মোডিউল আনমাউন্ট - হোম - ইন্সটল হয়নী - পারমিসিভ - মোডিউল ডিসেবল করা যায়নি: %s - কোনো মোডিউল ইন্সটল করা নেই - সংস্করণ: %d - সুপার ইউজার: %d - নেইম স্পেস মাউন্ট - ইনহেরিটেড - ইন্ডিভিজুয়াল - ক্যাপাবিলিটিস - আনমাউন্ট মোডিউলস - রিকভারিতে বুট - বুটলোডারে বুট - ডাউনলোড মডে বুট - ইমারজেন্সি ডাউনলোড মডে বুট - অ্যাবাউট - %s মোডিউল আনইনস্টলের বেপারে নিশ্চিৎ\? - %s আনইনস্টলড - %s আনইনস্টল করা যায়নি - ভার্সন - অথার - লগ সংরক্ষণ করুন - \ No newline at end of file diff --git a/manager/app/src/main/res/values-bn/strings.xml b/manager/app/src/main/res/values-bn/strings.xml deleted file mode 100644 index 312672c8..00000000 --- a/manager/app/src/main/res/values-bn/strings.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - হোম - ইনস্টল করা হয়নি - ইনস্টল করার জন্য ক্লিক করুন - ওয়ার্কিং - ওয়ার্কিং সংস্করণ: %d - সুপার ইউজার: %d - মডিউল: %d - অসমর্থিত - KernelSU শুধুমাত্র GKI কার্নেল সমর্থন করে - কার্নেল - ম্যানেজার সংস্করণ - ফিঙ্গারপ্রিন্ট - SELinux স্টেটাস - ডিজেবল - কার্যকর - অনুমতিমূলক - অজানা - সুপার ইউজার - মডিউল সক্ষম করতে ব্যর্থ হয়েছে: %s - মডিউল নিষ্ক্রিয় করতে ব্যর্থ হয়েছে: %s - কোন মডিউল ইনস্টল করা নেই - মডিউল - আনইন্সটল - মডিউল ইনস্টল - ইনস্টল - রিবুট - সেটিংস - সফট রিবুট - রিবুট রিকোভারি - রিবুট বুটলোডার - রিবুট ডাউনলোড - রিবুট ইডিএল - এবাউট - মডিউল আনইনস্টল নিশ্চিত করুন %s? - %s আনইনস্টল সফল - আনইন্সটল ব্যর্থ: %s - ভার্সন - লেখক - ওভারলেএফএস উপলব্ধ নয়, মডিউল কাজ করতে পারে না! - রিফ্রেশ - শো সিস্টেম অ্যাপস - হাইড সিস্টেম অ্যাপস - সেন্ড লগ - সেইফ মোড - রিবুট এপ্লাই - মডিউলগুলি অক্ষম কারণ তারা ম্যাজিস্কের সাথে বিরোধিতা করে! - লার্ন কার্নেলএসইউ - https://kernelsu.org/guide/what-is-kernelsu.html - কিভাবে কার্নেলএসইউ ইনস্টল করতে হয় এবং মডিউল ব্যবহার করতে হয় তা শিখুন - সাপোর্ট টাইটেল - কার্নেলএসইউ বিনামূল্যে এবং ওপেন সোর্স, এবং সবসময় থাকবে। আপনি সবসময় একটি অনুদান দিয়ে আপনার কৃতজ্ঞতা প্রদর্শন করতে পারেন. - আমাদের %2$s চ্যানেল মার্জ করুন]]> - প্রফাইলের নাম - নেমস্পেস মাউন্ট - গ্রুপস - যোগ্যতা - এসই লিনাক্স কনটেক্সট - ডিফল্ট - টেমপ্লেট - কাস্টম - গ্লোবাল - আলাদাভাবে - আনমাউন্ট মোডিউল - ম্যানেজার সঠিকভাবে কাজ করার জন্য বর্তমান KernelSU সংস্করণ %d খুবই কম। অনুগ্রহ করে %d বা উচ্চতর সংস্করণে আপগ্রেড করুন! - লগ সংরক্ষণ করুন - \ No newline at end of file diff --git a/manager/app/src/main/res/values-bs/strings.xml b/manager/app/src/main/res/values-bs/strings.xml deleted file mode 100644 index da078631..00000000 --- a/manager/app/src/main/res/values-bs/strings.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - Imenski prostor nosača - Naslijeđen - Globalan - Pojedinačan - Grupe - Sposobnosti - SELinux kontekst - Umount module - Ažuriranje Profila Aplikacije za %s nije uspjelo - Trenutna KernelSU verzija %d je preniska da bi upravitelj ispravno radio. Molimo vas da nadogradite na verziju %d ili noviju! - Umount module po zadanom - Globalna zadana vrijednost za \"Umount module\" u Profilima Aplikacije. Ako je omogućeno, uklonit će sve izmjene modula na sistemu za aplikacije koje nemaju postavljen Profil. - Uključivanjem ove opcije omogućit će KernelSU-u da vrati sve izmjenute datoteke od strane modula za ovu aplikaciju. - Ažuriranje - Skidanje module: %s - Započnite sa skidanjem: %s - Nova verzija: %s je dostupna, kliknite da skinete - Pokrenite - Prisilno Zaustavite - Resetujte - U Provođenju - Početna - Nije instalirano - Kliknite da instalirate - Superkorisnici: %d - Module: %d - Nepodržano - KernelSU samo podržava GKI kernele sad - Verzija Upravitelja - Otisak prsta - SELinux stanje - Instalirajte - Instalirajte - Ponovo pokrenite - Podešavanja - Verzija - Autor - Osvježi - Prikažite sistemske aplikacije - Sakrijte sistemske aplikacije - Sigurnosni mod - Ponovo pokrenite da bi proradilo - Module su isključene jer je u sukobu sa Magisk-om! - https://kernelsu.org/guide/what-is-kernelsu.html - Naučite kako da instalirate KernelSU i da koristite module - Podržite Nas - Pošaljite Izvještaj - Naučite KernelSU - Pogledajte izvornu kodu na %1$s
Pridružite nam se na %2$s kanalu
- Domena - Pravila - Neuspješno ažuriranje SELinux pravila za: %s - Radi - Verzija: %d - Kernel - Permisivno - Deinstalirajte - Nepoznato - Nema instaliranih modula - Superkorisnik - Modula - Ponovo pokrenite u Pogonski Učitavatelj - Ponovo pokrenite u Oporavu - %s deinstalirana - Lagano Ponovo pokretanje - Neuspješno uključivanje module: %s - Ponovo pokrenite u Preuzimanje - Neuspješno isključivanje module: %s - Ponovo pokrenite u EDL - Neuspješna deinstalacija: %s - Isključeno - O - Jeste li sigurni da želite deinstalirati modulu %s\? - overlayfs nije dostupan, modula ne može raditi! - KernelSU je, i uvijek če biti, besplatan, i otvorenog izvora. Možete nam međutim pokazati da vas je briga s time da napravite donaciju. - Zadano - Šablon - Prilagođeno - Naziv profila - Sačuvaj Dnevnike -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-da/strings.xml b/manager/app/src/main/res/values-da/strings.xml deleted file mode 100644 index 6ab02256..00000000 --- a/manager/app/src/main/res/values-da/strings.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - Arbejder - Moduler: %d - Ikke understøttet - Kernel - KernelSU understøtter kun GKI kernels - Manager Version - SELinux-status - Deaktiveret - Tilladende - Superbruger - Håndhævende - Deaktivering af modul fejlede: %s - Intet modul installeret - Afinstaller - Installer - Installer - Genstart - Indstillinger - Blød Genstart - Genstart til Download - Genstart til EDL - Om - Er du sikker på, at du vil afinstallere modulet %s\? - %s afinstalleret - Afinstallation af: %s fejlede - overlayfs er ikke tilgængeligt, modulet kan ikke fungere! - Opdater - Send Log - Sikker tilstand - Genstart for at tage effekt - Lær KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Lær hvordan man installerer KernelSU og moduler - Se source koden ved %1$s
Deltage i vores %2$s kanal
- Standard - Skabelon - Monter navnerum - Arvet - Global - Grupper - Evner - SELinux-kontext - Afmonteret moduler - Afmontere moduler som standard - Aktivering af denne indstilling vil tillade KernelSU at gendanne hvilken som helst modificeret filer af modulet for denne applikation. - Opdatering - Downloader modulet: %s - Ny version: %s er tilgængelig, kilk for at downloade - Start - Tving Stop - Opdatering af SELinux-regler for: %s fejlede - Start download: %s - Klik for at installere - Version: %d - Hjem - Ikke installeret - Superbrugere: %d - Fingeraftryk - Ukendt - Aktivering af modul fejlede: %s - Genstart til Recovery - Modul - Forfatter - Genstart til Bootloader - Version - Gem system-apps - Vis system-apps - Moduler er deaktiveret, fordi der er konflikt med Magiskes! - Støt Os - KernelSU er, og vil altid være gratis og open source. Du kan stadig vise os din støtte ved at donere. - Brugerdefineret - Profilnavn - Individuel - Opdatering af App Profil for %s fejlede - Den globale standard værdi for \"Afmonter moduler\" i App Profiler. Hvis aktiveret vil den fjerne alle modulers modifikationer til system applikationerne der ikke har en sat Profil. - Domæne - Regler - Genstart - Den nuværende KernelSU version %d er for lav til manageren for at fungere ordentligt. Opgrader til version %d eller højere! - Gem Logfiler -
\ 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 deleted file mode 100644 index 04712346..00000000 --- a/manager/app/src/main/res/values-de/strings.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - Startseite - Nicht installiert - Permissiv - Funktioniert - Version: %d - SuperUser - Tippen zum Installieren - Superuser: %d - Unbekannt - Erzwingen - Neustart in Bootloader - Neustart in Download-Modus - Neustart mit EDL-Modus - Autor - overlayfs nicht verfügbar, Modul kann nicht funktionieren! - Über - Module sind deaktiviert, weil es einen Konflikt mit Magisk gibt! - https://kernelsu.org/guide/what-is-kernelsu.html - Erfahren, wie KernelSU installiert und 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. - Standard - Vorlage - Benutzerdefiniert - App-Profilaktualisierung für %s fehlgeschlagen - Vererbt - 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 - Starten - Neue Version: %s verfügbar, tippen zum Aktualisieren - Stopp erzwingen - Neustart - Module: %d - Manager-Version - SELinux-Status - Deaktiviert - Modulaktivierung fehlgeschlagen: %s - Moduldeaktivierung fehlgeschlagen: %s - Keine Module installiert - Modul - Deinstallieren - Installieren - Neustarten - Einstellungen - Neustart in Recovery - %s deinstalliert - Version - Neu laden - 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
- Profilname - Namespace einhängen - Gruppen - Fähigkeiten - Module aushängen - Modul herunterladen: %s - Nicht unterstützt - KernelSU unterstützt derzeit nur GKI-Kernel - Kernel - Fingerabdruck - Installieren - Soft-Reboot - Sicher, dass du das Modul %s deinstallieren möchtest\? - Deinstallation fehlgeschlagen: %s - Die aktuelle Kernel-Version %d ist zu alt für diese Manager-Version. Bitte auf Version %d oder höher upgraden! - Änderungsprotokoll - Erfolgreich importiert - In Zwischenablage exportieren - Kann lokale Vorlage nicht finden! - Vorlagen-ID existiert bereits! - Aus Zwischenablage importieren - Konnte Changelog nicht laden: %s - Name - Ungültige Vorlagen-ID - Online-Vorlagen synchronisieren - Vorlage erstellen - Schreibgeschützt - Import/Export - Fehler beim Speichern - Vorlage bearbeiten - ID - App-Profil-Template - Beschreibung - Speichern - verwalte lokale und online Profil Vorlagen - Löschen - Zwischenablage ist leer! - Vorlage ansehen - WebView-Debugging aktivieren - Kann verwendet werden zum Debugging von WebUI, bitte nur falls nötig 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. -\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 - Protokolle Speichern -
\ 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 deleted file mode 100644 index 5623b47a..00000000 --- a/manager/app/src/main/res/values-es/strings.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - Inicio - No instalado - Toca 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) - Versión del kernel - Versión del gestor - Huella del dispositivo - Estado de SELinux - - Desactivado - Enforcing de SELinux - 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 - Módulo - Desinstalar - Instalar módulo - Instalar - Reiniciar - Ajustes - Reinicio minimo - 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\" - 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 - Modo seguro - Reinicia para aplicar cambios - Se deshabilitaron los módulos ya que entran en conflicto con los de Magisk! - Aprende KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Descubre cómo instalar KernelSU y 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
- Predeterminado - Plantilla - Personalizado - Nombre de perfil - Montaje del espacio de nombres - Heredado - Global - Individual - Grupos - Capacidades - Contexto de SELinux - Desmontar módulos - No se pudo actualizar el perfil de la applicació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. - Dominio - Reglas - Actualizar - 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! - 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 - Nombre - ID de la plantilla es invalido - Sincronizar plantillas en linea - Crear plantilla - sololectura - Importar/Exportar - Fallo en guardar plantilla - Editar plantilla - id - Plantilla del perfil de la aplicacion - Descripción - Guardar - Administrar las plantillas locales y de en linea del perfil de la aplicacion - Eliminar - El portapapeles esta vacio! - Ver plantilla - Guardar Registros -
\ 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 deleted file mode 100644 index d514fc6a..00000000 --- a/manager/app/src/main/res/values-et/strings.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - Töötamine - Versioon: %d - Mooduleid: %d - Tuum - Manageri versioon - Sõrmejälg - Lubav - Mooduli lubamine ebaõnnestus: %s - Mooduleid pole paigaldatud - Taaskäivita - Taaskäivita taastusesse - Kas soovid kindlasti eemaldada mooduli %s? - %s on eemaldatud - Raporteeri logi - Turvarežiim - Muudatuste rakendamiseks taaskäivita - Õpi KernelSUd - https://kernelsu.org/guide/what-is-kernelsu.html - Vaikimisi - Haagi nimeruum - Lahtihaagitud moodulid - Rakenduseprofiili uuendamine %s jaoks ebaõnnestus - Haagi moodulid vaikimisi lahti - Allalaadimise alustamine: %s - SELinux reeglite uuendamine ebaõnnestus: %s - Muuda malli - Rakenduseprofiili mall - ID - vaid lugemiseks - malli ID juba eksisteerib! - Ekspordi lõikelauale - Sünkrooni võrgumallid - Muudatuste logi hankimine ebaõnnestus: %s - Kodu - Klõpsa paigaldamiseks - Pole paigaldatud - Mittetoetatud - Superkasutajaid: %d - KernelSU toetab hetkel vaid GSI tuumasid - SELinuxi olek - Keelatud - Jõustav - Teadmata - Superkasutaja - Mooduli keelamine ebaõnnestus: %s - Moodul - Taaskäivita käivituslaadurisse - Eemalda - Paigalda - Teave - Paigalda - Seaded - Pehme taaskäivitus - Taaskäivita allalaadimisrežiimi - Taaskäivita EDL-i - Värskenda - Autor - Eemaldamine ebaõnnestus: %s - Versioon - overlayfs pole saadaval, moodul ei saa töötada! - Kuva süsteemirakendused - Peida süsteemirakendused - Moodulid on keelatud, kuna need lähevad konflikti Magiski omadega! - Õpi KernelSUd paigaldama ja mooduleid kasutama - Toeta meid - Grupid - KernelSU on, ja alati jääb, tasuta ning avatud lähtekoodiga kättesaadavaks. Sellegipoolest võid sa näidata, et hoolid, ning teha annetuse. - Mall - Vaata lähtekoodi %1$sis
Liitu meie %2$si kanaliga
- Profiili nimi - Kohandatud - Päritud - Globaalne - Individuaalne - 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! - Domeen - Käivita - Sundpeata - Reeglid - Uuenda - Mooduli allalaadimine: %s - Uus versioon: %s on saadaval, klõpsa täiendamiseks - Taaskäivita - Muudatuste logi - Nimi - Kirjeldus - Edukalt imporditud - Salvesta - Lõikelaud on tühi! - Kustuta - Vaata malli - Impordi/ekspordi - Impordi lõikelaualt - Malli salvestamine ebaõnnestus - 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. - Saab kasutada WebUI silumiseks, palun luba ainult vajadusel. - Juurkasutaja andmine ebaõnnestus! - Kontrolli uuendusi - Rakenduse avamisel kontrolli automaatselt uuendusi - Ava - Luba WebView silumine - Salvesta Logid -
\ 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 deleted file mode 100644 index a5cdb2f7..00000000 --- a/manager/app/src/main/res/values-fa/strings.xml +++ /dev/null @@ -1,67 +0,0 @@ - -خانه -نصب نشده است -برای نصب ضربه بزنید -به درستی کار می‌کند -نسخه: %d -برنامه های با دسترسی روت: %d -ماژول‌ها: %d -پشتیبانی نشده -کرنل اس یو فقط هسته های gki را پشتیبانی میکند - هسته - نسخه برنامه - اثرانگشت - وضعیت SELinux -غیرفعال -قانونمند -آزاد -ناشناخته -دسترسی روت - فعال کردن ماژول ناموفق بود: %s -غیرفعال کردن ماژول ناموفق بود: %s -هیچ ماژولی نصب نشده است -ماژول -لغو نصب -نصب -نصب -راه اندازی دوباره -تنظیمات -راه اندازی نرم -راه اندازی به ریکاوری -راه اندازی به بوتلودر -راه اندازی به حالت دانلود -راه اندازی به EDL -درباره - آیا مطمئنید که میخواهید ماژول %s را پاک کنید؟ -%s پاک شد -پاک کردن ناموفق بود: %s -نسخه -سازنده -overlayfs موجود نیست. مازول کار نمیکند!! -تازه‌سازی -نمایش برنامه های سیستمی -مخفی کردن برنامه های سیستمی -ارسال وقایع -حالت امن -راه‌اندازی مجدد برای تاثیرگذاری -مازول به دلیل تعارض با مجیسک غیرفعال شده اند\'s! -یادگیری کرنل اس یو -https://kernelsu.org/guide/what-is-kernelsu.html -یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید -از ما حمایت کنید -KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است. - -Join our %2$s channel ]]> - -پروفایل برنامه -پیش‌فرض -قالب -شخصی سازی شده -اسم پروفایل -Mount namespace -اثر گرفته -گلوبال -تکی -جداکردن ماژول ها - ذخیره گزارش‌ها - diff --git a/manager/app/src/main/res/values-fil/strings.xml b/manager/app/src/main/res/values-fil/strings.xml deleted file mode 100644 index fc527bf3..00000000 --- a/manager/app/src/main/res/values-fil/strings.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - Katayuan ng SELinux - Hindi pinagana - Enforcing - Permissive - Hindi naka-install - Home - Pindutin para mag-install - Gumagana - Bersyon: %d - Hindi matukoy - Mga Modyul: %d - Hindi Suportado - Sinusuportahan lang ng KernelSU ang mga kernel ng GKI ngayon - Nabigong paganahin ang modyul: %s - Nabigong i-disable ang modyul: %s - Walang naka-install na modyul - Modyul - I-install - I-install - I-reboot - I-soft Reboot - I-reboot sa Download - I-reboot sa EDL - Tungkol - Sigurado ka bang gusto mong i-uninstall ang modyul %s\? - Na-uninstall ang %s - Nabigong i-uninstall: %s - May-akda - Ang overlayfs ay hindi magagamit, ang modyul ay hindi gagana! - I-refresh - Ipakita ang mga application ng system - Magpadala ng Log - I-reboot para umepekto - Hindi pinagana ang mga modyul dahil salungat ito sa Magisk! - Alamin ang KernelSU - Matutunan kung paano mag-install ng KernelSU at gumamit ng mga modyul - Suportahan Kami - Ang KernelSU ay, at palaging magiging, libre, at open source. Gayunpaman, maaari mong ipakita sa amin na nagmamalasakit ka sa pamamagitan ng pagbibigay ng donasyon. - Tingnan ang source code sa %1$s
Sumali sa aming %2$s channel
- I-mount ang namespace - Indibidwal - Mga Grupo - Mga Kakayanan - Konteksto ng SELinux - I-unmount ang mga modyul - Nabigong i-update ang App Profile para sa %s - Ang kasalukuyang bersyon ng KernelSU %d ay masyadong mababa para gumana nang maayos ang manager. Mangyaring mag-upgrade sa bersyon %d o mas mataas! - Ang pagpapagana sa opsyong ito ay magbibigay-daan sa KernelSU na ibalik ang anumang binagong file ng mga modyul para sa aplikasyon na ito. - Mga Tuntunin - Nagda-download ng modyul: %s - Simulan ang pag-download: %s - Bagong bersyon: Available ang %s, i-click upang i-download - Ilunsad - Pilit na I-hinto - I-restart - Nabigong i-update ang mga panuntunan ng SELinux para sa: %s - Bersyon ng Manager - Mga setting - I-reboot sa Recovery - I-reboot sa Bootloader - Bersyon - I-uninstall - Itago ang mga application ng system - Pangalan ng profile - Minana - Ang pangkalahatang default na halaga para sa \"Umount modules\" sa Mga Profile ng App. Kung pinagana, aalisin nito ang lahat ng mga pagbabago sa modyul sa system para sa mga aplikasyon na walang hanay ng Profile. - I-save ang mga Log -
\ 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 deleted file mode 100644 index 01c0672b..00000000 --- a/manager/app/src/main/res/values-fr/strings.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - Non installé - Fonctionnel - Version : %d - Super-utilisateurs : %d - Modules : %d - Actuellement, KernelSU ne supporte que les noyaux GKI - Noyau - Empreinte digitale - Mode SELinux - Désactivé - Permissive - Inconnu - Super-utilisateur - Aucun module installé - Accueil - Appuyez ici pour installer - Non supporté - Échec de la désinstallation : %s - Version - Version du gestionnaire - Enforcing - Échec de l\'activation du module : %s - Modules - Désinstaller - Installer - Échec de la désactivation du module : %s - Redémarrer - Installer - Paramètres - Redémarrer en mode bootloader - Redémarrage progressif - Redémarrer en mode de récupération - Redémarrer en mode EDL - À propos - %s a été désinstallé - Redémarrer en mode de téléchargement - 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 ! - Rafraîchir - Afficher les applications système - Masquer les applications système - Mode sans échec - Rapport de journal - Redémarrez pour appliquer les modifications - Les modules sont désactivés car ils sont en conflit avec ceux de 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
- Modèle - Par défaut - Personnalisé - Nom du profil - Espace de noms de montage - Hérité - Individuel - Contexte SELinux - Global - Groupes - 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. - 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 - Règles - Mettre à jour - Téléchargement du module : %s - Lancer - La version %s est disponible, appuyez ici pour mettre à jour - Début du téléchargement de : %s - Forcer l\'arrêt - Relancer l\'application - Échec de la mise à jour des règles SELinux pour : %s - 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à ! - Journal des modifications - Importer à partir du presse-papiers - Échec de récupération du journal des modifications : %s - Nom - id de modèle invalide - Synchroniser les modèles en ligne - Créer un modèle - lecture seule - Importer/exporter - Échec de l\'enregistrement du modèle - Modifier le modèle - id - Modèles de profils d\'application - Description - Enregistrer - Gérer les modèles de profils d\'application locaux et en ligne - Supprimer - Le presse-papiers est vide ! - 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 - Peut être utilisé pour déboguer WebUI, n\'activez cette option que si nécessaire. - Échec de l\'octroi des privilèges root ! - Ouvrir - Installation directe (recommandé) - Sélectionner un fichier - Installer dans l\'emplacement inactif (après OTA) - Votre appareil sera **FORCÉ** à démarrer sur l\'emplacement inactif actuel après un redémarrage ! -\nN\'utilisez cette option qu\'une fois la mise à jour OTA terminée. -\nContinuer ? - 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) - 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 ». - Flash en cours - Flash réussi - Échec du flash - 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 -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-hi/strings.xml b/manager/app/src/main/res/values-hi/strings.xml deleted file mode 100644 index f9304469..00000000 --- a/manager/app/src/main/res/values-hi/strings.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - प्रभाव में होने के लिए रीबूट करें - जानें कि KernelSU कैसे स्थापित करें और मॉड्यूल का उपयोग कैसे करें - अज्ञात - सिस्टम एप्प दिखाए - %s अनइंस्टॉल सफल हुआ - मॉड्यूल्स अनमाउंट करें - लॉग भेजे - डिसेबल्ड (बंद) - हमें प्रोत्साहन दें - Inherited - मॉड्यूल बंद कर दिए गए हैं क्योंकि यह मैजिक के साथ टकरा रहे है! - क्या बदलाव हुए है - पर्मिसिव - डाउनलोड में रिबूट करें - डिफ़ॉल्ट रूप से मॉड्यूल अनमाउन्ट करें - इस विकल्प को चालू करने से KernelSU को इस एप्लिकेशन के लिए मॉड्यूल द्वारा किसी भी मोडिफाइड फ़ाइल को रिस्टोर करें। - Individual - %s मॉड्यूल चालू करने में विफल - जबर्दस्ती बंद करें - EDL मोड में रिबूट करें - फिर से चालू करें - क्षमताएं - सुपरयूजर : %d - %s की डाउनलोडिंग स्टार्ट करें - Global - ऐप प्रोफाइल में \"अनमाउंट मॉड्यूल\" के लिए ग्लोबल डिफ़ॉल्ट वैल्यू। यदि चालू किया गया है, तो यह एप्लीकेशंस के लिऐ सिस्टम के सभी मॉड्यूल मोडिफिकेशन को हटा देगा जिनकी प्रोफ़ाइल सेट नहीं है। - मॉड्यूल्स : %d - एनफोर्सिंग - SELinux context - फिंगरप्रिंट - डिफॉल्ट - लॉन्च करें - सेफ मोड - मैनेजर के ठीक से काम करने के लिए वर्तमान KernelSU वर्जन %d बहुत कम है। कृपया वर्जन %d या उच्चतर में अपग्रेड करें! - रिकवरी में रिबूट करें - सॉफ्ट रिबूट - प्रोफाइल का नाम - KernelSU मुफ़्त और ओपन सोर्स और हमेशा रहेगा। हालाँकि आप दान देकर हमें दिखा सकते हैं कि आप संरक्षण करते हैं। - अनइंस्टॉल करें - Namspace माउंट करें - इंस्टाल करें - इंस्टाल करने के लिए क्लिक करें - नियम - समूह - Overlayfs उपलब्ध नहीं है, मॉड्यूल काम नहीं कर सकता ! - मॉड्यूल - निर्माता - हमारे बारे में - वर्जन: %d - रीबूट करें - KernelSU अभी केवल GKI कर्नल्स को सपोर्ट करता है - SELinux स्थिति - सिस्टम एप्प छिपाए - वर्जन - सपोर्ट नहीं करता है - डोमेन - होम - कस्टम - टेम्पलेट - रिफ्रेश - %s मॉड्यूल डाउनलोड हो रहा है - अपडेट - KernelSU सीखें - क्या आप सच में मॉड्यूल %s को अनइंस्टॉल करना चाहते हैं\? - %s अनइंस्टल करने में असफल - सुपरयूजर - सेटिंग - काम कर रहा है - %s मॉड्यूल बंद करने में विफल - कोई मॉड्यूल इंस्टाल नहीं हुआ - इंस्टाल करें - कर्नल - इंस्टाल नहीं हुआ - %s के लिए ऐप प्रोफ़ाइल अपडेट करने में विफल - https://kernelsu.org/guide/what-is-kernelsu.html - %s के लिए SELinux नियमों को अपटेड करने में विफल - बुटलोडर में रिबूट करें - %1$s पर स्रोत कोड देखें
हमारे %2$s चैनल से जुड़ें
- मैनेजर वर्जन - नया वर्जन: %s उपलब्ध है,अपग्रेड के लिए क्लिक करें - लॉग सहेजें -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-hr/strings.xml b/manager/app/src/main/res/values-hr/strings.xml deleted file mode 100644 index 9fb1e4c6..00000000 --- a/manager/app/src/main/res/values-hr/strings.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - Prikažite sistemske aplikacije - Sakrijte sistemske aplikacije - Pošaljite Izvještaj - Sigurnosni mod - Ponovno pokrenite da bi proradilo - Neuspješno ažuriranje SELinux pravila za: %s - Početna - Nije instalirano - Verzija: %d - Kliknite da instalirate - Radi - Superkorisnici: %d - Module: %d - Nepodržano - KernelSU samo podržava GKI kernele sad - Kernel - Verzija Voditelja - Otisak prsta - Isključeno - U Provođenju - Permisivno - SELinux stanje - Nepoznato - Superkorisnik - Neuspješno uključivanje module: %s - Neuspješno isključivanje module: %s - Nema instaliranih modula - Modula - Deinstalirajte - Instalirajte - Instalirajte - Ponovno pokrenite - Postavke - Lagano Ponovno pokretanje - Ponovno pokrenite u Oporavu - Ponovno pokrenite u Pogonski Učitavalac - Ponovno pokrenite u Preuzimanje - Ponovo pokrenite u EDL - O - Jeste li sigurni da želite deinstalirati modulu %s\? - %s deinstalirana - Neuspješna deinstalacija: %s - Verzija - Autor - Osvježi - overlayfs nije dostupan, modula ne može raditi! - Module su isključene jer je u sukobu sa Magisk-om! - Naučite KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Naučite kako da instalirate KernelSU i da koristite module - Podržite Nas - KernelSU je, i uvijek če biti, besplatan, i otvorenog izvora. Možete nam međutim pokazati da vas je briga s time da napravite donaciju. - Pogledajte izvornu kodu na %1$s
Pridružite nam se na %2$s kanalu
- Zadano - Šablon - Prilagođeno - Naziv profila - Naslijeđen - Imenski prostor nosača - Ažuriranje Profila Aplikacije za %s nije uspjelo - Globalan - Pojedinačan - Umount module - Grupe - Sposobnosti - SELinux kontekst - Trenutna KernelSU verzija %d je preniska da bi voditelj ispravno radio. Molimo vas da nadogradite na verziju %d ili noviju! - Umount module po zadanom - Globalna zadana vrijednost za \"Umount module\" u Profilima Aplikacije. Ako je omogućeno, uklonit će sve izmjene modula na sistemu za aplikacije koje nemaju postavljen Profil. - Domena - Uključivanjem ove opcije omogućit će KernelSU-u da vrati sve izmjenute datoteke od strane modula za ovu aplikaciju. - Pravila - Ažuriranje - Preuzimanje module: %s - Započnite sa preuzimanjem: %s - Nova verzija: %s je dostupna, kliknite da preuzmete - Pokrenite - Prisilno Zaustavite - Resetujte - Spremi Zapise -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-hu/strings.xml b/manager/app/src/main/res/values-hu/strings.xml deleted file mode 100644 index 2b52317c..00000000 --- a/manager/app/src/main/res/values-hu/strings.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - Működik - Verzió: %d - Modulok: %d - KernelSU csak GKI kerneleket támogat jelenleg - Kernel - App verziója - Build Fingerprint - Kikapcsolt - Újraindítás letöltő módba - Újraindítás EDL-be - Névjegy - Biztos vagy benne hogy eltávolítod a következő modult: %s\? - Nem sikerült eltávolítani: %s - Készítő - Overlayfs nem elérhető, a modul nem tud enélkül működni! - Újratöltés - Mutasd a rendszer alkalmazásokat - Rejtsd el a rendszer alkalmazásokat - Biztonságos mód - A modul letiltva mert ütközik a Magisk verziójával! - Tudj meg többet a KernelSU-ról - Tudd meg hogyan telepítsd a KernelSU-t és használd moduljait - Támogass minket - Tekintsd meg a forráskódot a %1$s-n
Csatlakozz a %2$s csatornánkhoz
- Alapértelmezett - Sablon - Egyedi - Profil neve - Mountold a névteret - Örökölt - https://kernelsu.org/guide/what-is-kernelsu.html - Különálló - Csoportok - Jogosultságok - SElinux kontextus - Umountold a modulokat alpértelmezés szerint - Ennek az opciónak az engedélyezése lehetővé teszi, hogy a KernelSU visszaállítsa az alkalmazás moduljai által módosított fájlokat. - Tartomány - Szabályok - Frissítés - A %s modul letöltése folyamatban - Indítsd el a letöltést: %s - Indítás - Kényszerített leállítás - újraindítás - Kezdőlap - Nincs telepítve - Kattints a telepítéshez - Engedélyezett alkalmazások: %d - Nem támogatott - SELinux státusz - Érvényesítés - Megengedő - Ismeretlen - Super user - Nem sikerült engedélyezni a következő modult: %s - Nem sikerült letiltani a következő modulokat: %s - Nincs modul telepítve - Modulok - Eltávolítás - Telepítés - Telepítés - Újraindítás - Beállítások - Android felület újraindítása - Újraindítás recovery-módba - Újraindítás bootloader-módba - %s törölve - Verzió - Napló küldése - Indítsd újra a készüléket hogy érvényesítsd a változást - A KernelSU ingyenes és nyílt forráskódú és mindig is az lesz. Te viszont meg tudod mutatni azt, hogy törődsz ennek a projektnek a sorsával egy adomány formájában. - Globális - Unmountold a modulokat - Nem sikerült frissíteni az App Profilt ehhez %s - A „Modulok csatlakoztatása” globális alapértelmezett értéke az alkalmazásprofilokban. Ha engedélyezve van, eltávolítja a rendszer összes modul-módosítását azoknál az alkalmazásoknál, amelyeknek nincs beállított profilja. - Új verzió: %s elérhető, kattints a frissítéshez - Nem sikerült frissíteni a SELinux szabályait a következőhöz: %s - A jelenlegi KernelSU verzió %d túlságosan elavult. Kérlek frissíts a %d verzióra vagy újabbra! - Sikeresen importálva - Exportálás a vágólapból - A helyi sablon nem található az exportáláshoz! - A sablon ID már létezik! - Változások - Importálás a vágólapból - A változásnapló lekérése nem sikerült: %s - Név - Hibás sablon ID - Online sablonok szinkronizálása - Sablon készítése - csak olvasható - Import/Export - A sablon mentése sikertelen - Sablon szerkesztése - id - Alkalmazásprofil sablon - Leírás - Mentés - Az alkalmazásprofil helyi és online sablon kezelése - Törlés - A vágólap üres! - Sablon megnézése - Naplók Mentése -
\ 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 deleted file mode 100644 index 98698f52..00000000 --- a/manager/app/src/main/res/values-in/strings.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - Beranda - Tidak terinstal - Klik untuk menginstal - Berfungsi - Versi: %d - SuperUser: %d - Modul: %d - Tidak didukung - KernelSU saat ini hanya mendukung kernel GKI - Kernel - Versi Manager - Identitas - Status SELinux - Nonaktif - Enforcing - Permissive - Unknown - SuperUser - Gagal mengaktifkan modul: %s - Gagal menonaktifkan modul: %s - Tidak ada modul - Modul - Hapus - Instal - Instal - Reboot - Pengaturan - SoftReboot - But ke Recovery - But ke Bootloader - But ke Download - But ke EDL - Tentang - Yakin menghapus modul %s? - %s berhasil dihapus - Gagal menghapus: %s - Versi - Oleh - OverlayFS tidak tersedia, modul tidak berfungsi! - Muat ulang - Tampilkan aplikasi sistem - Sembunyikan aplikasi sistem - Laporkan Log - Mode aman - Reboot agar berfungsi - Konflik dengan Magisk, fungsi modul ditiadakan! - Pelajari KernelSU - https://kernelsu.org/id_ID/guide/what-is-kernelsu.html - Pelajari cara instal KernelSU dan menggunakan modul - Dukung Kami - KernelSU akan selalu menjadi aplikasi gratis dan terbuka. Anda dapat memberikan donasi sebagai bentuk dukungan. - Lihat kode sumber di %1$s
Gabung kanal %2$s kami
- Profil Apl - Bawaan - Templat - Khusus - Nama profil - Mount Namespace - Diwariskan - Universal - Individual - Kelompok - Kemampuan - Konteks SELinux - 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. - 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 - Jalankan - 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! - Catatan Perubahan - Berhasil diimpor - Ekspor ke papan klip - Tidak ditemukan templat lokal untuk diekspor! - Id templat sudah ada! - Impor dari papan klip - Gagal mengambil Changelog: %s - Nama - Id templat tidak valid - Sinkronkan templat daring - Buat Templat - Impor/Ekspor - Gagal menyimpan templat - Edit Templat - id - Templat Profil Aplikasi - Deskripsi - Simpan - Atur templat Profil yang lokal dan daring - Hapus - Papan klip kosong! - Lihat Templat - ReadOnly - Pengawakutuan WebView - Dapat mengawakutu WebView, hanya aktifkan jika butuh. - %1$s image partisi terekomendasi - Pilih KMI - Selanjutnya - Gawai akan **DIPAKSA** untuk but ke slot nonaktif! -\nHANYA gunakan setelah proses OTA selesai. -\nLanjutkan? - Instal Langsung (rekomendasi) - Pilih berkas - Instal ke slot nonaktif (setelah OTA) - Gagal memberikan akses root! - Buka - 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) - Hapus permanen KernelSU (root dan modul). - 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\". - Pemasangan Berhasil - LKM dipilih: %s - Pasang - Pemasangan Gagal - Simpan Log -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-it/strings.xml b/manager/app/src/main/res/values-it/strings.xml deleted file mode 100644 index 7bd3f924..00000000 --- a/manager/app/src/main/res/values-it/strings.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - Home - Non installato - Clicca per installare - In esecuzione - Versione: %d - Applicazioni con accesso root: %d - Moduli installati: %d - Non supportato - KernelSU ora supporta solo i kernel GKI - Kernel - Versione del manager - Impronta della build di Android - Stato di SELinux - Disabilitato - Enforcing - Permissive - Sconosciuto - Accesso root - Impossibile abilitare il modulo: %s - Impossibile disabilitare il modulo: %s - Nessun modulo installato - Modulo - Disinstalla - Installa - Installa - Riavvia - Impostazioni - Riavvio rapido - Riavvia in modalità Recovery - Riavvia in modalità Bootloader - Riavvia in modalità Download - Riavvia in modalità EDL - Informazioni - Sei sicuro di voler disinstallare il modulo %s? - %s disinstallato - Impossibile disinstallare: %s - Versione - Autore - overlayfs non è disponibile, i moduli non possono funzionare! - Ricarica - Mostra app di sistema - Nascondi app di sistema - Invia log - Modalità provvisoria - Riavvia per applicare la modifica - I moduli sono disabilitati perché in conflitto con quelli di Magisk! - Scopri KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Scopri come installare KernelSU e utilizzare i moduli - Supportaci - KernelSU è, e sempre sarà, gratuito e open source. Puoi comunque mostrarci il tuo apprezzamento facendo una donazione. - Unisciti al nostro canale %2$s]]> - Nome profilo - Spazio dei nomi del mount - Globale - Gruppi - Ereditato - Individuale - Predefinito - Personalizzato - Modello - Scollega moduli - Contesto SELinux - Aggiornamento App Profile per %s fallito - Aggiorna - Apri - Capacità - Scollega moduli da default - Regole - Sto scaricando il modulo: %s - Inizia a scaricare:%s - Nuova versione: %s disponibile, tocca per aggiornare - Arresto forzato - Riavvia - Aggiornamento regole SELinux per %s fallito - Attivando questa opzione permetterai a KernelSU di ripristinare ogni file modificato dai moduli per questa app. - Dominio - Il valore predefinito per \"Scollega moduli\" in App Profile. Se attivato, rimuoverà tutte le modifiche al sistema da parte dei moduli per le applicazioni che non hanno un profilo impostato. - La versione attualmente installata di KernelSU (%d) è troppo vecchia ed il gestore non può funzionare correttamente. Si prega di aggiornare alla versione %d o successiva! - Registro aggiornamenti - Crea modello - Modifica modello - identificativo - Identificativo modello non valido - Nome - Visualizza modello - Sola lettura - L\'identificativo del modello esiste già! - Importa/Esporta - Importa dagli appunti - Esporta negli appunti - Impossibile trovare modello locale da esportare! - Importato con successo - Sincronizza i modelli remoti - Gli appunti sono vuoti! - Impossibile ottenere l\'accesso root! - Modelli App Profile - Gestisci i modelli locali e remoti di App Profile - Elimina - Descrizione - Salva - Impossibile salvare il modello - Apri - Impossibile reperire il changelog: %s - Controlla aggiornamenti - Controlla automaticamente la disponibilità di aggiornamenti all\'apertura dell\'applicazione - 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) - 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) - Disinstalla - 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. - 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\". - Salva Registri - \ No newline at end of file diff --git a/manager/app/src/main/res/values-iw/strings.xml b/manager/app/src/main/res/values-iw/strings.xml deleted file mode 100644 index 18cfc638..00000000 --- a/manager/app/src/main/res/values-iw/strings.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - הפעל מחדש כדי להכניס לתוקף - למד כיצד להתקין את KernelSU ולהשתמש במודולים - לא ידוע - הצג אפליקציות מערכת - %s הוסר - הסרת טעינת מודולים - שלח לוג - מושבת - תמכו בנו - ירושה - מודולים מושבתים מכיוון שהם מתנגשים עם זה של Magisk! - יומן שינויים - התרים - הפעלה מחדש למצב הורדה - טעינת מודולים כברירת מחדל - הפעלת אפשרות זו תאפשר ל-KernelSU לשחזר קבצים שהשתנו על ידי המודולים עבור יישום זה. - אישי - הפעלת המודל נכשלה: %s - עצירה בכח - הפעלה מחדש למצב EDL - איתחול - יכולת - משתמשי על: %d - מפעיל מודל: %s - גלובלי - ערך ברירת המחדל הגלובלי עבור \"טעינת מודולים\" בפרופילי אפליקציה. אם מופעל, זה יסיר את כל שינויי המודול למערכת עבור יישומים שאין להם ערכת פרופיל. - מודלים:%d - אכיפה - הקשר SELinux - טביעת אצבע - ברירת מחדל - להשיק - מצב בטוח - גרסת KernelSU הנוכחית %d נמוכה מדי כדי שהמנהל יפעל כראוי. אנא שדרג לגרסה %d ומעלה! - הפעלה מחדש לריקברי - רך Reboot - שם פרופיל - KernelSU הוא, ותמיד יהיה, חינמי וקוד פתוח. עם זאת, תוכל להראות לנו שאכפת לך על ידי תרומה. - הסרה - טעינת מרחב שמות - התקנה - לחץ להתקנה - כללים - קבוצה - שכבות-על לא זמינות, המודול לא יכול לעבוד! - מודולים - יוצר - אודות - גרסה: %d - הפעלה מחדש - KernelSU תומך רק בליבת GKI כעת - סטטוס SELinux - הסתר אפליקציות מערכת - גרסה - אינו נתמך - תחום - בית - מותאם אישית - תבנית - רענון - מוריד מודל: %s - עדכון - למד אודות KernelSU - האם אתה בטוח שברצונך להסיר את התקנת המודל %s\? - הסרת התקנת %s נכשלה: - משתמש על - הגדרות - עובד - השבתת מודל %s נכשלה: - אין מודלים מותקנים - להתקין - Kernel - לא מותקן - נכשל עדכון פרופיל האפליקציה עבור %s - https://kernelsu.org/guide/what-is-kernelsu.html - נכשל עדכון כללי SELinux עבור: %s - הפעלה מחדש לבוטלאודר - ראה את קוד המקור ב%1$s
הצטרף אלינו %2$s בערוץ
- גרסת מנהל - גרסה חדשה עבור: %s זמינה, לחץ כדי לשדרג - שמור יומנים -
\ 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 deleted file mode 100644 index 4ecf7420..00000000 --- a/manager/app/src/main/res/values-ja/strings.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - ホーム - 未インストール - タップでインストール - 動作中 - バージョン: %d - スーパーユーザー: %d - モジュール: %d - 非対応 - 現在、 KernelSU は GKI カーネルにのみ対応しています - カーネル - アプリのバージョン - Fingerprint - SELinux の状態 - Disabled - Enforcing - Permissive - 不明 - スーパーユーザー - モジュールの有効化に失敗: %s - モジュールの無効化に失敗: %s - モジュールをインストールしていません - モジュール - アンインストール - インストール - インストール - 再起動 - 設定 - 通常の再起動 - リカバリーへ再起動 - ブートローダー へ再起動 - ダウンロードモードへ再起動 - EDL へ再起動 - アプリについて - モジュール %s をアンインストールしますか? - %s はアンインストールされました - アンインストールに失敗: %s - バージョン - 制作者 - OverlayFS が有効でないためモジュールは動作しません! - 更新 - システムアプリを表示 - システムアプリを非表示 - ログを送信 - セーフモード - 再起動すると有効化されます - Magisk と競合しているためモジュールは無効になっています! - KernelSU について - https://kernelsu.org/ja_JP/guide/what-is-kernelsu.html - KernelSU のインストール方法やモジュールの使い方はこちら - 支援する - KernelSU はこれからもずっとフリーでオープンソースです。寄付をすることで私たちを気にかけていることを示せます。 - %2$s チャンネルに参加]]> - アプリのプロファイル - 既定 - テンプレート - カスタム - プロファイル名 - 名前空間のマウント - 継承 - 共通 - 分離 - モジュールのアンマウント - グループ - SELinux コンテキスト - %s のアプリのプロファイルの更新をできませでした - ドメイン - ルール - 新しいバージョン: %s が利用可能です。タップしてダウンロード - アップデート - ダウンロードを開始: %s - 起動 - 強制停止 - 再起動 - SELinux ルールの更新に失敗しました: %s - ケーパビリティ - モジュールをダウンロード中: %s - このオプションを有効にすると、KernelSU はこのアプリのモジュールによって変更されたファイルを復元できるようになります。 - 既定でモジュールのマウントを解除 - アプリプロファイルの「モジュールのアンマウント」の共通のデフォルト値です。 有効にすると、プロファイルセットを持たないアプリのシステムに対するすべてのモジュールの変更が削除されます。 - 現在の KernelSU バージョン %d はマネージャーが適切に機能するには低すぎます。 バージョン %d 以降にアップグレードしてください! - 変更履歴 - インポート成功 - クリップボードからエクスポート - エクスポートするローカル テンプレートが見つかりません! - テンプレート id はすでに存在します! - クリップボードからインポート - 変更ログの取得に失敗しました: %s - 名前 - 無効なテンプレート id - オンラインテンプレートの同期 - テンプレートの作成 - 読み取り専用 - インポート/エクスポート - テンプレートの保存に失敗しました - テンプレートの編集 - id - アプリプロファイルのテンプレート - 説明 - 保存 - アプリプロファイルのローカルおよびオンラインテンプレートを管理する - 消去 - クリップボードが空です! - テンプレートを表示 - アップデートを確認 - アプリを開いたときにアップデートを自動的に確認する - root の付与に失敗しました! - 開く - WebView デバッグを有効にする - WebUI のデバッグに使用できます。必要な場合にのみ有効にしてください。 - %1$s パーティション イメージが推奨されます - KMI を選択してください - 次に - 非アクティブなスロットにインストール (OTA 後) - 再起動後、デバイスは**強制的に**、現在非アクティブなスロットから起動します。 -\nこのオプションは、OTA が完了した後にのみ使用してください。 -\n続く? - 直接インストール (推奨) - ファイルを選択してください - スパースイメージを最小化 - モジュールが配置されているスパースイメージのサイズを実際のサイズに変更します。 モジュールが正常に動作しなくなる可能性がありますので、必要な場合にのみご使用ください - 完全にアンインストールする - ストックイメージを復元 - 一時的にアンインストールする - アンインストール - KernelSU を一時的にアンインストールし、次回の再起動後に元の状態に戻します。 - KernelSU (ルートおよびすべてのモジュール) を完全かつ永久にアンインストールします。 - バックアップが存在する場合、工場出荷時のイメージを復元できます (OTA の前に使用してください)。KernelSU をアンインストールする必要がある場合は、「完全にアンインストールする」を使用してください。 - フラッシュ - フラッシュ成功 - フラッシュ失敗 - 選択された lkm: %s - ログを保存 - \ No newline at end of file diff --git a/manager/app/src/main/res/values-kn/strings.xml b/manager/app/src/main/res/values-kn/strings.xml deleted file mode 100644 index 3c4e79fe..00000000 --- a/manager/app/src/main/res/values-kn/strings.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - ಪರಿಣಾಮ ಬೀರಲು ರೀಬೂಟ್ ಮಾಡಿ - KernelSU ಅನ್ನು ಹೇಗೆ ಸ್ಥಾಪಿಸಬೇಕು ಮತ್ತು ಮಾಡ್ಯೂಲ್‌ಗಳನ್ನು ಬಳಸುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ - ತಿಳಿಯದ - ಸಿಸ್ಟಮ್ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ತೋರಿಸಿ - %s ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ - Umount ಮಾಡ್ಯೂಲ್‌ಗಳು - ಲಾಗ್ ಕಳುಹಿಸಿ - ನಮ್ಮನ್ನು ಬೆಂಬಲಿಸಿ - ಪಿತ್ರಾರ್ಜಿತ - ಮಾಡ್ಯೂಲ್‌ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಏಕೆಂದರೆ ಇದು ಮ್ಯಾಜಿಸ್ಕ್‌ನೊಂದಿಗೆ ಸಂಘರ್ಷವಾಗಿದೆ! - ಚೇಂಜ್ಲಾಗ್ - Permissive - ಡೀಫಾಲ್ಟ್ ಆಗಿ Umount ಮಾಡ್ಯೂಲ್ - ಈ ಆಯ್ಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುವುದರಿಂದ ಈ ಅಪ್ಲಿಕೇಶನ್‌ಗಾಗಿ ಮಾಡ್ಯೂಲ್‌ಗಳ ಮೂಲಕ ಯಾವುದೇ ಮಾರ್ಪಡಿಸಿದ ಫೈಲ್‌ಗಳನ್ನು ಮರುಸ್ಥಾಪಿಸಲು KernelSU ಗೆ ಅನುಮತಿಸುತ್ತದೆ. - ವೈಯಕ್ತಿಕ - ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ವಿಫಲವಾಗಿದೆ: %s - ಫೋರ್ಸ್ ಸ್ಟಾಪ್ - EDL ಗೆ ರೀಬೂಟ್ - ಸಾಮರ್ಥ್ಯಗಳು - ಸೂಪರ್‌ಯೂಸರ್‌ಗಳು: %d - ಡೌನ್‌ಲೋಡ್ ಮಾಡುವುದನ್ನು ಪ್ರಾರಂಭಿಸಿ: %s - ಜಾಗತಿಕ - ಅಪ್ಲಿಕೇಶನ್ ಪ್ರೊಫೈಲ್‌ಗಳಲ್ಲಿ \"Umount ಮಾಡ್ಯೂಲ್\" ಗಾಗಿ ಜಾಗತಿಕ ಡೀಫಾಲ್ಟ್ ಮೌಲ್ಯ. ಸಕ್ರಿಯಗೊಳಿಸಿದರೆ, ಪ್ರೊಫೈಲ್ ಸೆಟ್ ಅನ್ನು ಹೊಂದಿರದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಸಿಸ್ಟಮ್‌ಗೆ ಎಲ್ಲಾ ಮಾಡ್ಯೂಲ್ ಮಾರ್ಪಾಡುಗಳನ್ನು ಇದು ತೆಗೆದುಹಾಕುತ್ತದೆ. - ಮಾಡ್ಯೂಲ್‌ಗಳು: %d - SELinux ಸಂದರ್ಭ - ಡೀಫಾಲ್ಟ್ - ಲಾಂಚ್ - ಸುರಕ್ಷಿತ ಮೋಡ್ - ಪ್ರಸ್ತುತ KernelSU ಆವೃತ್ತಿ %d ಮ್ಯಾನೇಜರ್ ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ತುಂಬಾ ಕಡಿಮೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಆವೃತ್ತಿ %d ಅಥವಾ ಹೆಚ್ಚಿನದಕ್ಕೆ ಅಪ್‌ಗ್ರೇಡ್ ಮಾಡಿ! - ಸಾಫ್ಟ್ ರೀಬೂಟ್ - ಪ್ರೊಫೈಲ್ ಹೆಸರು - KernelSU ಉಚಿತ ಮತ್ತು ಮುಕ್ತ ಮೂಲವಾಗಿದೆ ಮತ್ತು ಯಾವಾಗಲೂ ಇರುತ್ತದೆ. ಆದಾಗ್ಯೂ ನೀವು ದೇಣಿಗೆ ನೀಡುವ ಮೂಲಕ ನೀವು ಕಾಳಜಿ ವಹಿಸುತ್ತೀರಿ ಎಂದು ನಮಗೆ ತೋರಿಸಬಹುದು. - ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ - ಮೌಂಟ್ ನೇಮ್‌ಸ್ಪೇಸ್ - ನಿಯಮಗಳು - ಗುಂಪುಗಳು - ಓವರ್‌ಲೇಫ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ, ಮಾಡ್ಯೂಲ್ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದಿಲ್ಲ! - ಮಾಡ್ಯೂಲ್ - ಲೇಖಕ - ಬಗ್ಗೆ - ವರ್ಷನ್: %d - ರೀಬೂಟ್ - KernelSU ಈಗ GKI ಕರ್ನಲ್‌ಗಳನ್ನು ಮಾತ್ರ ಬೆಂಬಲಿಸುತ್ತದೆ - SELinux ಸ್ಥಿತಿ - ಸಿಸ್ಟಮ್ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಮರೆಮಾಡಿ - ವರ್ಷನ್ - ಬೆಂಬಲಿತವಾಗಿಲ್ಲ - ಡೊಮೇನ್ - ಮನೆ - ಕಸ್ಟಮ್ - ಟೆಂಪ್ಲೇಟ್ - ರಿಫ್ರೆಶ್ - ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ: %s - KernelSU ಕಲಿಯಿರಿ - %s ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಅಸ್ಥಾಪಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ\? - ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ: %s - ಸೂಪರ್ಯೂಸರ್ - ಕೆಲಸ ಮಾಡುತ್ತಿದೆ - ಮಾಡ್ಯೂಲ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ವಿಫಲವಾಗಿದೆ: %s - ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ - ಕರ್ನಲ್ - %s ಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರೊಫೈಲ್ ಅನ್ನು ನವೀಕರಿಸಲು ವಿಫಲವಾಗಿದೆ - https://kernelsu.org/guide/what-is-kernelsu.html - %1$s ನಲ್ಲಿ ಮೂಲ ಕೋಡ್ ಅನ್ನು ವೀಕ್ಷಿಸಿ
ನಮ್ಮ %2$s ಚಾನಲ್‌ಗೆ ಸೇರಿ
- ಮ್ಯಾನೇಜರ್ ವರ್ಷನ್ - ಹೊಸ ಆವೃತ್ತಿ: %s ಲಭ್ಯವಿದೆ, ಅಪ್‌ಗ್ರೇಡ್ ಮಾಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ - ಲಾಗ್ಗಳನ್ನು ಉಳಿಸಿ -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-ko/strings.xml b/manager/app/src/main/res/values-ko/strings.xml deleted file mode 100644 index 7c29cc02..00000000 --- a/manager/app/src/main/res/values-ko/strings.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - 설치되지 않음 - 이 곳을 눌러 설치하기 - 정상 작동 중 - 버전: %d - 루트 권한: %d개 - 설치된 모듈: %d개 - 지원되지 않음 - KernelSU는 현재 GKI 커널만 지원합니다 - 커널 - 매니저 버전 - 빌드 정보 - SELinux 상태 - 비활성화됨 - 적용 - 허용 - 알 수 없음 - 슈퍼유저 - 모듈 활성화 실패: %s - 모듈 비활성화 실패: %s - 설치된 모듈 없음 - 모듈 - 삭제 - 설치 - 설치 - 다시 시작 - 설정 - 빠른 다시 시작 - 복구 모드로 다시 시작 - 부트로더로 다시 시작 - 다운로드 모드로 다시 시작 - EDL 모드로 다시 시작 - 정보 - %s 모듈을 삭제할까요? - %s 모듈 삭제됨 - 모듈 삭제 실패: %s - 버전 - 제작자 - overlayfs 사용 불가, 모듈을 사용할 수 없습니다! - 새로고침 - 시스템 앱 보이기 - 시스템 앱 숨기기 - 로그 보내기 - 안전 모드 - 다시 시작하여 변경 사항 적용 - Magisk와의 충돌로 인해 모듈을 사용할 수 없습니다! - KernelSU 알아보기 - KernelSU 설치 방법과 모듈 사용 방법을 확인합니다 - 지원이 필요합니다 - KernelSU는 지금도, 앞으로도 항상 무료이며 오픈 소스로 유지됩니다. 기부를 통해 여러분의 관심을 보여주세요. - %2$s 채널 참가하기]]> - https://kernelsu.org/guide/what-is-kernelsu.html - 앱 프로필 메뉴의 \"모듈 사용 해제\" 설정에 대한 전역 기본값을 설정합니다. 활성화 시, 개별 프로필이 설정되지 않은 앱은 시스템에 대한 모듈의 모든 수정사항이 적용되지 않습니다. - 다시 시작 - 규칙 - 새 버전: %s 사용 가능, 여기를 눌러서 받기 - 다운로드 시작: %s - 강제 중지 - 기본값 - 사용자 지정 - 템플릿 - 프로필 이름 - 이름 공간 마운트 - 상속 - 전역 - 개별 - 사용자 그룹 - 모듈 사용 해제 - SELinux 컨텍스트 - 권한 - %s에 대한 앱 프로필 업데이트 실패 - 기본값으로 모듈 사용 해제 - 이 옵션이 활성화되면, KernelSU는 이 애플리케이션에 대한 모듈의 모든 수정사항을 복구합니다. - 업데이트 - 모듈 받는 중: %s - 도메인 - 실행 - 다음 앱에 대한 SELinux 규칙 업데이트 실패: %s - 로그 저장 - \ No newline at end of file diff --git a/manager/app/src/main/res/values-lt/strings.xml b/manager/app/src/main/res/values-lt/strings.xml deleted file mode 100644 index cba5f5b1..00000000 --- a/manager/app/src/main/res/values-lt/strings.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - Pirštų atspaudas - Išjungta - Priverstinas - Nežinomas - Supernaudotojai - Nepavyko įjungti modulio: %s - Nepavyko išjungti modulio: %s - Leistinas - Nėra įdiegtų modulių - Moduliai - Perkrovimas neišjungus - Perkrauti į atkūrimo rėžimą - Perkrauti į įkrovos tvarkyklę - Perkrauti į atsisiuntimo rėžimą - Apie - Nepavyko išdiegti: %s - %s išdiegtas - Versija - Autorius - overlayfs nepasiekiamas, modulis negali veikti! - Rodyti sistemos programas - Slėpti sistemos programas - Siųsti žurnalą - Paleisti iš naujo - Atšviežinti - Saugus rėžimas - Paleiskite iš naujo, kad įsigaliotų - Moduliai yra išjungti, nes jie konfliktuoja su Magisk\'s! - https://kernelsu.org/guide/what-is-kernelsu.html - Sužinokite apie KernelSU - Sužinokite, kaip įdiegti KernelSU ir naudoti modulius - Peržiūrėkite šaltinio kodą %1$s
Prisijunkite prie mūsų %2$s kanalo
- Numatytas - Šablonas - Pasirinktinis - Profilio pavadinimas - Prijungti vardų erdvę - Paveldėtas - Globalus - Individualus - Grupės - Galimybės - SELinux kontekstas - Atjungti modulius - Atjungti modulius pagal numatytuosius parametrus - Įjungus šią parinktį, KernelSU galės atkurti visus modulių modifikuotus failus šiai programai. - Domenas - Taisyklės - Atnaujinti - Atsisiunčiamas modulis: %s - Pradedamas atsisiuntimas: %s - Nauja versija: %s pasiekiama, spustelėkite norėdami atsinaujinti - Paleisti - Priversti sustoti - Perkrauti - Nepavyko atnaujinti SELinux taisyklių: %s - Namai - Neįdiegta - KernelSU dabar palaiko tik GKI branduolius - Spustelėkite norėdami įdiegti - Veikia - Supernaudotojai: %d - Versija: %d - Nepalaikoma - Moduliai: %d - Tvarkyklės versija - Branduolys - SELinux statusas - Išdiegti - Įdiegti - Įdiegti - Parametrai - Perkrauti į EDL - Ar tikrai norite išdiegti modulį %s\? - Paremkite mus - KernelSU yra ir visada bus nemokamas ir atvirojo kodo. Tačiau galite parodyti, kad jums rūpi, paaukodami mums. - Nepavyko atnaujinti programos profilio %s - Visuotinė numatytoji „Modulių atjungimo“ reikšmė programų profiliuose. Jei įjungta, ji pašalins visus sistemos modulio pakeitimus programoms, kurios neturi profilio. - Keitimų žurnalas - Ši KernelSU versija %d yra per žema, kad šis vadybininkas galėtų tinkamai funkcionuoti. Prašome atsinaujinti į versiją %d ar aukščiau! - Saglabāt Žurnālus -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-lv/strings.xml b/manager/app/src/main/res/values-lv/strings.xml deleted file mode 100644 index c264b76a..00000000 --- a/manager/app/src/main/res/values-lv/strings.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - Iespējojot šo opciju, KernelSU varēs atjaunot visus moduļos šīs lietojumprogrammas modificētos failus. - Neizdevās atjaunināt SELinux noteikumus: %s - Pārvaldiet vietējo un tiešsaistes lietotņu profila veidni - Nederīgs veidnes id - veidnes id jau pastāv! - Eksportēt starpliktuvē - Importēt no starpliktuves - Importēts veiksmīgi - Sinhronizēt tiešsaistes veidnes - Sākums - Nav ieinstalēts - Noklikšķiniet, lai instalētu - Darbojas - Versija: %d - Superlietotāji: %d - Moduļi: %d - Neatbalstīts - KernelSU atbalsta tikai GKI kodolus - Kodols - Pārvaldnieka versija - Pirkstu nospiedums - SELinux statuss - Izpildīšana - Atspējots - Nezināms - SuperLietotājs - Neizdevās atspējot moduli: %s - Nav instalētu moduļu - Moduļi - Atinstalēt - Instalēt - Restartēt - Iestatījumi - Ātri restartēt - Restartēt uz Bootloaderu - Restartēt uz Recovery - Restartēt uz Download - Restartēt uz EDL - Par - %s ir atinstalēts - Neizdevās atinstalēt: %s - Autors - Atjaunot - Rādīt sistēmas lietotnes - Slēpt sistēmas lietotnes - Ziņot žurnālu - Restartējiet, lai stātos spēkā - Uzzināt par KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Uzzināt, kā instalēt KernelSU un izmantot moduļus - Atbalsti mūs - Skatiet avota kodu vietnē %1$s
Pievienojies mūsu %2$s kanālam
- Noklusējums - Veidne - Pielāgots - Profila vārds - Mount nosaukumvieta - Individuāls - Iespējas - SELinux konteksts - Atvienot moduļus - Neizdevās atjaunināt lietotnes profilu %s - Pēc noklusējuma atvienot moduļus - Globālā noklusējuma vērtība vienumam “Atvienot moduļus” lietotņu profilos. Ja tas ir iespējots, lietojumprogrammām, kurām nav iestatīts profils, tiks noņemtas visas sistēmas moduļu modifikācijas. - Domēns - Noteikumi - Atjaunināt - Lejupielādē moduli: %s - Sākt lejupielādi: %s - Jaunā versija: %s ir pieejama, noklikšķiniet, lai atjauninātu - Palaist - Piespiedu apstāšana - Restartēt aplikāciju - Izmaiņu žurnāls - Lietotnes profila veidne - Izveidot veidni - Rediģēt veidni - id - Vārds - Apraksts - Saglabāt - Dzēst - Skatīt veidni - tikai lasīt - Importēt/Eksportēt - Nevar atrast vietējo eksportējamo veidni! - Neizdevās saglabāt veidni - Starpliktuve ir tukša! - Izmaiņu žurnāla iegūšana neizdevās: %s - Visatļautība - Neizdevās iespējot moduli: %s - Instalēt - Vai tiešām vēlaties atinstalēt moduli %s? - Versija - overlayfs nav pieejams, modulis nevar darboties! - Drošais režīms - Moduļi ir atspējoti, jo tie konfliktē ar Magisk! - KernelSU ir un vienmēr būs bezmaksas un atvērtā koda. Tomēr jūs varat parādīt mums, ka jums rūp, veicot ziedojumu. - Grupas - Globāli - Pašreizējā KernelSU versija %d ir pārāk zema, lai pārvaldnieks darbotos pareizi. Lūdzu, atjauniniet uz versiju %d vai jaunāku! - Iespējot WebView atkļūdošanu - Ieteicams %1$s nodalījuma attēls - Nākamais - Mantots - Izvēlieties failu - Instalēt neaktīvajā slotā (pēc OTA) - Pēc restartēšanas jūsu ierīce tiks **PIESPIESTI** palaista pašreizējā neaktīvajā slotā! -\nIzmantojiet šo opciju tikai pēc OTA pabeigšanas -\nTurpināt? - Tiešā instalēšana (Ieteicams) - Atinstalēt - Pagaidu atinstalēšana - Atjaunot oriģinālo attēlu - Īslaicīgi atinstalēt KernelSU, pēc nākamās restartēšanas atjaunot sākotnējo stāvokli. - KernelSU (saknes un visu moduļu) pilnīga atinstalēšana. - Atjaunojot rūpnīcas attēlu (ja ir dublējums), ko parasti izmanto pirms OTA; ja nepieciešams atinstalēt KernelSU, lūdzu, izmantojiet \"Neatgriezeniski atinstalēt\". - Izvēlētais lkm: %s - Neizdevās piešķirt sakni! - Atvērt - Pārbaudīt atjauninājumus - Automātiski pārbaudīt atjauninājumus atverot aplikāciju - Var izmantot WebUI atkļūdošanai, lūdzu, izmantot tikai tad, kad tas ir nepieciešams. - Izvēlieties KMI - Neatgriezeniski atinstalēt - Instalē - Instalēts veiksmīgi - Instalēšana neizdevās - Samazināt reto attēlu - Mainīt retā attēla izmēru, kurā atrodas modulis, līdz tā faktiskajam izmēram. Ņemiet vērā, ka tas var izraisīt moduļa neparastu darbību, tāpēc, lūdzu, izmantojiet tikai nepieciešamības gadījumā (piemēram, dublēšanai) - Išsaugoti Žurnalus -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-mr/strings.xml b/manager/app/src/main/res/values-mr/strings.xml deleted file mode 100644 index eaaf2a25..00000000 --- a/manager/app/src/main/res/values-mr/strings.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - इंस्टॉल केले नाही - होम - इंस्टॉल साठी क्लिक करा - कार्यरत - आवृत्ती: %d - मॉड्यूल्स: %d - सुपरयूझर: %d - असमर्थित - KernelSU आता फक्त GKI कर्नलचे समर्थन करते - कर्नल - फिंगरप्रिंट - व्यवस्थापक आवृत्ती - SELinux स्थिती - अक्षम - एनफोर्सिंग - परमिसिव - अज्ञात - स्थापित करा - कोणतेही मॉड्यूल स्थापित केलेले नाही - रीबूट करा - सुपरयुझर - मॉड्यूल सक्षम करण्यात अयशस्वी: %s - विस्थापित करा - मॉड्यूल अक्षम करण्यात अयशस्वी: %s - मॉड्यूल - स्थापित करा - सेटिंग्ज - सॉफ्ट रीबूट - बद्दल - EDL वर रीबूट करा - तुमची खात्री आहे की तुम्ही मॉड्यूल %s विस्थापित करू इच्छिता\? - विस्थापित करण्यात अयशस्वी: %s - overlayfs उपलब्ध नाही, मॉड्यूल काम करू शकत नाही! - सिस्टम अॅप्स दाखवा - बूटलोडरवर रीबूट करा - %s विस्थापित - आवृत्ती - लेखक - रिफ्रेश करा - रिकवरी मध्ये रिबुट करा - डाउनलोड करण्यासाठी रीबूट करा - लॉग पाठवा - सुरक्षित मोड - सिस्टम अॅप्स लपवा - प्रभावी होण्यासाठी रीबूट करा - KernelSU शिका - https://kernelsu.org/guide/what-is-kernelsu.html - मॉड्यूल अक्षम केले आहेत कारण ते Magisk च्या विरोधाभास आहे! - KernelSU कसे स्थापित करायचे आणि मॉड्यूल कसे वापरायचे ते शिका - KernelSU विनामूल्य आणि मुक्त स्रोत आहे, आणि नेहमीच असेल. तथापि, देणगी देऊन तुम्ही आम्हाला दाखवू शकता की तुमची काळजी आहे. - आम्हाला पाठिंबा द्या - कस्टम - माउंट नेमस्पेस - डीफॉल्ट - साचा - वैयक्तिक - क्षमता - %1$s वर स्रोत कोड पहा
आमच्या %2$s चॅनेलमध्ये सामील व्हा
- प्रोफाइल नाव - इनहेरीटेड - जागतिक - गट - SELinux संदर्भ - उमाउंट मॉड्यूल्स - %s साठी अॅप प्रोफाइल अपडेट करण्यात अयशस्वी - डीफॉल्टनुसार मॉड्यूल्स उमाउंट करा - अॅप प्रोफाइलमधील \"उमाउंट मॉड्यूल्स\" साठी जागतिक डीफॉल्ट मूल्य. सक्षम असल्यास, ते प्रोफाइल सेट नसलेल्या ॲप्लिकेशनचे सिस्टममधील सर्व मॉड्यूल बदल काढून टाकेल. - हा पर्याय सक्षम केल्याने KernelSU ला या ऍप्लिकेशनसाठी मॉड्यूल्सद्वारे कोणत्याही सुधारित फाइल्स पुनर्संचयित करण्यास अनुमती मिळेल. - यासाठी SELinux नियम अपडेट करण्यात अयशस्वी: %s - नियम - अपडेट करा - डोमेन - मॉड्यूल डाउनलोड करत आहे: %s - डाउनलोड करणे सुरू करा: %s - नवीन आवृत्ती: %s उपलब्ध आहे, डाउनलोड करण्यासाठी क्लिक करा - सक्तीने थांबा - लाँच करा - पुन्हा सुरू करा - लॉग जतन करा -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-ms/strings.xml b/manager/app/src/main/res/values-ms/strings.xml deleted file mode 100644 index 46c1539c..00000000 --- a/manager/app/src/main/res/values-ms/strings.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Tidak Diketahui - Lumpuhkan - Permisif - Mulakan semula ke Download - Modul tidak berjaya Diaktifkan:%s - Mulakan semula ke EDL - Superusers%d - Modul%d - Enforcing - Cap Jari - Mulakan semula ke Recovery - Soft reboot - Padam - Pasang - Tekan untuk memasang - Modul - Tentang - Versi%d - Mulakan semula - KernelSU ketika ini hanya menyokong kernel GKI - Status SELinux - Tidak Disokong - Layar Utama - Apakah anda pasti ingin membuang modul %s\? - SuperUser - Tetapan - Berjalan - Gagal mematikan modul:%s - Tiada modul dipasang - Pasang - Kernel - Tidak terpasang - Mulakan semula ke bootloader - Versi Manager - Simpan Log - \ 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 10a773b1..00000000 --- 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 deleted file mode 100644 index 91abf657..00000000 --- a/manager/app/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ 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 deleted file mode 100644 index bebf3789..00000000 --- a/manager/app/src/main/res/values-nl/strings.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - Home - Niet geïnstalleerd - Klik om te installeren - Werkend - Versie: %d - Supergebruikers: %d - Modules: %d - Niet ondersteund - KernelSU ondersteunt alleen GKI kernels - Kernel - Manager Versie - Fingerprint - SELinux status - Uitgeschakeld - Afgedwongen - Permissief - Niet gekend - SupergeBruiker - Mislukt om module in te schakelen: %s - Mislukt om module uit te schakelen: %s - Geen geïnstalleerde modules - Module - Verwijderen - Installeren - Installeren - Herstart - Instellingen - Soft herstart - Herstart naar Recovery - Herstart naar Bootloader - Herstart om te downloaden - Herstart naar EDL - Over - Zeker van het verwijderen van module %s? - %s is verwijderd - Mislukt om te verwijderen: %s - Versie - Auteur - overlayfs is niet beschikbaar, module kan niet werken! - Vernieuwen - Toon systeem apps - Verberg systeem apps - Rapport Log - Safe mode - Herstart om effect te hebben - Modules zijn uitgeschakeld omdat ze in conflict zijn met magisk! - Leer KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Leer hoe KernelSU te installeren en modules te gebruiken - Ondersteun ons - KernelSU is, en zal altijd, vrij en open source zijn. Je kan altijd je appreciatie tonen met een donatie. - Vervoeg ons %2$s kanaal]]> - App profiel - Standaard - Sjabloon - Aangepast - Profiel naam - Koppel naamruimte - Overgenomen - Globaal - Individuëel - Groepen - Mogelijkheden - SELinux context - 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. - Domein - Regels - Update - Downloaden van module: %s - Nieuwe versie: %s is beschikbaar,klik om te upgraden - Start - 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! - wijzigings logboek - App-profiel Sjabloon - Maken Sjabloon - Bewerkin Sjabloon - id - Ongeldige sjabloon id - Naam - Redde - Bekijken Sjabloon - Beschrijving - Beheer lokale en online sjabloon van app-profiel - Verwijderen - alleen lezen - sjabloon id bestaat al! - Synchroniseer online-sjablonen - Mislukt naar opslaan sjabloon - Klembord is leeg! - Importeren/Exporteren - Importeren vanaf klembord - Ophalen van wijzigingslogboek mislukt: %s - Exporteren naar klembord - 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! - Succesvol geïmporteerd - Open - Controleer automatisch op updates bij het openen van de app - Directe installatie (aanbevolen) - 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) - %1$s partitie-image wordt aanbevolen - Naast - Uw apparaat wordt **GEFORCEERD** om na een herstart op te starten naar het huidige inactieve slot! -\nGebruik deze optie alleen nadat OTA is voltooid. -\nDoorgaan? - Installeren in inactief slot (na OTA) - KMI selecteren - Desinstalleren - Tijdelijk verwijderen - Permanent verwijderen - Herstel stockafbeelding - Verwijder KernelSU tijdelijk en herstel het naar de oorspronkelijke staat na de volgende herstart. - Logboeken Opslaan - \ 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 deleted file mode 100644 index b4fe83f3..00000000 --- a/manager/app/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - KernelSU - Strona główna - Nie zainstalowano - Kliknij, aby zainstalować - Działa - Wersja: %d - Superużytkownicy: %d - Moduły: %d - Nieobsługiwany - KernelSU obsługuje obecnie tylko jądra GKI - Jądro - Wersja menedżera - Odcisk - Status SELinux - Wyłączony - Enforcing - Dozwolony - Nieznany - Superużytkownik - Nie udało się włączyć modułu: %s - Nie udało się wyłączyć modułu: %s - Brak zainstalowanych modułów - Moduły - Odinstaluj - Instaluj - Instaluj - Uruchom ponownie - Ustawienia - Miękki restart - Restart do trybu Recovery - Restart do trybu Bootloader - Restart do trybu Download - Restart do trybu EDL - Informacje - Czy na pewno chcesz odinstalować moduł %s? - Odinstalowano %s - Nie udało się odinstalować:: %s - Wersja - Autor - overlayfs jest niedostępny, moduł nie zadziała! - Odśwież - Pokaż aplikacje systemowe - Ukryj aplikacje systemowe - Raportuj log - Tryb bezpieczny - Uruchom ponownie, aby zastosować zmiany - Moduły są wyłączone, ponieważ są w konflikcie z modułami Magiska! - Poznaj KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Dowiedz się jak zainstalować KernelSU i jak korzystać z modułów - Wesprzyj nas - KernelSU jest i zawsze będzie darmowy oraz otwarty. Niemniej jednak możesz nam pokazać, że Ci zależy, wysyłając darowiznę. - Dołącz do kanału %2$s]]> - Profil aplikacji - Domyślny - Szablon - Własny - Nazwa profilu - Przestrzeń nazw montowania - Odziedziczona - Globalna - Indywidualna - Grupy - Uprawnienia - Kontekst SELinux - 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. - 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ć - Uruchom - Wymuś zatrzymanie - Restartuj - Nie udało się zaktualizować reguł SELinux dla: %s - Obecna wersja KernelSU %d jest zbyt stara, aby menedżer działał poprawnie. Prosimy o aktualizację do wersji %d lub nowszej! - Dziennik zmian - Włącz debugowanie WebView - Może być użyte do debugowania WebUI. Włącz tylko w razie potrzeby. - Obraz partycji %1$s jest zalecany - Wybierz KMI - Dalej - Instalacja bezpośrednia (zalecane) - Wybierz plik - Zainstaluj do nieaktywnego slotu (po aktualizcji OTA) - Po ponownym uruchomieniu Twoje urządzenie zostanie **ZMUSZONE** do uruchomia się z obecnie nieaktywnego slotu! -\nUżyj tej opcji dopiero po zakończeniu aktualizacji OTA. -\nCzy chcesz kontynuować? - Stwórz szablon - Edytuj szablon - Nazwa - Opis - Zapisz - Usuń - tylko do odczytu - Importuj/Eksportuj - Importuj ze schowka - Eksportuj do schowka - Nie można znaleźć lokalnego szablonu do eksportu! - Zaimportowano pomyślnie - Nie udało się zapisać szablonu - Schowek jest pusty! - Zarządzaj lokalnym i internetowym szablonem profilu aplikacji - Synchronizuj internetowe szablony - Zobacz szablon - Błędny identyfikator szablonu - Szablon profilu aplikacji - Identyfikator - Szablon o takim identyfikatorze już istnieje! - Nie udało się przyznać roota! - Otwórz - Pobranie dziennika zmian nie powiodło się: %s - 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) - 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\". - Flashowanie - Flashowanie ukończone pomyślnie - Flashowanie nieudane - Wybrano lkm: %s - Zapisz Dzienniki - \ 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 deleted file mode 100644 index f092a451..00000000 --- a/manager/app/src/main/res/values-pt-rBR/strings.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - Início - Não instalado - Clique para instalar - Em execução - Versão: %d - SuperUsuários: %d - Módulos: %d - Sem suporte - KernelSU suporta apenas kernels GKI agora - Kernel - Versão do gerenciador - Impressão digital - Status do SELinux - Desativado - Impondo - Permissivo - Desconhecido - SuperUsuário - Falha ao ativar o módulo %s - Falha ao desativar o módulo %s - Nenhum módulo instalado - Módulo - Desinstalar - Instalar - Instalar - Reiniciar - Configurações - Reinicialização suave - Reiniciar em modo Recovery - Reiniciar em modo Bootloader - Reiniciar em modo Download - Reiniciar em modo EDL - Sobre - Tem certeza que deseja desinstalar o módulo %s? - %s desinstalado - Falha ao desinstalar %s - Versão - Autor - Os módulos estão indisponíveis porque OverlayFS está desabilitado pelo kernel! - Atualizar - Mostrar apps do sistema - Ocultar apps do sistema - Reportar registro - Modo de segurança - Reinicie para entrar em vigor - Os módulos estão indisponíveis devido a um conflito com Magisk! - Saiba mais sobre o KernelSU - https://kernelsu.org/pt_BR/guide/what-is-kernelsu.html - Saiba como instalar o KernelSU e usar os módulos - Apoie-nos - KernelSU sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode nos ajudar enviando uma pequena doação. - Junte-se ao nosso canal do %2$s]]> - Perfil do Aplicativo - Padrão - Modelo - Personalizado - Nome do perfil - Montar namespace - Herdado - Global - Individual - Grupos - Capacidades - Contexto do SELinux - Desmontar módulos - Falha ao atualizar o Perfil do Aplicativo para %s - Desmontar módulos por padrão - O valor padrão global para \"Desmontar módulos\" em Perfil do Aplicativo. Se ativado, ele removerá todas as modificações do módulo no sistema para apps que não possuem um perfil definido. - Ativar esta opção permitirá que o KernelSU restaure quaisquer arquivos modificados pelos módulos para este app. - Domínio - Regras - Atualizar - Baixando módulo %s - Começando a baixar %s - Nova versão %s está disponível, clique para atualizar. - Iniciar - Forçar parada - Reiniciar - Falha ao atualizar as regras do SELinux para: %s - A versão atual do KernelSU %d é muito baixa para o gerenciador funcionar corretamente. Por favor, atualize para a versão %d ou superior! - Registro de alterações - Importado com sucesso - Exportar para a área de transferência - Não foi possível encontrar o modelo local para exportar! - O ID do modelo já existe! - Importar da área de transferência - Falha ao buscar o registro de alterações: %s - Nome - ID do modelo inválido - Sincronizar modelos online - Criar modelo - Somente leitura - Importar/Exportar - Falha ao salvar o modelo - Editar modelo - ID - Modelo do Perfil do Aplicativo - Descrição - Salvar - Gerencie o modelo local e online do Perfil do Aplicativo - Excluir - A área de transferência está vazia! - Ver modelo - Verificar por atualização - Verifique automaticamente se há atualizações ao abrir o app - Falha ao conceder acesso root! - Abrir - Ativar depuração do WebView - Pode ser usado para depurar o WebUI. Por favor, ative somente quando necessário. - Selecione um arquivo - Instalação direta (recomendada) - Instalar no slot inativo (após o OTA) - Seu dispositivo será **FORÇADO** a inicializar no slot inativo atual após uma reinicialização! -\nSó use esta opção após a conclusão do OTA. -\nDeseja continuar? - Próximo - A imagem da partição %1$s é recomendada - Selecionar KMI - Minimizar imagem esparsa - Redimensione a imagem esparsa onde o módulo está localizado para seu tamanho real. Observe que isso pode fazer com que o módulo funcione de forma anormal, portanto, use-o somente quando necessário (como um backup). - Desinstalar - Desinstalar temporariamente - Desinstalar permanentemente - 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 - LKM selecionado: %s - Flash falhou - Flashando - Flash bem-sucedido - Salvar Logs - \ No newline at end of file diff --git a/manager/app/src/main/res/values-pt/strings.xml b/manager/app/src/main/res/values-pt/strings.xml deleted file mode 100644 index ea1547db..00000000 --- a/manager/app/src/main/res/values-pt/strings.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - Não instalado - Início - Clique para instalar - Funcionando - Super Usuário: %d - Módulos: %d - Versão: %d - Kernel - Instalar - Sem suporte - KernelSU suporta apenas kernels GKI agora - Status do SELinux - Versão do aplicativo - Falha ao desativar o módulo: %s - Impressão digital - Desabilitado - Impondo - Permissivo - Desconhecido - Super Usuário - Falha ao ativar o módulo: %s - Nenhum módulo instalado - Desinstalar - Modulos - Reiniciar - Instalar - Reinicialização Suave - Configurações - Reinicializar modo Bootloader - Reiniciar modo recuperação - Falha ao desinstalar: %s - Versão - Autor - Atualizar - Esconder apps do sistema - Reiniciar para baixar - Reiniciar em EDL - Tem certeza de que deseja desinstalar o módulo %s\? - Sobre - overlayfs não está disponível, o módulo não pode funcionar! - Enviar log - %s desinstalado - Mostrar aplicativos do sistema - Aprenda a instalar o KernelSU e usar os módulos - O KernelSU é, e sempre será, gratuito e de código aberto. No entanto, você pode nos mostrar que se importa fazendo uma doação. - Veja o código-fonte em %1$s
Junte-se ao nosso canal %2$s
- Individual - Global - Herdado - Padrão - Modelo - Personalizado - Nome do perfil - Montar namespace - Modo de segurança - Reinicie para entrar em vigor - Aprender KernelSU - Os módulos estão desativados porque estão em conflito com os do Magisk! - Apoie-nos - Grupos - Capacidades - contexto SELinux - Domínio - Atualização - Desativar modulos - Falha ao atualizar o perfil do aplicativo para %s - Módulos desativados por padrão - O valor padrão global para \"Módulos Umount\" em Perfis de Aplicativos. Se ativado, removerá todas as modificações de módulo do sistema para aplicativos que não possuem um Perfil definido. - Regras - Ativar esta opção permitirá que o KernelSU restaure quaisquer arquivos modificados pelos módulos para este aplicativo. - Iniciar o download: %s - Baixando módulo: %s - Falha ao atualizar as regras do SELinux para: %s - https://kernelsu.org/guide/what-is-kernelsu.html - Reiniciar - Lançar - Forçar parada - Nova versão: %s está disponível, clique para baixar - A versão atual do KernelSU %d é muito baixa para o gerenciador funcionar corretamente. Atualize para a versão %d ou superior! - Salvar Registros -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-ro/strings.xml b/manager/app/src/main/res/values-ro/strings.xml deleted file mode 100644 index fea3ffb6..00000000 --- a/manager/app/src/main/res/values-ro/strings.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - Acasă - Nu este instalat - Click pentru a instala - Funcționează - Versiune: %d - Super-utilizatori: %d - Module: %d - Necompatibil - KernelSU suportă doar nuclee GKI acum - Nucleu - Versiune Manager - Amprentă - Stare SELinux - Dezactivat - Obligatoriu - Permisiv - Necunoscut - Super-Utilizator - Activarea modulului %s a eșuat - Dezactivarea modulului %s a eșuat - Niciun modul instalat - Module - Dezinstalează - Instalează - Instalează - Repornește - Setări - Repornire rapidă - Repornire în Recuperare - Repornire în Bootloader - Repornire în Download - Repornire în EDL - Despre - Sigur dorești să dezinstalezi modulul %s? - %s dezinstalat - Dezinstalare eșuată: %s - Versiune - Autor - overlayfs nu este disponibil, modulul nu poate funcționa! - Reîmprospătează - Arată aplicațiile de sistem - Ascunde aplicațiile de sistem - Raportează jurnal - Mod sigur - Repornește pentru ca modificările să intre în vigoare - Modulele sunt dezactivate deoarece sunt în conflict cu cele ale Magisk-ului! - Află mai multe despre KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Află cum să instalezi KernelSU și să utilizezi module - Suport - KernelSU este, și va fi întotdeauna, gratuit și cu codul sursă deschis. Cu toate acestea, ne poți arăta că îți pasă făcând o donație. - Alătură-te canalului nostru %2$s]]> - Implicit - Șablon - Personalizat - Nume profil - Montare spațiu de nume - Moștenit - Global - Individual - Grupuri - Capabilități - Context SELinux - Module u-montate - Nu s-a putut actualiza profilul aplicației pentru %s - U-montează modulele în mod implicit - Valoarea implicită globală pentru „Module u-montate” în Profilurile aplicațiilor. Dacă este activat, va elimina toate modificările modulelor aduse sistemului pentru aplicațiile care nu au un profil setat. - Activarea acestei opțiuni va permite KernelSU să restaureze orice fișiere modificate de către modulele pentru această aplicație. - Domeniu - Reguli - Actualizează - Se descarcă modulul: %s - Începe descărcarea: %s - Versiune nouă: %s este disponibilă, clic pentru a actualiza - Nu s-au reușit actualizările regulilor SELinux pentru: %s - Lansare - Oprire forțată - Repornește - Versiunea actuală a KernelSU %d este prea mică pentru ca managerul să funcționeze corect. Actualizează la versiunea %d sau o versiune superioară! - Jurnalul modificărilor - Importat cu succes - Export în clipboard - Nu există șabloane locale de exportat! - ID-ul șablonului există deja! - Import din clipboard - Preluarea jurnalului de modificări a eșuat: %s - Nume - ID șablon nevalid - Sincronizează șabloanele online - Creează un șablon - doar citire - Import/Export - Nu s-a salvat șablonul - Editează șablonul - ID - Șablon de profil al aplicației - Descriere - Salvează - Gestionează șablonul local și online al Profilului aplicației - Șterge - Clipboard-ul este gol! - Vizualizare șablon - Verifică actualizarea - Se verifică automat actualizările când deschizi aplicația - Activează depanarea WebView - Poate fi folosit pentru a depana WebUI, activează numai când este necesar. - Nu s-a acordat acces root! - Deschide - Se recomandă imaginea partiției %1$s - Înainte - Dispozitivul va fi **FORȚAT** să pornească în slot-ul inactiv curent după o repornire! -\nFolosește această opțiune numai după finisarea OTA. -\nContinui? - Selectează KMI - Instalare directă (recomandat) - Selectează un fișier - Instalează într-un slot inactiv (după OTA) - Dezinstalează - Restaurare imagine stoc - Dezinstalează temporar KernelSU, se revine la starea inițială după următoarea repornire. - Lkm selectat: %s - Dezinstalează temporar - Dezinstalează definitiv - Dezinstalare KernelSU (Root și toate modulele) complet și permanent. - Restaurează imaginea stoc din fabrică (dacă există o copie de rezervă), utilizată de obicei înainte de OTA; dacă trebuie să dezinstalezi KernelSU, utilizează „Dezinstalare permanentă”. - Instalare - Instalare reușită - Instalarea a eșuat - Salvează Jurnale - \ 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 deleted file mode 100644 index 91dd276f..00000000 --- a/manager/app/src/main/res/values-ru/strings.xml +++ /dev/null @@ -1,138 +0,0 @@ - - - Главная - Не установлен - Нажмите, чтобы установить - Работает - Версия: %d - Суперпользователи: %d - - Модули: %d - Не поддерживается - KernelSU поддерживает только GKI ядра - Ядро - Версия менеджера - Подпись - Состояние SELinux - Выключен - Принудительный - Разрешающий - Неизвестно - SU пользователь - - Не удалось включить модуль: %s - Не удалось отключить модуль: %s - Нет установленных модулей - Модули - Удалить - Установить - Установка - Перезагрузить - Настройки - Мягкая перезагрузка - Перезагрузить в Recovery - Перезагрузить в Bootloader - Перезагрузить в Download - Перезагрузить в EDL - О приложении - Вы уверены, что хотите удалить модуль %s? - %s удален - Не удалось удалить: %s - Версия - Автор - overlayfs недоступен, модуль не может работать! - Обновить страницу - Показать системные приложения - Скрыть системные приложения - Отправить лог - Безопасный режим - Перезагрузите, чтобы изменения вступили в силу - Модули отключены, потому что они конфликтуют с Magisk! - Узнайте о KernelSU - https://kernelsu.org/ru_RU/guide/what-is-kernelsu.html - Узнайте, как установить KernelSU и использовать модули - Поддержите нас - KernelSU был и всегда будет бесплатным и открытым проектом. Однако Вы всегда можете поддержать нас, отправив небольшое пожертвование. - Присоединяйтесь к нашему %2$s каналу]]> - App Profile - - По умолчанию - Шаблон - Пользовательский - Название профиля - Монтировать пространство имен - Унаследованный - Глобальный - Индивидуальный - Группы - Возможности - Контекст SELinux - Размонтировать модули - Не удалось обновить App Profile для %s - Размонтировать модули по умолчанию - Глобальное значение по умолчанию для \"Размонтировать модули\" в App Profile. При включении будут удалены все модификации модулей в системе для приложений, у которых не задан Profile. - Включение этой опции позволит KernelSU восстанавливать любые измененные модулями файлы для данного приложения. - Домен - Правила - Обновить - Скачивание модуля: %s - Начало скачивания: %s - Новая версия: %s доступна, нажмите, чтобы скачать - Принудительно остановить - Не удалось обновить правила SELinux для %s - Запустить - Перезапустить - Текущая версия KernelSU %d слишком низкая для правильной работы менеджера. Пожалуйста, обновите до версии %d или выше! - Список изменений - Успешный импорт - Экспортировать в буфер обмена - Нет локальных шаблонов для экспорта! - Шаблон с таким id уже существует! - Импортировать из буфера обмена - Не удалось получить список изменений: %s - Название - Неверный id шаблона - Синхронизировать онлайн-шаблоны - Создать шаблон - только чтение - Импорт/Экспорт - Не удалось сохранить шаблон - Редактирование шаблона - Идентификационный номер - Шаблон профиля приложения - Описание - Сохранить - Управление локальным и онлайн-шаблоном профиля приложения - Удалить - Буфер обмена пуст! - Просмотр шаблона - Проверка обновлений - Автоматическая проверка обновлений при открытии приложения - Не удалось выдать root! - Открыть - Включить отладку WebView - Используется для отладки WebUI. Пожалуйста, включайте только при необходимости. - Прямая установка (Рекомендуется) - Установка в неактивный слот (После OTA) - Далее - Выбрать файл - Ваше устройство будет **ПРИНУДИТЕЛЬНО** загружено в текущий неактивный слот после перезагрузки! -\n Используйте эту опцию только после завершения OTA. -\n Продолжить? - Выбрать KMI - %1$s образ раздела рекомендуется - Минимизировать разреженный образ - Изменить размер разреженного образа в котором находятся модули, до его фактического размера. Обратите внимание, что это может вызвать ненормальную работу модулей, поэтому используйте это только при необходимости (например, для резервного копирования) - Удалить Временно - Удалить KernelSU (Root и все модули) полностью и навсегда. - Удалить Навсегда - Временно удалить KernelSU, восстановить исходное состояние после следующей перезагрузки. - Удалить - Восстановить Сток образ - Восстановить стоковый заводской образ (если существует резервная копия), обычно используется перед OTA; если вам нужно удалить KernelSU, используйте «Удалить Навсегда». - Установка выполнена - Установка - Установка не выполнена - Выбран lkm: %s - Сохранить Журналы - \ No newline at end of file diff --git a/manager/app/src/main/res/values-sl/strings.xml b/manager/app/src/main/res/values-sl/strings.xml deleted file mode 100644 index ae02e596..00000000 --- a/manager/app/src/main/res/values-sl/strings.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - Klikni za namestitev - V obdelavi - Verzija: %d - Superuporabniki: %d - KernelSU podpira samo GKI kernele - Kernel - Verzija upravitelja - Prstni odtis - SELinux status - Onemogočeno - Neznano - Napaka pri onemogočanju modula: %s - Ni nameščenih modulov - Modul - Odmesti - Namesti - Namesti - Mehki ponovni zagon - Ponovni zagon v Recovery - Ponovni zagon v Bootloader - Ponovni zagon v EDL - Ste prepričani, da želite odstraniti modul %s? - %s je odmeščen - Avtor - overlayfs ni na voljo, modul ne more delovati! - Skrij prikaz sistemskih aplikacij - Prijavite dnevnik - Naučite se KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Naučite se, kako namestiti KernelSU in uporabiti module - Glej odprto kodo na %1$s
Pridružite se našem %2$s kanalu
- Privzeto - Predloga - Imenski prostor vmestitve - Podedovano - Globalno - Pozameznik - Zmožnosti - Izvrzi module - Po privzetem izvrzi module - Domena - Posodobitev - Nalaganje modula: %s - Zaženi - Ponovni zagon - Dnevnik sprememb - Predloga za aplikacijski profil - Domov - Moduli: %d - Ne podpira - SuperUporabnik - Napaka pri omogočanju modula: %s - Znova zaženi - Nastavitve - Ponovni zagon v Download - O nas - Verzija - Napaka pri odmeščanju: %s - Osveži - Varni način - Za uveljavitev je potreben ponovni zagon - Prikaz sistemskih aplikacij - Moduli so onemogočeni, ker so v konfliktu z Magiskovimi! - Podprite nas - Po meri - Ime profila - Skupine - SELinux kontekst - KernelSU je, in bo vedno brezplačen in odprtokoden. Kljub temu, nam lahko z donacijo pokažete, da vam je mar. - Napaka pri posodobitvi aplikacijskega profila za %s - Za pravilno funkionalnost upravitelja je trenutna KernelSU verzija %d prenizka. Potrebna je nadgradnja na verzijo %d ali več! - Globalno privzeta vrednost za \"Izvrzi module\" v aplikacijskih profilih. Če je omogočena, bo to odstranilo vse sistemske modifikacije modulov za aplikacije, ki nimajo nastavljenega profila. - Omogočanje te opcije bo dovolilo KernelSU, da obnovi vse zaradi modulov spremenjene datoteke za to aplikacijo. - Prisilna ustavitev - Pravila - Začni z nalaganjem: %s - Na voljo je nova verzija: %s, kliknite za nadgradnjo - Napaka pri posodobitvi SELinux pravil za: %s - Ni nameščeno - Enforcing - Permissive - Ustvari predlogo - Uredi predlogo - Neveljaven id predloge - Opis - Shrani - Odstrani - le za branje - id predloge že obstaja! - Uvoz iz odložišča - Izvoz v odložišče - Lokalna predloga za izvoz ni bila najdena! - Napaka pri shranjevanju predloge - Odložišče je prazno! - Upravljaj z lokalnimi in spletnimi predlogami za aplikacijski profil - id - Ime - Ogled predloge - Uvoz uspešen - Sinhroniziraj predloge iz spleta - Uvoz/Izvoz - Napaka pri pridobivanju dnevnika sprememb: %s - Shrani Dnevnike -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-sr/strings.xml b/manager/app/src/main/res/values-sr/strings.xml deleted file mode 100644 index 73920b6f..00000000 --- a/manager/app/src/main/res/values-sr/strings.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Superkorisnici - Moduli: %d - Додирните да бисте инсталирали - Почетна - Није инсталирано - Верзија: %d - Ради - Сачувај Дневнике - \ No newline at end of file diff --git a/manager/app/src/main/res/values-te/strings.xml b/manager/app/src/main/res/values-te/strings.xml deleted file mode 100644 index f6095426..00000000 --- a/manager/app/src/main/res/values-te/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - తెలియదు - మాడ్యూల్‌ని ప్రారంభించడంలో విఫలమైంది: %s - బలవంతంగా ఆపడం - పునఃప్రారంభించండి - మాడ్యూల్ - గురించి - SELinux స్థితి - హోమ్ - సూపర్యూజర్ - మాడ్యూల్‌ని నిలిపివేయడంలో విఫలమైంది: %s - మాడ్యూల్ ఏదీ ఇన్‌స్టాల్ చేయబడలేదు - ఇన్‌స్టాల్ చేయలేదు - ఇన్‌స్టాల్ చేయడానికి క్లిక్ చేయండి - పని చేస్తోంది - వెర్షన్: %d - సూపర్‌యూజర్‌లు: %d - మాడ్యూల్స్: %d - లాగ్‌లు సేవ్ చేయండి - \ 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 deleted file mode 100644 index 50bb145e..00000000 --- a/manager/app/src/main/res/values-th/strings.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - หน้าหลัก - ยังไม่ได้ติดตั้ง - กดเพื่อติดตั้ง - กำลังทำงาน - เวอร์ชั่น: %d - เวอร์ชั่นตัวจัดการ - สิทธิ์ผู้ใช้ขั้นสูง: %d - โมดูล: %d - ไม่รองรับ - Enforcing - รีบูตเข้าสู่โหมดกู้คืน - ซอฟต์รีบูต - ตอนนี้ KernelSU รองรับเคอร์เนลประเภท GKI เท่านั้น - เคอร์เนล - ปิดใช้งาน - ลายนิ้วมือ - สถานะ SELinux - Permissive - ไม่ทราบ - สิทธิ์ผู้ใช้ขั้นสูง - ล้มเหลวในการเปิดใช้งานโมดูล: %s - ล้มเหลวในการปิดใช้งานโมดูล: %s - ไม่มีโมดูลที่ติดตั้ง - โมดูล - ถอนการติดตั้ง - ตั้งค่า - ติดตั้ง - ติดตั้ง - รีบูต - รีบูตเข้าสู่โหมด Bootloader - เกี่ยวกับ - รีบูตเข้าสู่โหมด Download - รีบูตเข้าสู่โหมด EDL - %s ถอนการติดตั้งสำเร็จ - ล้มเหลวในการถอนการติดตั้ง: %s - overlayfs ไม่สามารถใช้งานได้ โมดูลหยุดทำงาน! - คุณแน่ใจว่าจะถอนการติดตั้งโมดูล %s หรือไม่\? - ผู้สร้าง - เวอร์ชั่น - แสดงแอประบบ - ซ่อนแอประบบ - รีเฟรช - ส่งรายงาน Log - โหมดปลอดภัย - รีบูตเพื่อให้มีผล - โมดูลถูกปิดใช้งานเนื่องจากขัดแย้งกับ Magisk! - เรียนรู้เกี่ยวกับ KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - เรียนรู้วิธีการติดตั้ง KernelSU และวิธีใช้งานโมดูลต่าง ๆ - สนับสนุนพวกเรา - KernelSU เป็นโอเพ่นซอร์สฟรีทั้งจากนี้และตลอดไป อย่างไรก็ตาม คุณสามารถแสดงความห่วงใยได้ด้วยการบริจาค - ดูซอร์สโค้ดที่ %1$s
และเข้าร่วมช่อง %2$s ของเรา
- กำหนดเอง - ค่าเริ่มต้น - เทมเพลต - ชื่อโปรไฟล์ - Mount เนมสเปซ - ทั่วไป - สืบทอด - ส่วนบุคคล - หมวดหมู่ - ความสามารถของแอป - การเปิดใช้งานตัวเลือกนี้จะทำให้ KernelSU สามารถกู้คืนไฟล์ที่แก้ไขโดยโมดูลสำหรับแอปพลิเคชั่นนี้ได้ - บริบท SELinux - Umount โมดูล - ไม่สามารถอัปเดตโปรไฟล์แอปสำหรับ %s ได้ - Umount โมดูลตามค่าเริ่มต้น - โดเมน - อัปเดต - กฎ - กำลังดาวน์โหลดโมดูล: %s - กำลังเริ่มดาวน์โหลด: %s - เวอร์ชั่นใหม่: %s พร้อมใช้งาน โปรดคลิกเพื่ออัปเกรด - บังคับหยุด - รีสตาร์ท - หากเปิดใช้งานค่าเริ่มต้นโดยทั่วไปสำหรับ \"Umount โมดูล\" ในโปรไฟล์แอป จะเป็นการลบการแก้ไขโมดูลทั้งหมดในระบบสำหรับแอปพลิเคชั่นที่ไม่มีการตั้งค่าโปรไฟล์ - เปิด - ไม่สามารถอัปเดตกฎ SElinux สำหรับ: %s ได้ - KernelSU เวอร์ชั่น %d ต่ำเกินไป ทำให้ตัวจัดการไม่สามารถใช้งานได้อย่างถูกต้อง โปรดอัปเกรดเป็นเวอร์ชั่น %d หรือที่สูงกว่า! - บันทึกการเปลี่ยนแปลง - นำเข้าเสร็จสิ้น - ส่งออกไปยังคลิปบอร์ด - ไม่พบเทมเพลตในเครื่องที่จะส่งออก! - มีไอดีเทมเพลตนี้อยู่แล้ว! - นำเข้าจากคลิปบอร์ด - ชื่อ - ไอดีเทมเพลตไม่ถูกต้อง - ซิงค์เทมเพลตออนไลน์ - สร้างเทมเพลต - อ่านเท่านั้น - นำเข้า/ส่งออก - ไม่สามารถบันทึกเทมเพลต - แก้ไขเทมเพลต - ไอดี - เทมเพลตโปรไฟล์แอป - คำอธิบาย - บันทึก - จัดการเทมเพลตโปรไฟล์แอปในเครื่องและเทมเพลตออนไลน์ - ลบ - คลิปบอร์ดว่างเปล่า! - ดูเทมเพลต - ดึงข้อมูลบันทึกการเปลี่ยนแปลงล้มเหลว: %s - เปิด - ไม่สามารถให้สิทธิ์รูทได้! - ตรวจสอบการอัปเดต - ตรวจสอบการอัปเดตโดยอัตโนมัติเมื่อเปิดแอป - เปิดใช้งานการแก้ไขข้อบกพร่อง WebView - เลือก KMI - ต่อไป - เลือกไฟล์ - ติดตั้งลงในสล็อตที่ไม่ใช้งาน (หลังจาก OTA) - ติดตั้งโดยตรง (แนะนำ) - แนะนำให้ใช้อิมเมจพาร์ติชั่น %1$s - สามารถใช้เพื่อดีบัก WebUI โปรดเปิดใช้งานเมื่อจำเป็นเท่านั้น - อุปกรณ์ของคุณจะถูก **บังคับ** ให้บูตไปยังสล็อตที่ไม่ได้ใช้งานหลังจากรีบูต! -\nโปรดใช้ตัวเลือกนี้หลังจาก OTA เสร็จแล้วเท่านั้น -\nดำเนินการต่อหรือไม่? - ลดความกระจายของอิมเมจ - ปรับขนาดความกระจายของอิมเมจในโมดูลให้เป็นขนาดจริง โปรดทราบว่านี่อาจทำให้โมดูลทำงานผิดปกติ โปรดใช้เมื่อจำเป็นเท่านั้น (เช่น การสำรองข้อมูล) - ถอนการติดตั้งถาวร - เรียกคืนอิมเมจดั้งเดิม - ถอนการติดตั้ง KernelSU ชั่วคราว จะคืนค่าเป็นสถานะดั้งเดิมหลังจากรีบูตในครั้งถัดไป - กำลังแฟลช - แฟลชสำเร็จ - แฟลชล้มเหลว - เลือก lkm: %s - ถอนการติดตั้ง - ถอนการติดตั้งชั่วคราว - การถอนการติดตั้ง KernelSU (การรูทและโมดูลทั้งหมด) อย่างสมบูรณ์โดยถาวร - คืนค่าโรงงานอิมเมจดั้งเดิม (หากมีข้อมูลสำรอง) ส่วนใหญ่มักใช้ก่อนทำการ OTA ซึ่งหากคุณต้องการถอนการติดตั้ง KernelSU โปรดใช้ \"ถอนการติดตั้งถาวร\" - บันทึกบันทึก -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-tr/strings.xml b/manager/app/src/main/res/values-tr/strings.xml deleted file mode 100644 index ed0bcd0f..00000000 --- a/manager/app/src/main/res/values-tr/strings.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - KernelSU - Ana Sayfa - Kurulmadı - Kurmak için tıklayın - Çalışıyor - Sürüm: %d - Süper kullanıcılar: %d - Modüller: %d - Desteklenmiyor - KernelSU şimdilik sadece GKI çekirdeklerini destekliyor - Çekirdek - Yönetici sürümü - Parmak izi - SELinux durumu - Devre dışı - Etkin (Enforcing) - Serbest (Permissive) - Bilinmiyor - Süper kullanıcı - Modül etkinleştirilemedi: %s - Modül devre dışı bırakılamadı: %s - Kurulu modül yok - Modül - Kaldır - Kur - Kur - Cihazı yeniden başlat - Ayarlar - Hızlı yeniden başlat - Kurtarma modunda yeniden başlat - Önyükleyici modunda yeniden başlat - İndirme modunda yeniden başlat - EDL modunda yeniden başlat - Hakkında - %s modülünü kaldırmak istediğinizden emin misiniz? - %s kaldırıldı - Kaldırma başarısız: %s - Sürüm - Geliştirici - overlayfs mevcut değil, modül çalışamaz! - Yenile - Sistem uygulamalarını göster - Sistem uygulamalarını gizle - Günlük raporu 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ı! - 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 - Bizi destekleyin - KernelSU ücretsiz ve açık kaynaklı bir yazılımdır ve her zaman öyle kalacaktır. Ancak bağış yaparak bize destek olduğunuzu gösterebilirsiniz. - %1$s adresinde kaynak kodunu görüntüleyin.
%2$s kanalımıza katılın.
- Uygulama profili - Varsayılan - Şablon - Özel - Profil adı - Ad alanını bağla - Kalıtsal - Küresel - Bireysel - Gruplar - Yetkinlikler - SELinux içeriği - Modüllerin bağlantısını kes - %s için uygulama profili güncellenemedi. - Mevcut KernelSU sürümü %d, yöneticinin düzgün çalışabilmesi için çok düşük. Lütfen %d sürümüne veya daha yüksek bir sürüme güncelleyin! - Varsayılan olarak modüllerin bağlantısını kes - Uygulama profilindeki \"Modüllerin bağlantısını kes\" seçeneği için varsayılan değer. Etkinleştirilirse, profil ayarı yapılmamış uygulamalar için modüllerin sistemde yaptığı tüm değişiklikler kaldırılacaktır. - Bu seçeneği etkinleştirmek, KernelSU\'nun bu uygulama için modüller tarafından değiştirilen dosyaları geri yüklemesine izin verir. - İsim alanı - Kurallar - Güncelle - Modül indiriliyor: %s - İndirme başladı: %s - Yeni sürüm: %s mevcut, güncellemek için tıklayın - Uygulamayı başlat - Uygulamayı durmaya zorla - Uygulamayı yeniden başlat - %s için SELinux kuralları güncellenemedi. - Değişiklik geçmişi - Uygulama profili şablonu - Yerel ve çevrimiçi uygulama profili şablonlarını yönetin - Şablon oluştur - Şablonu düzenle - Kimlik - Geçersiz şablon kimliği - İsim - Açıklama - Kaydet - Sil - Şablonu görüntüle - salt okunur - Şablon kimliği zaten mevcut! - İçe aktar/Dışa aktar - Panodan içe aktar - Panodan dışa aktar - Dışa aktarmak için yerel şablon bulunamadı! - Başarıyla içe aktarıldı - Çevrimiçi şablonları senkronize et - Şablon kaydedilemedi - Pano boş! - Değişiklik geçmişi alınamadı: %s - Güncellemeleri denetle - Uygulamayı açarken güncellemeleri otomatik denetle - Root izni verilemedi! - - 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) - 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? - Sonraki - 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 - 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. - Flaşlama başarılı - Seçili lkm: %s - Flaşlanıyor - Flaşlama başarısız - Günlükleri Kaydet -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-uk/strings.xml b/manager/app/src/main/res/values-uk/strings.xml deleted file mode 100644 index 919ac133..00000000 --- a/manager/app/src/main/res/values-uk/strings.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - Головна - Не встановлено - Натисніть щоб встановити - Працює - Версія: %d - Суперкористувачі: %d - Модулі: %d - Не підтримується - KernelSU підтримує лише GKI ядра на данний момент - Ядро - Версія менеджера - Відбиток - Статус SELinux - Вимкнено - Примусовий - Дозвільний - Невідомо - Суперкористувач - Не вдалося ввімкнути модуль: %s - Не вдалося вимкнути модуль: %s - Немає встановлених модулів - Модулі - Видалити - Встановити - Встановити - Перезавантажити - Налаштування - М\'яке перезавантаження - Перезавантажити до Recovery - Перезавантажити до Bootloader - Перезавантажити до Download - Перезавантажити до EDL - Про додаток - Ви впевнені, що хочете видалити модуль %s? - %s видалено - Не вдалося видалити: %s - Версія - Автор - overlayfs не доступний, модуль не може працювати! - Освіжати(Оновити) - Показати системні додатки - Сховати системні додатки - Надіслати логи - Безпечний режим - Перезавантажте, щоб застосувати - Модулі вимкнено, оскільки вони конфліктують із модулями Magisk! - Дізнайтеся про KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Дізнайтеся, як інсталювати KernelSU і використовувати модулі - Підтримати нас - KernelSU є, і завжди буде безкоштовним та з відкритим кодом. Однак, якщо вам не байдуже, можете зробити невеличке пожертвування. - Приєднуйтесь до нашого каналу %2$s]]> - Профіль додатка - Типовий - Шаблон - Власний - Назва профілю - Змонтувати простір імен - Наслідуваний - Глобальний - Індивідуальний - Групи - Можливості - Контекст SELinux - Розмонтувати модулі - Не вдалося оновити профіль додатка для %s - Розмонтувати модулі за замовчуванням - Загальне значення за замовчуванням для \"Розмонтувати модулі\" у профілях додатків. Якщо ввімкнено, буде видалено всі модифікації модулів у системі для додатків, які не мають встановленого профілю. - Увімкнення даної опції дозволить KernelSU відновити для цього додатка будь-які файли, змінені модулями. - Домен - Правила - Оновити - Завантаження модуля: %s - Початок завантаження: %s - Запустити - Примусово зупинити - Перезапустити - Нова версія: %s доступна, натисніть, щоб завантажити - Не вдалося оновити правила SELinux для: %s - Журнал змін - Поточна версія KernelSU %d занадто низька, щоб менеджер міг працювати належним чином. Будь ласка, оновіть до версії %d або вище! - Успішно імпортовано - Експортувати в буфер обміну - Неможливо знайти локальні шаблони для експорту! - Шаблон з таким ідентифікатором вже існує! - Імпортувати з буферу обміну - Невдача при завантаженні списку змін: %s - Ім\'я - Невірний ідентифікатор шаблону - Синхронізувати мережеві шаблони - Створити шаблон - Тільки читання - Імпорт/Експорт - Помилка при збереженні шаблону - Редагувати шаблон - Ідентифікатор - Шаблон Профілю Додатку - Опис - Зберегти - Керувати локальними та мережевими шаблонами профілів додатків - Видалити - Буфер обміну пустий! - Переглянути шаблон - Увімкнути налагодження WebView - Виберіть KMI - Далі - Перевірка оновлень - Автоматична перевірка оновлень під час відкриття програми - Використовується для налагодження WebUI. Будь ласка, вмикайте тільки за потреби. - Пряме встановлення (рекомендовано) - Виберіть файл - Встановлення в неактивний слот (Після OTA) - Ваш пристрій буде **ПРИМУСОВО** завантажено в поточний неактивний слот після перезавантаження! -\n Використовуйте цю опцію тільки після завершення OTA. -\n Продовжити? - %1$s образ розділу рекомендується - Не вдалося отримати root! - Відкрити - Мінімізувати розріджений образ - Змінити розмір розрідженого образу, в якому знаходяться модулі, до його фактичного розміру. Зверніть увагу, що це може спричинити ненормальну роботу модулів, тому використовуйте це лише за потреби (наприклад, для резервного копіювання) - Тимчасово видалити - Назавжди видалити - Відновити Стоковий образ - Тимчасово видалити KernelSU, відновити початковий стан після наступного перезавантаження. - Видалити - Прошивка - Прошивку виконано - Прошивка не виконана - Обрано lkm: %s - Видалити KernelSU (Root і всі модулі) повністю і назавжди. - Відновити стоковий заводський образ (якщо є резервна копія), зазвичай використовується перед OTA; якщо вам потрібно видалити KernelSU, використовуйте \"Назавжди видалити\". - Зберегти Журнали - \ No newline at end of file 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 325416c0..00000000 --- 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-vi/strings.xml b/manager/app/src/main/res/values-vi/strings.xml deleted file mode 100644 index 04d87838..00000000 --- a/manager/app/src/main/res/values-vi/strings.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - Hồ sơ ứng dụng - Mặc định - Mẫu - Tuỳ chỉnh - Tên hồ sơ - Nhóm - Không thể cập nhật Hồ sơ ứng dụng cho %s - Ngắt mô-đun theo mặc định - Giá trị mặc định của \"Ngắt mô-đun\" trong Cấu hình ứng dụng. Nếu bật, KernelSU sẽ khôi phục mọi tệp hệ thống đã sửa đổi bởi mô-đun cho các ứng dụng chưa thiết lập Cấu hình. - Bật tùy chọn này sẽ khôi phục mọi tệp đã sửa đổi bởi các mô-đun cho ứng dụng này. - Cập nhật - Đang tải xuống mô-đun: %s - Bắt đầu tải xuống: %s - Phiên bản mới: %s đã có, bấm để nâng cấp - Tìm hiểu KernelSU - Tìm hiểu cách cài đặt KernelSU và sử dụng các mô-đun - Hỗ trợ chúng tôi - KernelSU sẽ luôn luôn miễn phí và mã nguồn mở. Tuy nhiên bạn có thể ủng hộ chúng tôi bằng một khoản đóng góp nhỏ. - Tham gia kênh %2$s của chúng tôi]]> - Các mô-đun bị vô hiệu hóa vì chúng xung đột với Magisk! - Bạn có muốn gỡ cài đặt mô-đun %s không\? - Nhật ký báo cáo - Trang chủ - Chưa cài đặt - Nhấn để cài đặt - Đang hoạt động - Phiên bản: %d - Không được hỗ trợ - KernelSU hiện tại chỉ hỗ trợ kernel GKI - Kernel - Phiên bản Manager - Fingerprint - Trạng thái SELinux - Vô hiệu hóa - Thực thi - Cho phép - Không rõ - SuperUser - Không thể kích hoạt mô-đun: %s - Không thể vô hiệu hóa mô-đun: %s - Chưa cài đặt mô-đun nào - Mô-đun - Gỡ cài đặt - Cài đặt - Cài đặt - Khởi động lại - Thiết đặt - Khởi động mềm - Khởi động lại vào Recovery - Khởi động lại vào Bootloader - Khởi động lại vào Download Mode - Khởi động lại vào EDL - Giới thiệu - %s được gỡ cài đặt - Lỗi khi gỡ cài đặt: %s - Phiên bản - Tác giả - overlayfs hiện không khả dụng, mô-đun không thể hoạt động! - Làm mới - Hiển thị ứng dụng hệ thống - Ẩn ứng dụng hệ thống - Chế độ an toàn - Khởi động lại để có hiệu lực - https://kernelsu.org/vi_VN/guide/what-is-kernelsu.html - Số superuser: %d - Số mô-đun: %d - Phạm vi - Quy định - Khởi chạy - Khởi động lại - Gắn namespace - Quyền - Không thể cập nhật quy định SELinux cho: %s - Buộc dừng - Thừa hưởng - Chung - Riêng - Bối cảnh SELinux - Ngắt mô-đun - KernelSU phiên bản %d quá thấp để trình quản lý hoạt động, hãy cập nhật lên %d hoặc mới hơn! - Đã nhập thành công - Xuất từ khay nhớ tạm - Không thể tìm thấy mẫu cục bộ để xuất! - id bản mẫu đã tồn tại! - Nhật ký thay đổi - Nhập từ khay nhớ tạm - Không nạp được nhật ký thay đổi: %s - Tên - Id mẫu không hợp lệ - Đồng bộ hóa các mẫu trực tuyến - Tạo Bản Mẫu - Nhập/Xuất - Không lưu được mẫu - Sửa Bản Mẫu - Mẫu Hồ Sơ Ứng Dụng - Mô tả - Lưu - Quản lý mẫu Hồ sơ Ứng dụng cục bộ và trực tuyến - Xóa - Clipboard trống! - Xem Bản Mẫu - chỉ đọc - id - Bật gỡ lỗi WebView - Có thể được sử dụng để gỡ lỗi WebUI, vui lòng chỉ bật khi cần. - Không cấp được quyền root! - Kiểm tra cập nhật - Tự động kiểm tra cập nhật khi mở ứng dụng - Mở - Cài đặt vào khe không hoạt động (Sau OTA) - Thiết bị của bạn sẽ **BẮT BUỘC** khởi động vào khe không hoạt động hiện tại sau khi khởi động lại! -\nChỉ sử dụng tùy chọn này sau khi OTA hoàn tất. -\nTiếp tục? - Tạm thời gỡ cài đặt KernelSU, khôi phục về trạng thái ban đầu sau lần khởi động lại tiếp theo. - Chọn KMI - Kế tiếp - Cài đặt trực tiếp (Được khuyến nghị) - Chọn một tệp - Gỡ cài đặt - Gỡ cài đặt tạm thời - Gỡ cài đặt vĩnh viễn - Khôi phục hình ảnh gốc - Gỡ cài đặt KernelSU (Root và tất cả các mô-đun) hoàn toàn và vĩnh viễn. - Khôi phục hình ảnh gốc của nhà máy (nếu có bản sao lưu), thường được sử dụng trước OTA; nếu bạn cần gỡ cài đặt KernelSU, vui lòng sử dụng \"Gỡ cài đặt vĩnh viễn\". - Đang cài - Cài thành công - Cài thất bại - Đã chọn lkm: %s - Nên sử dụng hình ảnh phân vùng %1$s - Giảm thiểu hình ảnh thưa thớt - Thay đổi kích thước hình ảnh thưa nơi đặt mô-đun theo kích thước thực tế của nó. Lưu ý điều này có thể khiến module hoạt động không bình thường nên vui lòng chỉ sử dụng khi cần thiết (chẳng hạn như để sao lưu) - Lưu Nhật Ký - \ 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 deleted file mode 100644 index e854fb60..00000000 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - 主页 - 未安装 - 点击安装 - 工作中 - 版本: %d - 超级用户数:%d - 不支持 - KernelSU 现在只支持 GKI 内核 - 内核版本 - 管理器版本 - 系统指纹 - SELinux 状态 - 被禁用 - 强制执行 - 宽容模式 - 未知 - 超级用户 - 无法启用模块: %s - 无法禁用模块: %s - 没有安装模块 - 模块 - 卸载 - 安装 - 安装 - 重启 - 设置 - 软重启 - 重启到 Recovery - 重启到 BootLoader - 重启到 Download - 重启到 EDL - 关于 - 确定要卸载模块 %s 吗? - %s 已卸载 - 卸载失败: %s - 版本 - 作者 - 内核不支持 overlayfs,模块功能无法运作! - 刷新 - 显示系统应用 - 隐藏系统应用 - 发送日志 - 安全模式 - 重启生效 - 所有模块已被禁用,因为它与 Magisk 的模块系统有冲突! - 模块数:%d - 了解 KernelSU - https://kernelsu.org/zh_CN/guide/what-is-kernelsu.html - 了解如何安装 KernelSU 以及如何开发模块 - 支持开发 - KernelSU 将保持免费开源,向开发者捐赠以表示支持。 - 加入我们的 %2$s 频道
加入我们的 QQ 频道]]>
- 默认 - 模版 - 自定义 - 名称 - 命名空间 - 继承 - 全局 - 私有 - - 权能 - SELinux - 卸载模块 - 为 %s 更新 App Profile 失败 - 当前 KernelSU 版本 %d 过低,管理器无法正常工作,请升级内核 KernelSU 版本至 %d 或以上! - 默认卸载模块 - App Profile 中\"卸载模块\"的全局默认值,如果启用,将会为没有设置 Profile 的应用移除所有模块针对系统的修改。 - 启用后将允许 KernelSU 为本应用还原被模块修改过的文件。 - - 规则 - 更新 - 正在下载模块:%s - 开始下载:%s - 发现新版本:%s,点击升级 - 启动 - 强制停止 - 重新启动 - 为:%s 更新翻译失败 - 更新日志 - App Profile 模版 - 管理本地和在线的 App Profile 模版 - 创建模版 - 编辑模版 - 模版 id - 模版 id 不合法 - 名字 - 描述 - 保存 - 删除 - 查看模版 - 只读 - 模版 id 已存在! - 导入/导出 - 从剪切板导入 - 导出到剪切板 - 没有本地模版可以导出! - 导入成功! - 同步在线规则 - 模版保存失败! - 剪切板为空! - 获取更新日志失败:%s - 检查更新 - 在应用启动后自动检查是否有最新版 - 获取 root 失败! - 打开 - 启用 WebView 调试 - 可用于调试 WebUI ,请仅在需要时启用。 - 直接安装(推荐) - 选择一个文件 - 安装到未使用的槽位(OTA 后) - 将在重启后强制切换到另一个槽位!\n注意只能在 OTA 更新完成后的重启之前使用。\n确认? - 下一步 - 建议选择 %1$s 分区镜像 - 选择 KMI - 最小化稀疏文件 - 将模块所在的稀疏文件镜像调整为其实际大小,注意这可能导致模块工作异常,请仅在必要时(如备份)使用 - 卸载 - 临时卸载 - 永久卸载 - 恢复原厂镜像 - 临时卸载 KernelSU,下次重启后恢复 - 完全并永久移除 KernelSU 和所有模块 - 恢复原厂镜像,一般在 OTA 前使用;如需卸载请使用“永久卸载” - 刷写中 - 刷写完成 - 刷写失败 - 选择的 LKM :%s - 保存日志 -
\ No newline at end of file diff --git a/manager/app/src/main/res/values-zh-rHK/strings.xml b/manager/app/src/main/res/values-zh-rHK/strings.xml deleted file mode 100644 index 154ddac9..00000000 --- a/manager/app/src/main/res/values-zh-rHK/strings.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - 首頁 - 未安裝 - 按一下以安裝 - 運作中 - KernelSU 版本:%d - 超級使用者:%d 個 - 已安裝模組:%d 個 - 不支援 - KernelSU 現在僅支援 GKI 核心 - 核心 - 管理器版本 - 指紋 - SELinux 狀態 - 已停用 - 強制 - 寬鬆 - 未知 - 超級使用者 - 無法啟用模組:%s - 無法停用模組:%s - 尚未安裝模組 - 模組 - 解除安裝 - 安裝 - 安裝 - 重新啟動 - 設定 - 軟啟動 - 重新啟動至 Recovery - 重新啟動至 Bootloader - 重新啟動至 Download - 重新啟動至 EDL - 關於 - 您確定要解除安裝模組「%s」嗎? - 「%s」已解除安裝 - 無法解除安裝:%s - 版本 - 作者 - OverlayFS 無法使用,模組無法正常運作! - 重新整理 - 顯示系統應用程式 - 隱藏系統應用程式 - 傳送記錄 - 安全模式 - 重新啟動以生效 - 模組已停用,因其與 Magisk 的模組存在衝突! - 深入瞭解 KernelSU - https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html - 瞭解如何安裝 KernelSU 以及如何開發模組 - 支援開發 - KernelSU 將保持免費和開源,您可以考慮向開發人員贊助以表示支持。 - 加入我們的 %2$s 頻道]]> - 預設 - 設定檔名稱 - 範本 - 繼承 - 全域 - 功能 - 卸載模組 - 無法更新 %s 應用程式設定檔 - 規則 - 目前 KernelSU 版本 %d 過低,管理器無法正常運作。請升級至 %d 或更高版本! - 應用程式設定檔中「解除安裝模組」的全域預設值,如果啟用,將會為沒有設定檔的應用程式移除所有模組針對系統的修改。 - 啟用此選項將允許 KernelSU 為這個應用程式還原任何被模組修改過的檔案。 - 網域 - 更新 - 自訂 - 掛載命名空間 - 個人 - 群組 - SELinux 環境 - 預設解除安裝模組 - 正在下載模組:%s - 開始下載:%s - 新版本:%s 已可供使用,按一下以升級 - 啟動 - 強制停止 - 重新啟動 - 無法為 %s 更新 SELinux 規則 - 變更記錄 - 成功匯出 - 導出到剪貼板 - 本地沒有模板可匯出! - 模板 ID 已存在! - 從剪貼簿匯入 - 獲取更新日誌失敗:%s - 名字 - 模板 ID 無效 - 同步在線規則 - 創建模板 - 只讀 - 匯出 / 匯入 - 模板儲存失敗 - 編輯模板 - 模板 ID - App Profile 模板 - 描述 - 儲存 - 管理本地和線上的 App Profile 模板 - 刪除 - 剪貼簿沒有內容! - 查看模板 - 啟用 WebView 偵錯 - 可用於偵錯WebUI,請僅在需要時啟用。 - 直接安裝(建議) - 選擇一個文件 - 安裝到非活動插槽(OTA 後) - 重新啟動後,您的裝置將強制啟動到目前非活動插槽! -\n僅在 OTA 完成後使用此選項。 -\n繼續? - 下一個 - 選擇KMI - 建議使用 %1$s 分割區映像 - 授予root權限失敗! - 打開 - 檢查更新 - 開啟應用程式時自動檢查更新 - 最小化稀疏影像 - 將模組所在的稀疏影像調整為實際大小。 請注意,這可能會導致模組工作異常,因此請僅在必要時使用(例如備份) - 解除安裝 - 保存日志 - \ No newline at end of file diff --git a/manager/app/src/main/res/values-zh-rTW/strings.xml b/manager/app/src/main/res/values-zh-rTW/strings.xml deleted file mode 100644 index 7917ddef..00000000 --- a/manager/app/src/main/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - 首頁 - 未安裝 - 按一下以安裝 - 運作中 - KernelSU 版本:%d - 已授權 Root:%d 個 - 不支援 - KernelSU 現在僅支援 GKI 核心 - 核心 - 管理器版本 - 指紋 - SELinux 狀態 - 已停用 - 強制 - 寬鬆 - 未知 - Root 授權 - 無法啟用模組:%s - 無法停用模組:%s - 尚未安裝模組 - 模組 - 解除安裝 - 安裝 - 安裝 - 重新啟動 - 設定 - 軟重新啟動 - 重新啟動至 Recovery - 重新啟動至 Bootloader - 重新啟動至 Download - 重新啟動至 EDL - 關於 - 您確定要解除安裝模組「%s」嗎? - 「%s」已解除安裝 - 無法解除安裝:%s - 版本 - 作者 - OverlayFS 無法使用,模組無法正常運作! - 重新整理 - 顯示系統應用程式 - 隱藏系統應用程式 - 傳送記錄 - 安全模式 - 重新啟動以生效 - 模組已停用,因其與 Magisk 的模組存在衝突! - 已安裝模組:%d 個 - 深入瞭解 KernelSU - https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html - 瞭解如何安裝 KernelSU 以及如何開發模組 - 支援開發 - KernelSU 將保持免費和開源,您可以考慮向開發人員贊助以表示支持。 - 加入我們的 %2$s 頻道]]> - 卸載模組 - 無法更新 %s 應用程式設定檔 - 目前安裝的 KernelSU 版本 %d 過低,管理器無法正常工作,請升級核心 KernelSU 版本至 %d 或以上! - 預設卸載模組 - 應用程式設定檔中「卸載模組」的全域預設值,如果啟用,將會為沒有設定檔的應用程式移除所有模組針對系統的修改。 - 啟用後將允許 KernelSU 為本應用程式還原被模組修改過的檔案。 - 預設 - 自訂 - 權限 - 規則 - 正在下載模組:%s - 重新啟動 - 模板 - 設定檔名稱 - 掛載命名空間 - 繼承 - 全域 - 私人 - 群組 - SELinux context - - 更新 - 開始下載:%s - 發現新版本:%s 已可供使用,按一下即可升級 - 啟動 - 強制停止 - 無法為 %s 更新 SELinux - 變更記錄 - 模板 ID 無效 - 創建模板 - 編輯模板 - 模板 ID - App Profile 模板 - 管理本地和線上的 App Profile 模板 - 成功匯入 - 匯出至剪貼簿 - 沒有本地模板可匯出! - 模板 ID 已存在! - 從剪貼簿匯入 - 獲取更新日誌失敗:%s - 名稱 - 與線上規則同步 - 唯讀 - 匯出 / 匯入 - 模板儲存失敗 - 描述 - 儲存 - 刪除 - 剪貼簿沒有內容! - 檢查模板 - 可用於偵錯 WebUI,請僅在需要時啟用。 - 啟用 WebView 偵錯 - 取得root失敗! - 開啟 - 檢查更新 - 在打開App時自動檢查更新 - 選擇一個檔案 - 安裝到非使用中的槽位(在 OTA 更新後) - 您的裝置將在下次重新啟動後強制切換到非使用中的槽位! -\n這個選項僅在 OTA 更新完畢後使用。 -\n請問是否繼續? - 直接安裝(建議) - 下一步 - 選擇 KMI - 建議使用 %1$s 分區 - 最小化模組稀疏映像 - 將模組的稀疏映像調整為其實際大小,請注意這可能導致模組工作異常,請僅在需要時(如備份)使用 - 解除安裝 - 暫時解除安裝 - 還原原廠映像 - 暫時卸載KernelSU,下次重啟後恢復原狀。 - 永久解除安裝 - 完全的(永久的)解除安裝 KernelSU(Root 和所有模組)。 - 寫入中 - 寫入完成 - 恢復原廠映像(如果有備份),通常在OTA之前使用;如果需要解除安裝KernelSU,請使用「永久解除安裝」。 - 寫入失敗 - 選擇的 LKM :%s - 儲存日誌 - \ 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 deleted file mode 100644 index d094969a..00000000 --- a/manager/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - KernelSU - Home - Not installed - Click to install - Working - Version: %d - Superusers: %d - Modules: %d - Unsupported - KernelSU only supports GKI kernels now - Kernel - Manager Version - Fingerprint - SELinux status - Disabled - Enforcing - Permissive - Unknown - SuperUser - Failed to enable module: %s - Failed to disable module: %s - No installed modules - Module - Uninstall - Install - Install - Reboot - Settings - Soft Reboot - Reboot to Recovery - Reboot to Bootloader - Reboot to Download - Reboot to EDL - About - Are you sure you want to uninstall module %s? - %s is uninstalled - Failed to uninstall: %s - Version - Author - overlayfs is not available, module cannot work! - Refresh - Show system apps - Hide system apps - Report Log - Safe mode - Reboot to take effect - Modules are disabled because it is conflict with Magisk\'s! - Learn KernelSU - https://kernelsu.org/guide/what-is-kernelsu.html - Learn how to install KernelSU and use modules - Support Us - KernelSU is, and always will be, free, and open source. You can however show us that you care by making a donation. - Join our %2$s channel]]> - App Profile - Default - Template - Custom - Profile name - Mount namespace - Inherited - Global - Individual - Groups - Capabilities - 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! - 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. - Domain - Rules - Update - Downloading module: %s - Start downloading: %s - New version: %s is available, click to upgrade - Launch - 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 - Invalid template id - Name - Description - Save - Delete - View Template - readonly - template id already exists! - Import/Export - Import from clipboard - Export to clipboard - Can not find local template to export! - Imported successfully - Sync online templates - Failed to save template - Clipboard is empty! - Fetch changelog failed: %s - Check update - Automatically check for updates when opening the app - Failed to grant root! - Open - 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) - 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) - Uninstall - 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\". - Flashing - Flash success - Flash failed - Selected lkm: %s - Save Logs - \ No newline at end of file diff --git a/manager/app/src/main/res/values/themes.xml b/manager/app/src/main/res/values/themes.xml deleted file mode 100644 index 7d41d8ec..00000000 --- a/manager/app/src/main/res/values/themes.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ No newline at end of file diff --git a/manager/app/src/main/res/xml/backup_rules.xml b/manager/app/src/main/res/xml/backup_rules.xml deleted file mode 100644 index fa0f996d..00000000 --- a/manager/app/src/main/res/xml/backup_rules.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/manager/app/src/main/res/xml/data_extraction_rules.xml b/manager/app/src/main/res/xml/data_extraction_rules.xml deleted file mode 100644 index 9ee9997b..00000000 --- a/manager/app/src/main/res/xml/data_extraction_rules.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/manager/app/src/main/res/xml/filepaths.xml b/manager/app/src/main/res/xml/filepaths.xml deleted file mode 100644 index f8a9a5c5..00000000 --- a/manager/app/src/main/res/xml/filepaths.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/manager/app/src/main/res/xml/network_security_config.xml b/manager/app/src/main/res/xml/network_security_config.xml deleted file mode 100644 index 6dd26ccf..00000000 --- a/manager/app/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - 127.0.0.1 - 0.0.0.0 - ::1 - - diff --git a/manager/build.gradle.kts b/manager/build.gradle.kts deleted file mode 100644 index 0e503df3..00000000 --- a/manager/build.gradle.kts +++ /dev/null @@ -1,101 +0,0 @@ -import com.android.build.api.dsl.ApplicationDefaultConfig -import com.android.build.api.dsl.CommonExtension -import com.android.build.gradle.api.AndroidBasePlugin -import java.io.ByteArrayOutputStream - -plugins { - alias(libs.plugins.agp.app) apply false - alias(libs.plugins.agp.lib) apply false - alias(libs.plugins.kotlin) apply false - alias(libs.plugins.compose.compiler) apply false - alias(libs.plugins.lsplugin.cmaker) -} - -cmaker { - default { - arguments.addAll( - arrayOf( - "-DANDROID_STL=c++_static", - ) - ) - val flags = arrayOf( - "-Wno-gnu-string-literal-operator-template", - "-Wno-c++2b-extensions", - ) - cFlags.addAll(flags) - cppFlags.addAll(flags) - abiFilters("arm64-v8a", "x86_64") - } - buildTypes { - if (it.name == "release") { - arguments += "-DDEBUG_SYMBOLS_PATH=${buildDir.absolutePath}/symbols" - } - } -} - -val androidMinSdkVersion = 26 -val androidTargetSdkVersion = 34 -val androidCompileSdkVersion = 34 -val androidBuildToolsVersion = "34.0.0" -val androidCompileNdkVersion = "26.3.11579264" -val androidSourceCompatibility = JavaVersion.VERSION_21 -val androidTargetCompatibility = JavaVersion.VERSION_21 -val managerVersionCode by extra(getVersionCode()) -val managerVersionName by extra(getVersionName()) - -fun getGitCommitCount(): Int { - val out = ByteArrayOutputStream() - exec { - commandLine("git", "rev-list", "--count", "HEAD") - standardOutput = out - } - return out.toString().trim().toInt() -} - -fun getGitDescribe(): String { - val out = ByteArrayOutputStream() - exec { - commandLine("git", "describe", "--tags", "--always") - standardOutput = out - } - return out.toString().trim() -} - -fun getVersionCode(): Int { - val commitCount = getGitCommitCount() - val major = 1 - return major * 10000 + commitCount + 200 -} - -fun getVersionName(): String { - return getGitDescribe() -} - -subprojects { - plugins.withType(AndroidBasePlugin::class.java) { - extensions.configure(CommonExtension::class.java) { - compileSdk = androidCompileSdkVersion - ndkVersion = androidCompileNdkVersion - buildToolsVersion = androidBuildToolsVersion - - defaultConfig { - minSdk = androidMinSdkVersion - if (this is ApplicationDefaultConfig) { - targetSdk = androidTargetSdkVersion - versionCode = managerVersionCode - versionName = managerVersionName - } - } - - lint { - abortOnError = true - checkReleaseBuilds = false - } - - compileOptions { - sourceCompatibility = androidSourceCompatibility - targetCompatibility = androidTargetCompatibility - } - } - } -} \ No newline at end of file diff --git a/manager/gradle.properties b/manager/gradle.properties deleted file mode 100644 index 387da396..00000000 --- a/manager/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -android.experimental.enableNewResourceShrinker.preciseShrinking=true -android.enableAppCompileTimeRClass=true -android.useAndroidX=true diff --git a/manager/gradle/libs.versions.toml b/manager/gradle/libs.versions.toml deleted file mode 100644 index 039835ee..00000000 --- a/manager/gradle/libs.versions.toml +++ /dev/null @@ -1,78 +0,0 @@ -[versions] -agp = "8.4.1" -kotlin = "2.0.0" -ksp = "2.0.0-1.0.21" -compose-bom = "2024.05.00" -lifecycle = "2.8.1" -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" -sheets-compose-dialogs = "1.3.0" -markdown = "4.6.2" -webkit = "1.11.0" -appiconloader-coil = "1.5.0" -parcelablelist = "2.0.1" -libsu = "5.2.2" -apksign = "1.4" -cmaker = "1.2" - -[plugins] -agp-app = { id = "com.android.application", version.ref = "agp" } -agp-lib = { id = "com.android.library", version.ref = "agp" } - -kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } - -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } - -lsplugin-apksign = { id = "org.lsposed.lsplugin.apksign", version.ref = "apksign" } -lsplugin-cmaker = { id = "org.lsposed.lsplugin.cmaker", version.ref = "cmaker" } - -[libraries] -androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" } - -androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } - -androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } -androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" } -androidx-compose-material = { group = "androidx.compose.material", name = "material" } -androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } -androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } -androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } -androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } -androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } - -androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } -androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" } -androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } - -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" } - -dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:parcelablelist", version.ref = "parcelablelist" } - -io-coil-kt-coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil-compose" } - -kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } - -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-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 diff --git a/manager/gradle/wrapper/gradle-wrapper.jar b/manager/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136..00000000 Binary files a/manager/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/manager/gradle/wrapper/gradle-wrapper.properties b/manager/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index b82aa23a..00000000 --- a/manager/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/manager/gradlew b/manager/gradlew deleted file mode 100755 index 4b6a9cfc..00000000 --- a/manager/gradlew +++ /dev/null @@ -1,248 +0,0 @@ -#!/bin/sh -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# 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 - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/manager/gradlew.bat b/manager/gradlew.bat deleted file mode 100644 index 25da30db..00000000 --- a/manager/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/manager/settings.gradle.kts b/manager/settings.gradle.kts deleted file mode 100644 index 2230bf48..00000000 --- a/manager/settings.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -@file:Suppress("UnstableApiUsage") - -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") - -pluginManagement { - repositories { - google() - mavenCentral() - } -} - -dependencyResolutionManagement { - repositories { - google() - mavenCentral() - maven("https://jitpack.io") - } -} - -rootProject.name = "KernelSU" -include(":app") diff --git a/manager/sign.example.properties b/manager/sign.example.properties deleted file mode 100644 index bc70a60c..00000000 --- a/manager/sign.example.properties +++ /dev/null @@ -1,4 +0,0 @@ -KEYSTORE_FILE= -KEYSTORE_PASSWORD= -KEY_ALIAS= -KEY_PASSWORD= diff --git a/userspace/ksud/.gitignore b/userspace/ksud/.gitignore deleted file mode 100644 index 3c71873d..00000000 --- a/userspace/ksud/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -.cargo/ \ No newline at end of file diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock deleted file mode 100644 index e39414ab..00000000 --- a/userspace/ksud/Cargo.lock +++ /dev/null @@ -1,1860 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if 1.0.0", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-properties" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_log-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" - -[[package]] -name = "android_logger" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f" -dependencies = [ - "android_log-sys", - "env_logger 0.10.2", - "log", - "once_cell", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "async-trait" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.6.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", -] - -[[package]] -name = "cc" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" -dependencies = [ - "jobserver", - "libc", - "once_cell", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - -[[package]] -name = "const_format" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "deflate64" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d" - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive-new" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "derive_arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "either" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" -dependencies = [ - "env_filter", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "extattr" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b59f8a77817ff1b795adafc535941bdf664184f5f95e0b6d1d77dd6d12815dc" -dependencies = [ - "bitflags 1.3.2", - "errno 0.2.8", - "libc", -] - -[[package]] -name = "flate2" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -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" -source = "git+https://github.com/tiann/hole-punch#11ab7a61bfb98682b72fd7f58a47d8e5d997328e" -dependencies = [ - "cfg-if 0.1.10", - "errno 0.2.8", - "libc", - "memmap", - "thiserror", - "winapi", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "include-flate" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e11569346406931d20276cc460215ee2826e7cad43aa986999cb244dd7adb0" -dependencies = [ - "include-flate-codegen-exports", - "lazy_static", - "libflate", -] - -[[package]] -name = "include-flate-codegen" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a7d6e1419fa3129eb0802b4c99603c0d425c79fb5d76191d5a20d0ab0d664e8" -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", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -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", -] - -[[package]] -name = "is_executable" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" -dependencies = [ - "winapi", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "java-properties" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37bf6f484471c451f2b51eabd9e66b3fa7274550c5ec4b6c3d6070840945117f" -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", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" -dependencies = [ - "crossbeam", - "rayon", -] - -[[package]] -name = "ksud" -version = "0.1.0" -dependencies = [ - "android-properties", - "android_logger", - "anyhow", - "chrono", - "clap", - "const_format", - "derive-new", - "encoding_rs", - "env_logger 0.11.3", - "extattr", - "getopts", - "hole-punch", - "humansize", - "is_executable", - "java-properties", - "jwalk", - "libc", - "log", - "loopdev", - "nom", - "procfs", - "regex", - "retry", - "rust-embed", - "rustix 0.38.30", - "serde", - "serde_json", - "sha1", - "sha256", - "tempdir", - "which", - "zip 2.1.2", - "zip-extensions", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "libflate" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18" -dependencies = [ - "adler32", - "crc32fast", - "libflate_lz77", -] - -[[package]] -name = "libflate_lz77" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf" -dependencies = [ - "rle-decode-fast", -] - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "loopdev" -version = "0.5.0" -source = "git+https://github.com/Kernel-SU/loopdev#7a921f8d966477a645b1188732fac486c71a68ef" -dependencies = [ - "errno 0.2.8", - "libc", -] - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "memmap" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" -dependencies = [ - "adler", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -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", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -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" - -[[package]] -name = "proc-macro2" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "procfs" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" -dependencies = [ - "bitflags 2.5.0", - "chrono", - "flate2", - "hex", - "lazy_static", - "procfs-core", - "rustix 0.38.34", -] - -[[package]] -name = "procfs-core" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" -dependencies = [ - "bitflags 2.5.0", - "chrono", - "hex", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "retry" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4" -dependencies = [ - "rand 0.8.5", -] - -[[package]] -name = "rle-decode-fast" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" - -[[package]] -name = "rust-embed" -version = "8.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a" -dependencies = [ - "include-flate", - "rust-embed-impl", - "rust-embed-utils", - "walkdir", -] - -[[package]] -name = "rust-embed-impl" -version = "8.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4" -dependencies = [ - "proc-macro2", - "quote", - "rust-embed-utils", - "syn 2.0.65", - "walkdir", -] - -[[package]] -name = "rust-embed-utils" -version = "8.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32" -dependencies = [ - "sha2", - "walkdir", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustix" -version = "0.38.30" -source = "git+https://github.com/Kernel-SU/rustix.git?branch=main#0e270bce2d97466be6b987bb5f7ea5b1e8d84969" -dependencies = [ - "bitflags 2.5.0", - "errno 0.3.9", - "itoa", - "libc", - "linux-raw-sys", - "once_cell", - "windows-sys", -] - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.5.0", - "errno 0.3.9", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "serde_json" -version = "1.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha256" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0" -dependencies = [ - "async-trait", - "bytes", - "hex", - "sha2", - "tokio", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "strsim" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" -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", -] - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "tokio" -version = "1.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" -dependencies = [ - "backtrace", - "bytes", - "pin-project-lite", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-width" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.65", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "which" -version = "6.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" -dependencies = [ - "either", - "home", - "rustix 0.38.34", - "winsafe", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd 0.11.2+zstd.1.5.2", -] - -[[package]] -name = "zip" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098d5d7737fb0b70814faa73c17df84f047d38dd31d13bbf2ec3fb354b5abf45" -dependencies = [ - "arbitrary", - "bzip2", - "crc32fast", - "crossbeam-utils", - "deflate64", - "displaydoc", - "flate2", - "indexmap", - "memchr", - "thiserror", - "time", - "zopfli", - "zstd 0.13.1", -] - -[[package]] -name = "zip-extensions" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c865b4f0f43f22d1bd7ba05479b5c003e0e98e9090c3a2e4280b5eace59f62df" -dependencies = [ - "zip 0.6.6", -] - -[[package]] -name = "zopfli" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" -dependencies = [ - "bumpalo", - "crc32fast", - "lockfree-object-pool", - "log", - "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 deleted file mode 100644 index b5486ada..00000000 --- a/userspace/ksud/Cargo.toml +++ /dev/null @@ -1,63 +0,0 @@ -[package] -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"] } -const_format = "0.2" -zip = { version = "2", features = [ - "deflate", - "deflate64", - "bzip2", - "time", - "zstd", -], default-features = false } -zip-extensions = "0.7" -java-properties = "2" -log = "0.4" -env_logger = { version = "0.11", default-features = false } -serde = { version = "1" } -serde_json = "1" -regex = "1" -encoding_rs = "0.8" -retry = "2" -humansize = "2" -libc = "0.2" -extattr = "1" -jwalk = "0.8" -is_executable = "1" -nom = "7" -derive-new = "0.6" -rust-embed = { version = "8", features = [ - "debug-embed", - "compression", # must clean build after updating binaries -] } -which = "6" -getopts = "0.2" -sha256 = "1" -sha1 = "0.10" -tempdir = "0.3" -chrono = "0.4" -hole-punch = { git = "https://github.com/tiann/hole-punch" } - -[target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies] -rustix = { git = "https://github.com/Kernel-SU/rustix.git", branch = "main", features = [ - "all-apis", -] } -# 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" -loopdev = { git = "https://github.com/Kernel-SU/loopdev" } - -[target.'cfg(target_os = "android")'.dependencies] -android_logger = "0.13" - -[profile.release] -strip = true -opt-level = "z" -lto = true \ No newline at end of file diff --git a/userspace/ksud/bin/.gitignore b/userspace/ksud/bin/.gitignore deleted file mode 100644 index 1464b7ed..00000000 --- a/userspace/ksud/bin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.ko \ No newline at end of file diff --git a/userspace/ksud/bin/aarch64/bootctl b/userspace/ksud/bin/aarch64/bootctl deleted file mode 100644 index cf5c6136..00000000 Binary files a/userspace/ksud/bin/aarch64/bootctl and /dev/null differ diff --git a/userspace/ksud/bin/aarch64/busybox b/userspace/ksud/bin/aarch64/busybox deleted file mode 100755 index 1ddf3f73..00000000 Binary files a/userspace/ksud/bin/aarch64/busybox and /dev/null differ diff --git a/userspace/ksud/bin/aarch64/ksuinit b/userspace/ksud/bin/aarch64/ksuinit deleted file mode 100755 index 8d3ba057..00000000 Binary files a/userspace/ksud/bin/aarch64/ksuinit and /dev/null differ diff --git a/userspace/ksud/bin/aarch64/resetprop b/userspace/ksud/bin/aarch64/resetprop deleted file mode 100644 index 1155e5f4..00000000 Binary files a/userspace/ksud/bin/aarch64/resetprop and /dev/null differ diff --git a/userspace/ksud/bin/x86_64/busybox b/userspace/ksud/bin/x86_64/busybox deleted file mode 100755 index 2557c61d..00000000 Binary files a/userspace/ksud/bin/x86_64/busybox and /dev/null differ diff --git a/userspace/ksud/bin/x86_64/ksuinit b/userspace/ksud/bin/x86_64/ksuinit deleted file mode 100755 index 9517baf9..00000000 Binary files a/userspace/ksud/bin/x86_64/ksuinit and /dev/null differ diff --git a/userspace/ksud/bin/x86_64/resetprop b/userspace/ksud/bin/x86_64/resetprop deleted file mode 100644 index dc4d9910..00000000 Binary files a/userspace/ksud/bin/x86_64/resetprop and /dev/null differ diff --git a/userspace/ksud/build.rs b/userspace/ksud/build.rs deleted file mode 100644 index 021418ac..00000000 --- a/userspace/ksud/build.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::Path; -use std::process::Command; - -fn get_git_version() -> Result<(u32, String), std::io::Error> { - let output = Command::new("git") - .args(["rev-list", "--count", "HEAD"]) - .output()?; - - let output = output.stdout; - let version_code = String::from_utf8(output).expect("Failed to read git count stdout"); - let version_code: u32 = version_code - .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_name = String::from_utf8( - Command::new("git") - .args(["describe", "--tags", "--always"]) - .output()? - .stdout, - ) - .map_err(|_| { - std::io::Error::new( - std::io::ErrorKind::Other, - "Failed to read git describe stdout", - ) - })?; - let version_name = version_name.trim_start_matches('v').to_string(); - Ok((version_code, version_name)) -} - -fn main() { - let (code, name) = match get_git_version() { - Ok((code, name)) => (code, name), - Err(_) => { - // show warning if git is not installed - println!("cargo:warning=Failed to get git version, using 0.0.0"); - (0, "0.0.0".to_string()) - } - }; - let out_dir = env::var("OUT_DIR").expect("Failed to get $OUT_DIR"); - let out_dir = Path::new(&out_dir); - File::create(Path::new(out_dir).join("VERSION_CODE")) - .expect("Failed to create VERSION_CODE") - .write_all(code.to_string().as_bytes()) - .expect("Failed to write VERSION_CODE"); - - File::create(Path::new(out_dir).join("VERSION_NAME")) - .expect("Failed to create VERSION_NAME") - .write_all(name.trim().as_bytes()) - .expect("Failed to write VERSION_NAME"); -} diff --git a/userspace/ksud/src/apk_sign.rs b/userspace/ksud/src/apk_sign.rs deleted file mode 100644 index 6d047cca..00000000 --- a/userspace/ksud/src/apk_sign.rs +++ /dev/null @@ -1,115 +0,0 @@ -use anyhow::{ensure, Result}; -use std::io::{Read, Seek, SeekFrom}; - -pub fn get_apk_signature(apk: &str) -> Result<(u32, String)> { - let mut buffer = [0u8; 0x10]; - let mut size4 = [0u8; 4]; - let mut size8 = [0u8; 8]; - let mut size_of_block = [0u8; 8]; - - let mut f = std::fs::File::open(apk)?; - - let mut i = 0; - loop { - let mut n = [0u8; 2]; - f.seek(SeekFrom::End(-i - 2))?; - f.read_exact(&mut n)?; - - let n = u16::from_le_bytes(n); - if i64::from(n) == i { - f.seek(SeekFrom::Current(-22))?; - f.read_exact(&mut size4)?; - - if u32::from_le_bytes(size4) ^ 0xcafe_babe_u32 == 0xccfb_f1ee_u32 { - if i > 0 { - println!("warning: comment length is {i}"); - } - break; - } - } - - ensure!(n != 0xffff, "not a zip file"); - - i += 1; - } - - f.seek(SeekFrom::Current(12))?; - // offset - f.read_exact(&mut size4)?; - f.seek(SeekFrom::Start(u64::from(u32::from_le_bytes(size4)) - 0x18))?; - - f.read_exact(&mut size8)?; - f.read_exact(&mut buffer)?; - - ensure!(&buffer == b"APK Sig Block 42", "Can not found sig block"); - - let pos = u64::from(u32::from_le_bytes(size4)) - (u64::from_le_bytes(size8) + 0x8); - f.seek(SeekFrom::Start(pos))?; - f.read_exact(&mut size_of_block)?; - - ensure!(size_of_block == size8, "not a signed apk"); - - let mut v2_signing: Option<(u32, String)> = None; - let mut v3_signing_exist = false; - let mut v3_1_signing_exist = false; - - loop { - let mut id = [0u8; 4]; - let mut offset = 4u32; - - f.read_exact(&mut size8)?; // sequence length - if size8 == size_of_block { - break; - } - - f.read_exact(&mut id)?; // id - - let id = u32::from_le_bytes(id); - if id == 0x7109_871a_u32 { - v2_signing = Some(calc_cert_sha256(&mut f, &mut size4, &mut offset)?); - } else if id == 0xf053_68c0_u32 { - // v3 signature scheme - v3_signing_exist = true; - } else if id == 0x1b93_ad61_u32 { - // v3.1 signature scheme: credits to vvb2060 - v3_1_signing_exist = true; - } - - f.seek(SeekFrom::Current( - i64::from_le_bytes(size8) - i64::from(offset), - ))?; - } - - if v3_signing_exist || v3_1_signing_exist { - return Err(anyhow::anyhow!("Unexpected v3 signature found!",)); - } - - v2_signing.ok_or(anyhow::anyhow!("No signature found!")) -} - -fn calc_cert_sha256( - f: &mut std::fs::File, - size4: &mut [u8; 4], - offset: &mut u32, -) -> Result<(u32, String)> { - f.read_exact(size4)?; // signer-sequence length - f.read_exact(size4)?; // signer length - f.read_exact(size4)?; // signed data length - *offset += 0x4 * 3; - - f.read_exact(size4)?; // digests-sequence length - let pos = u32::from_le_bytes(*size4); // skip digests - f.seek(SeekFrom::Current(i64::from(pos)))?; - *offset += 0x4 + pos; - - f.read_exact(size4)?; // certificates length - f.read_exact(size4)?; // certificate length - *offset += 0x4 * 2; - - let cert_len = u32::from_le_bytes(*size4); - let mut cert: Vec = vec![0; cert_len as usize]; - f.read_exact(&mut cert)?; - *offset += cert_len; - - Ok((cert_len, sha256::digest(&cert))) -} diff --git a/userspace/ksud/src/assets.rs b/userspace/ksud/src/assets.rs deleted file mode 100644 index e8255c82..00000000 --- a/userspace/ksud/src/assets.rs +++ /dev/null @@ -1,50 +0,0 @@ -use anyhow::Result; -use const_format::concatcp; -use rust_embed::RustEmbed; -use std::path::Path; - -use crate::{defs::BINARY_DIR, utils}; - -pub const RESETPROP_PATH: &str = concatcp!(BINARY_DIR, "resetprop"); -pub const BUSYBOX_PATH: &str = concatcp!(BINARY_DIR, "busybox"); -pub const BOOTCTL_PATH: &str = concatcp!(BINARY_DIR, "bootctl"); - -#[cfg(all(target_arch = "x86_64", target_os = "android"))] -#[derive(RustEmbed)] -#[folder = "bin/x86_64"] -struct Asset; - -// IF NOT x86_64 ANDROID, ie. macos, linux, windows, always use aarch64 -#[cfg(not(all(target_arch = "x86_64", target_os = "android")))] -#[derive(RustEmbed)] -#[folder = "bin/aarch64"] -struct Asset; - -pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> { - for file in Asset::iter() { - if file == "ksuinit" || file.ends_with(".ko") { - // don't extract ksuinit and kernel modules - continue; - } - let asset = Asset::get(&file).ok_or(anyhow::anyhow!("asset not found: {}", file))?; - utils::ensure_binary(format!("{BINARY_DIR}{file}"), &asset.data, ignore_if_exist)? - } - Ok(()) -} - -pub fn copy_assets_to_file(name: &str, dst: impl AsRef) -> Result<()> { - let asset = Asset::get(name).ok_or(anyhow::anyhow!("asset not found: {}", name))?; - std::fs::write(dst, asset.data)?; - Ok(()) -} - -pub fn list_supported_kmi() -> Result> { - let mut list = Vec::new(); - for file in Asset::iter() { - // kmi_name = "xxx_kernelsu.ko" - if let Some(kmi) = file.strip_suffix("_kernelsu.ko") { - list.push(kmi.to_string()); - } - } - Ok(list) -} diff --git a/userspace/ksud/src/banner b/userspace/ksud/src/banner deleted file mode 100644 index 6087569c..00000000 --- a/userspace/ksud/src/banner +++ /dev/null @@ -1,5 +0,0 @@ - _ __ _ ____ _ _ - | |/ /___ _ __ _ __ ___| / ___|| | | | - | ' // _ \ '__| '_ \ / _ \ \___ \| | | | - | . \ __/ | | | | | __/ |___) | |_| | - |_|\_\___|_| |_| |_|\___|_|____/ \___/ diff --git a/userspace/ksud/src/boot_patch.rs b/userspace/ksud/src/boot_patch.rs deleted file mode 100644 index c2661c68..00000000 --- a/userspace/ksud/src/boot_patch.rs +++ /dev/null @@ -1,632 +0,0 @@ -#[cfg(unix)] -use std::os::unix::fs::PermissionsExt; -use std::path::Path; -use std::path::PathBuf; -use std::process::Command; -use std::process::Stdio; - -use anyhow::anyhow; -use anyhow::bail; -use anyhow::ensure; -use anyhow::Context; -use anyhow::Result; -use which::which; - -use crate::defs; -use crate::defs::BACKUP_FILENAME; -use crate::defs::{KSU_BACKUP_DIR, KSU_BACKUP_FILE_PREFIX}; -use crate::{assets, utils}; - -#[cfg(target_os = "android")] -fn ensure_gki_kernel() -> Result<()> { - let version = get_kernel_version()?; - let is_gki = version.0 == 5 && version.1 >= 10 || version.2 > 5; - ensure!(is_gki, "only support GKI kernel"); - Ok(()) -} - -#[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+)")?; - if let Some(captures) = re.captures(&version) { - let major = captures - .get(1) - .and_then(|m| m.as_str().parse::().ok()) - .ok_or_else(|| anyhow!("Major version parse error"))?; - let minor = captures - .get(2) - .and_then(|m| m.as_str().parse::().ok()) - .ok_or_else(|| anyhow!("Minor version parse error"))?; - let patch = captures - .get(3) - .and_then(|m| m.as_str().parse::().ok()) - .ok_or_else(|| anyhow!("Patch version parse error"))?; - Ok((major, minor, patch)) - } else { - Err(anyhow!("Invalid kernel version string")) - } -} - -#[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) - .ok_or_else(|| anyhow::anyhow!("Failed to get KMI from boot/modules"))?; - let android_version = cap.get(4).map_or("", |m| m.as_str()); - let kernel_version = cap.get(2).map_or("", |m| m.as_str()); - Ok(format!("{android_version}-{kernel_version}")) -} - -#[cfg(target_os = "android")] -fn parse_kmi_from_uname() -> Result { - let uname = rustix::system::uname(); - let version = uname.release().to_string_lossy(); - parse_kmi(&version) -} - -#[cfg(target_os = "android")] -fn parse_kmi_from_modules() -> Result { - use std::io::BufRead; - // find a *.ko in /vendor/lib/modules - let modfile = std::fs::read_dir("/vendor/lib/modules")? - .filter_map(Result::ok) - .find(|entry| entry.path().extension().map_or(false, |ext| ext == "ko")) - .map(|entry| entry.path()) - .ok_or_else(|| anyhow!("No kernel module found"))?; - let output = Command::new("modinfo").arg(modfile).output()?; - for line in output.stdout.lines().map_while(Result::ok) { - if line.starts_with("vermagic") { - return parse_kmi(&line); - } - } - anyhow::bail!("Parse KMI from modules failed") -} - -#[cfg(target_os = "android")] -pub fn get_current_kmi() -> Result { - parse_kmi_from_uname().or_else(|_| parse_kmi_from_modules()) -} - -#[cfg(not(target_os = "android"))] -pub fn get_current_kmi() -> Result { - bail!("Unsupported platform") -} - -fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> { - let status = Command::new(magiskboot) - .current_dir(workdir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .arg("cpio") - .arg("ramdisk.cpio") - .arg(cmd) - .status()?; - - ensure!(status.success(), "magiskboot cpio {} failed", cmd); - Ok(()) -} - -fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result { - let status = Command::new(magiskboot) - .current_dir(workdir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .args(["cpio", "ramdisk.cpio", "test"]) - .status()?; - - // 0: stock, 1: magisk - Ok(status.code() == Some(1)) -} - -fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result { - let status = Command::new(magiskboot) - .current_dir(workdir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .args(["cpio", "ramdisk.cpio", "exists kernelsu.ko"]) - .status()?; - - Ok(status.success()) -} - -fn dd, Q: AsRef>(ifile: P, ofile: Q) -> Result<()> { - let status = Command::new("dd") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .arg(format!("if={}", ifile.as_ref().display())) - .arg(format!("of={}", ofile.as_ref().display())) - .status()?; - ensure!( - status.success(), - "dd if={:?} of={:?} failed", - ifile.as_ref(), - ofile.as_ref() - ); - Ok(()) -} - -pub fn restore( - image: Option, - magiskboot_path: Option, - flash: bool, -) -> Result<()> { - let tmpdir = tempdir::TempDir::new("KernelSU").context("create temp dir failed")?; - let workdir = tmpdir.path(); - let magiskboot = find_magiskboot(magiskboot_path, workdir)?; - - let kmi = get_current_kmi().unwrap_or_else(|_| String::from("")); - - let skip_init = kmi.starts_with("android12-"); - - let (bootimage, bootdevice) = find_boot_image(&image, skip_init, false, false, workdir)?; - - println!("- Unpacking boot image"); - let status = Command::new(&magiskboot) - .current_dir(workdir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .arg("unpack") - .arg(bootimage.display().to_string()) - .status()?; - ensure!(status.success(), "magiskboot unpack failed"); - - let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?; - ensure!(is_kernelsu_patched, "boot image is not patched by KernelSU"); - - let mut new_boot = None; - let mut from_backup = false; - - #[cfg(target_os = "android")] - if do_cpio_cmd(&magiskboot, workdir, &format!("exists {BACKUP_FILENAME}")).is_ok() { - do_cpio_cmd( - &magiskboot, - workdir, - &format!("extract {0} {0}", BACKUP_FILENAME), - )?; - let sha = std::fs::read(workdir.join(BACKUP_FILENAME))?; - let sha = String::from_utf8(sha)?; - let sha = sha.trim(); - let backup_path = - PathBuf::from(KSU_BACKUP_DIR).join(format!("{KSU_BACKUP_FILE_PREFIX}{sha}")); - if backup_path.is_file() { - new_boot = Some(backup_path); - from_backup = true; - } else { - println!("- Warning: no backup {backup_path:?} found!"); - } - - if let Err(e) = clean_backup(sha) { - println!("- Warning: Cleanup backup image failed: {e}"); - } - } else { - println!("- Backup info is absent!"); - } - - if new_boot.is_none() { - // remove kernelsu.ko - do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?; - - // if init.real exists, restore it - let status = do_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok(); - if status { - do_cpio_cmd(&magiskboot, workdir, "mv init.real init")?; - } else { - let ramdisk = workdir.join("ramdisk.cpio"); - std::fs::remove_file(ramdisk)?; - } - - println!("- Repacking boot image"); - let status = Command::new(&magiskboot) - .current_dir(workdir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .arg("repack") - .arg(bootimage.display().to_string()) - .status()?; - ensure!(status.success(), "magiskboot repack failed"); - new_boot = Some(workdir.join("new-boot.img")); - } - - let new_boot = new_boot.unwrap(); - - if image.is_some() { - // if image is specified, write to output file - let output_dir = std::env::current_dir()?; - let now = chrono::Utc::now(); - let output_image = output_dir.join(format!( - "kernelsu_restore_{}.img", - now.format("%Y%m%d_%H%M%S") - )); - - if from_backup || std::fs::rename(&new_boot, &output_image).is_err() { - std::fs::copy(&new_boot, &output_image).context("copy out new boot failed")?; - } - println!("- Output file is written to"); - println!("- {}", output_image.display().to_string().trim_matches('"')); - } - if flash { - if from_backup { - println!("- Flashing new boot image from {}", new_boot.display()); - } else { - println!("- Flashing new boot image"); - } - flash_boot(&bootdevice, new_boot)?; - } - println!("- Done!"); - Ok(()) -} - -#[allow(clippy::too_many_arguments)] -pub fn patch( - image: Option, - kernel: Option, - kmod: Option, - init: Option, - ota: bool, - flash: bool, - out: Option, - magiskboot: Option, - kmi: Option, -) -> Result<()> { - let result = do_patch(image, kernel, kmod, init, ota, flash, out, magiskboot, kmi); - if let Err(ref e) = result { - println!("- Install Error: {e}"); - } - result -} - -#[allow(clippy::too_many_arguments)] -fn do_patch( - image: Option, - kernel: Option, - kmod: Option, - init: Option, - ota: bool, - flash: bool, - out: Option, - magiskboot_path: Option, - kmi: Option, -) -> Result<()> { - println!(include_str!("banner")); - - let patch_file = image.is_some(); - - #[cfg(target_os = "android")] - if !patch_file { - ensure_gki_kernel()?; - } - - let is_replace_kernel = kernel.is_some(); - - if is_replace_kernel { - ensure!( - init.is_none() && kmod.is_none(), - "init and module must not be specified." - ); - } - - let tmpdir = tempdir::TempDir::new("KernelSU").context("create temp dir failed")?; - let workdir = tmpdir.path(); - - let kmi = if let Some(kmi) = kmi { - kmi - } else { - get_current_kmi().context("Unknown KMI, please choose LKM manually")? - }; - - let skip_init = kmi.starts_with("android12-"); - - let (bootimage, bootdevice) = - find_boot_image(&image, skip_init, ota, is_replace_kernel, workdir)?; - - let bootimage = bootimage.display().to_string(); - - // 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")?; - } - - println!("- Preparing assets"); - - let kmod_file = workdir.join("kernelsu.ko"); - if let Some(kmod) = kmod { - std::fs::copy(kmod, kmod_file).context("copy kernel module failed")?; - } else { - // If kmod is not specified, extract from assets - println!("- KMI: {kmi}"); - let name = format!("{kmi}_kernelsu.ko"); - assets::copy_assets_to_file(&name, kmod_file) - .with_context(|| format!("Failed to copy {name}"))?; - }; - - let init_file = workdir.join("init"); - if let Some(init) = init { - std::fs::copy(init, init_file).context("copy init failed")?; - } else { - assets::copy_assets_to_file("ksuinit", init_file).context("copy ksuinit failed")?; - } - - // magiskboot unpack boot.img - // magiskboot cpio ramdisk.cpio 'cp init init.real' - // magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init' - // magiskboot cpio ramdisk.cpio 'add 0755 kernelsu.ko' - - println!("- Unpacking boot image"); - let status = Command::new(&magiskboot) - .current_dir(workdir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .arg("unpack") - .arg(&bootimage) - .status()?; - ensure!(status.success(), "magiskboot unpack failed"); - - let no_ramdisk = !workdir.join("ramdisk.cpio").exists(); - let is_magisk_patched = is_magisk_patched(&magiskboot, workdir)?; - ensure!( - no_ramdisk || !is_magisk_patched, - "Cannot work with Magisk patched image" - ); - - println!("- Adding KernelSU LKM"); - let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?; - - let mut need_backup = false; - if !is_kernelsu_patched { - // kernelsu.ko is not exist, backup init if necessary - let status = do_cpio_cmd(&magiskboot, workdir, "exists init"); - if status.is_ok() { - do_cpio_cmd(&magiskboot, workdir, "mv init init.real")?; - } - - need_backup = flash; - } - - do_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?; - do_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?; - - #[cfg(target_os = "android")] - if need_backup { - if let Err(e) = do_backup(&magiskboot, workdir, &bootimage) { - println!("- Backup stock image failed: {e}"); - } - } - - println!("- Repacking boot image"); - // magiskboot repack boot.img - let status = Command::new(&magiskboot) - .current_dir(workdir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .arg("repack") - .arg(&bootimage) - .status()?; - ensure!(status.success(), "magiskboot repack failed"); - let new_boot = workdir.join("new-boot.img"); - - if patch_file { - // if image is specified, write to output file - let output_dir = out.unwrap_or(std::env::current_dir()?); - let now = chrono::Utc::now(); - let output_image = output_dir.join(format!( - "kernelsu_patched_{}.img", - now.format("%Y%m%d_%H%M%S") - )); - - if std::fs::rename(&new_boot, &output_image).is_err() { - std::fs::copy(&new_boot, &output_image).context("copy out new boot failed")?; - } - println!("- Output file is written to"); - println!("- {}", output_image.display().to_string().trim_matches('"')); - } - - if flash { - println!("- Flashing new boot image"); - flash_boot(&bootdevice, new_boot)?; - - if ota { - post_ota()?; - } - } - - println!("- Done!"); - Ok(()) -} - -#[cfg(target_os = "android")] -fn calculate_sha1(file_path: impl AsRef) -> Result { - use sha1::Digest; - use std::io::Read; - let mut file = std::fs::File::open(file_path.as_ref())?; - let mut hasher = sha1::Sha1::new(); - let mut buffer = [0; 1024]; - - loop { - let n = file.read(&mut buffer)?; - if n == 0 { - break; - } - hasher.update(&buffer[..n]); - } - - let result = hasher.finalize(); - Ok(format!("{:x}", result)) -} - -#[cfg(target_os = "android")] -fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> { - let sha1 = calculate_sha1(image)?; - let filename = format!("{KSU_BACKUP_FILE_PREFIX}{sha1}"); - - println!("- Backup stock boot image"); - // magiskboot cpio ramdisk.cpio 'add 0755 $BACKUP_FILENAME' - let target = format!("{KSU_BACKUP_DIR}{filename}"); - std::fs::copy(image, &target).with_context(|| format!("backup to {target}"))?; - std::fs::write(workdir.join(BACKUP_FILENAME), sha1.as_bytes()).context("write sha1")?; - do_cpio_cmd( - magiskboot, - workdir, - &format!("add 0755 {0} {0}", BACKUP_FILENAME), - )?; - println!("- Stock image has been backup to"); - println!("- {target}"); - Ok(()) -} - -#[cfg(target_os = "android")] -fn clean_backup(sha1: &str) -> Result<()> { - println!("- Clean up backup"); - let backup_name = format!("{}{}", KSU_BACKUP_FILE_PREFIX, sha1); - let dir = std::fs::read_dir(defs::KSU_BACKUP_DIR)?; - for entry in dir.flatten() { - let path = entry.path(); - if !path.is_file() { - continue; - } - if let Some(name) = path.file_name() { - let name = name.to_string_lossy().to_string(); - if name != backup_name - && name.starts_with(KSU_BACKUP_FILE_PREFIX) - && std::fs::remove_file(path).is_ok() - { - println!("- removed {name}"); - } - } - } - Ok(()) -} - -fn flash_boot(bootdevice: &Option, new_boot: PathBuf) -> Result<()> { - let Some(bootdevice) = bootdevice else { - bail!("boot device not found") - }; - let status = Command::new("blockdev") - .arg("--setrw") - .arg(bootdevice) - .status()?; - ensure!(status.success(), "set boot device rw failed"); - dd(new_boot, bootdevice).context("flash boot failed")?; - Ok(()) -} - -fn find_magiskboot(magiskboot_path: Option, workdir: &Path) -> Result { - let magiskboot = { - if which("magiskboot").is_ok() { - let _ = assets::ensure_binaries(true); - "magiskboot".into() - } else { - // magiskboot is not in $PATH, use builtin or specified one - let magiskboot = if let Some(magiskboot_path) = magiskboot_path { - std::fs::canonicalize(magiskboot_path)? - } else { - let magiskboot_path = workdir.join("magiskboot"); - assets::copy_assets_to_file("magiskboot", &magiskboot_path) - .context("copy magiskboot failed")?; - magiskboot_path - }; - ensure!(magiskboot.exists(), "{magiskboot:?} is not exist"); - #[cfg(unix)] - let _ = std::fs::set_permissions(&magiskboot, std::fs::Permissions::from_mode(0o755)); - magiskboot - } - }; - Ok(magiskboot) -} - -fn find_boot_image( - image: &Option, - skip_init: bool, - ota: bool, - is_replace_kernel: bool, - workdir: &Path, -) -> Result<(PathBuf, Option)> { - let bootimage; - let mut bootdevice = None; - if let Some(ref image) = *image { - ensure!(image.exists(), "boot image not found"); - bootimage = std::fs::canonicalize(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"); - } - let mut slot_suffix = - utils::getprop("ro.boot.slot_suffix").unwrap_or_else(|| String::from("")); - - if !slot_suffix.is_empty() && ota { - if slot_suffix == "_a" { - slot_suffix = "_b".to_string() - } else { - slot_suffix = "_a".to_string() - } - }; - - let init_boot_exist = - Path::new(&format!("/dev/block/by-name/init_boot{slot_suffix}")).exists(); - let boot_partition = if !is_replace_kernel && init_boot_exist && !skip_init { - format!("/dev/block/by-name/init_boot{slot_suffix}") - } else { - format!("/dev/block/by-name/boot{slot_suffix}") - }; - - println!("- Bootdevice: {boot_partition}"); - let tmp_boot_path = workdir.join("boot.img"); - - dd(&boot_partition, &tmp_boot_path)?; - - ensure!(tmp_boot_path.exists(), "boot image not found"); - - bootimage = tmp_boot_path; - bootdevice = Some(boot_partition); - }; - Ok((bootimage, bootdevice)) -} - -fn post_ota() -> Result<()> { - use crate::defs::ADB_DIR; - use assets::BOOTCTL_PATH; - let status = Command::new(BOOTCTL_PATH).arg("hal-info").status()?; - if !status.success() { - return Ok(()); - } - - let current_slot = Command::new(BOOTCTL_PATH) - .arg("get-current-slot") - .output()? - .stdout; - let current_slot = String::from_utf8(current_slot)?; - let current_slot = current_slot.trim(); - let target_slot = if current_slot == "0" { 1 } else { 0 }; - - Command::new(BOOTCTL_PATH) - .arg(format!("set-active-boot-slot {target_slot}")) - .status()?; - - let post_fs_data = std::path::Path::new(ADB_DIR).join("post-fs-data.d"); - utils::ensure_dir_exists(&post_fs_data)?; - let post_ota_sh = post_fs_data.join("post_ota.sh"); - - let sh_content = format!( - r###" -{BOOTCTL_PATH} mark-boot-successful -rm -f {BOOTCTL_PATH} -rm -f /data/adb/post-fs-data.d/post_ota.sh -"### - ); - - std::fs::write(&post_ota_sh, sh_content)?; - #[cfg(unix)] - std::fs::set_permissions(post_ota_sh, std::fs::Permissions::from_mode(0o755))?; - - Ok(()) -} diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs deleted file mode 100644 index cd96a360..00000000 --- a/userspace/ksud/src/cli.rs +++ /dev/null @@ -1,392 +0,0 @@ -use anyhow::{Ok, Result}; -use clap::Parser; -use std::path::PathBuf; - -#[cfg(target_os = "android")] -use android_logger::Config; -#[cfg(target_os = "android")] -use log::LevelFilter; - -use crate::{apk_sign, assets, debug, defs, init_event, ksucalls, module, utils}; - -/// KernelSU userspace cli -#[derive(Parser, Debug)] -#[command(author, version = defs::VERSION_NAME, about, long_about = None)] -struct Args { - #[command(subcommand)] - command: Commands, -} - -#[derive(clap::Subcommand, Debug)] -enum Commands { - /// Manage KernelSU modules - Module { - #[command(subcommand)] - command: Module, - }, - - /// Trigger `post-fs-data` event - PostFsData, - - /// Trigger `service` event - Services, - - /// Trigger `boot-complete` event - BootCompleted, - - /// Install KernelSU userspace component to system - Install { - #[arg(long, default_value = None)] - magiskboot: Option, - }, - - /// Uninstall KernelSU modules and itself(LKM Only) - Uninstall { - /// magiskboot path, if not specified, will search from $PATH - #[arg(long, default_value = None)] - magiskboot: Option, - }, - - /// SELinux policy Patch tool - Sepolicy { - #[command(subcommand)] - command: Sepolicy, - }, - - /// Manage App Profiles - Profile { - #[command(subcommand)] - command: Profile, - }, - - /// Patch boot or init_boot images to apply KernelSU - BootPatch { - /// boot image path, if not specified, will try to find the boot image automatically - #[arg(short, long)] - boot: Option, - - /// kernel image path to replace - #[arg(short, long)] - kernel: Option, - - /// LKM module path to replace, if not specified, will use the builtin one - #[arg(short, long)] - module: Option, - - /// init to be replaced - #[arg(short, long, requires("module"))] - init: Option, - - /// will use another slot when boot image is not specified - #[arg(short = 'u', long, default_value = "false")] - ota: bool, - - /// Flash it to boot partition after patch - #[arg(short, long, default_value = "false")] - flash: bool, - - /// output path, if not specified, will use current directory - #[arg(short, long, default_value = None)] - out: Option, - - /// magiskboot path, if not specified, will search from $PATH - #[arg(long, default_value = None)] - magiskboot: Option, - - /// KMI version, if specified, will use the specified KMI - #[arg(long, default_value = None)] - kmi: Option, - }, - - /// Restore boot or init_boot images patched by KernelSU - BootRestore { - /// boot image path, if not specified, will try to find the boot image automatically - #[arg(short, long)] - boot: Option, - - /// Flash it to boot partition after patch - #[arg(short, long, default_value = "false")] - flash: bool, - - /// magiskboot path, if not specified, will search from $PATH - #[arg(long, default_value = None)] - magiskboot: Option, - }, - - /// Show boot information - BootInfo { - #[command(subcommand)] - command: BootInfo, - }, - /// For developers - Debug { - #[command(subcommand)] - command: Debug, - }, -} - -#[derive(clap::Subcommand, Debug)] -enum BootInfo { - /// show current kmi version - CurrentKmi, - - /// show supported kmi versions - SupportedKmi, -} - -#[derive(clap::Subcommand, Debug)] -enum Debug { - /// Set the manager app, kernel CONFIG_KSU_DEBUG should be enabled. - SetManager { - /// manager package name - #[arg(default_value_t = String::from("me.weishu.kernelsu"))] - apk: String, - }, - - /// Get apk size and hash - GetSign { - /// apk path - apk: String, - }, - - /// Root Shell - Su { - /// switch to gloabl mount namespace - #[arg(short, long, default_value = "false")] - global_mnt: bool, - }, - - /// Get kernel version - Version, - - Mount, - - /// Copy sparse file - Xcp { - /// source file - src: String, - /// destination file - dst: String, - /// punch hole - #[arg(short, long, default_value = "false")] - punch_hole: bool, - }, - - /// For testing - Test, -} - -#[derive(clap::Subcommand, Debug)] -enum Sepolicy { - /// Patch sepolicy - Patch { - /// sepolicy statements - sepolicy: String, - }, - - /// Apply sepolicy from file - Apply { - /// sepolicy file path - file: String, - }, - - /// Check if sepolicy statement is supported/valid - Check { - /// sepolicy statements - sepolicy: String, - }, -} - -#[derive(clap::Subcommand, Debug)] -enum Module { - /// Install module - Install { - /// module zip file path - zip: String, - }, - - /// Uninstall module - Uninstall { - /// module id - id: String, - }, - - /// enable module - Enable { - /// module id - id: String, - }, - - /// disable module - Disable { - // module id - id: String, - }, - - /// list all modules - List, - - /// Shrink module image size - Shrink, -} - -#[derive(clap::Subcommand, Debug)] -enum Profile { - /// get root profile's selinux policy of - GetSepolicy { - /// package name - package: String, - }, - - /// set root profile's selinux policy of to - SetSepolicy { - /// package name - package: String, - /// policy statements - policy: String, - }, - - /// get template of - GetTemplate { - /// template id - id: String, - }, - - /// set template of to