Compare commits

...

46 Commits

Author SHA1 Message Date
weishu
e35180c919 Update build-manager.yml 2023-05-15 12:14:30 +08:00
Howard Wu
2f54ceb7c4 ci: android12-5.10 drop deprecated tag (#495) 2023-05-15 09:58:25 +08:00
Mohamed Elsayed
6506ef468d Add Arabic translation (#491) 2023-05-13 16:25:10 +08:00
5ec1cff
da46dfbde1 ksud: use MS_RDONLY when mounting overlayfs (#490)
fix https://github.com/tiann/KernelSU/issues/489
2023-05-13 16:17:22 +08:00
Alessandro Paluzzi
09ecc2c9b5 Add italian translation (#486) 2023-05-13 07:07:34 +08:00
github-actions[bot]
0b2899a961 [add device]: (#485)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/484

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-13 06:03:40 +08:00
dabao1955
c6ed3fa27f Change the device supported by the kernel source code I maintain. (#483) 2023-05-12 23:34:25 +08:00
TheNoFace
43cd3b9cad Add Korean translation (#480) 2023-05-12 20:27:43 +08:00
tiann
294d6fa05e kernel: don't umount for process in global namespace 2023-05-12 12:32:35 +08:00
Syuugo
009a479c17 WSA: 5.15.94.1 (#475)
![](https://github.com/tiann/KernelSU/assets/52069677/99edfd12-c0a1-4430-bf2f-b17b76dbc44f)

Co-authored-by: weishu <twsxtd@gmail.com>
2023-05-11 18:45:15 +08:00
tiann
72ee14e6be kernel: revert init stage for x86_64 temporarily 2023-05-11 17:20:55 +08:00
Murat Kozan
2b01a1c395 Add Turkish translation (#474) 2023-05-11 11:14:38 +08:00
tiann
f69793d38e ksud: REPLACE must be directory, if you need to replace normal file, just put it to module's system corresponding location, don't need extra steps. fix #466 2023-05-10 14:36:02 +08:00
github-actions[bot]
eda0d6d23b [add device]: OPPO Reno 6 (#473)
OPPO Reno 6 has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/472

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-10 07:12:39 +08:00
S M Mahbub Hossain
abba36d786 Add Bangla/Bengali translation (#471)
Signed-off-by: S M Mahbub Hossain  <118460787+smmahbubhossain@users.noreply.github.com>
2023-05-09 19:03:58 +08:00
raystef66
33ea9a6f33 Add Flemish/Dutch translation (#470) 2023-05-08 23:21:20 +08:00
Kurisu Cat
9a0da7270b document: fix typo (#467)
修正文档中的错别字
2023-05-08 00:12:38 +08:00
github-actions[bot]
9caf440200 [add device]: (#462)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/461

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 18:57:39 +08:00
github-actions[bot]
c9e53cf355 [add device]: (#459)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/458

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 10:42:42 +08:00
RyuujiX
432eb318ac kernel: Kconfig: Remove KPROBES dependancy (#453)
For those who want to Implement KernelSU Manually with KPROBES disabled.

When KPROBES Broken and Still enabled, this will causing Loop at splash
logo even Already Manually Imported because this
842c0b674f/kernel/ksu.c (L57).
And when KPROBES is disabled, KSU also will not compiled (I Know it'll
still build if obj-y is set for KSU, but it's better to remove, who
knows if someone set as obj-$(CONFIG_KSU)).

Signed-off-by: RyuujiX <saputradenny712@gmail.com>
2023-05-04 22:57:49 +08:00
セリカ・シルフィル
cea0db4e0d manager: Open guide in the current language if it exist (#452)
If not present, the English page will be opened by default.
2023-05-04 21:10:33 +08:00
weishu
842c0b674f ci: Fix setlocalversion patch failed (#451) 2023-05-04 15:37:06 +08:00
Huy Minh
36ed99d1f6 ksud.c : Include compat.h (#450)
Fix compiling on Android-x86

Signed-off-by: hmtheboy154 <buingoc67@gmail.com>
2023-05-04 11:49:21 +08:00
shygos
86d0f37b37 kernel: Use a better way to link submodule directory (#449)
Use ../ instead of absolute path
2023-05-03 22:05:36 +08:00
github-actions[bot]
5303c9c461 [add device]: (#448)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/447

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-02 06:56:35 +08:00
tiann
67667b6df2 kernel: umount by lazy 2023-05-02 00:12:01 +08:00
Lvc Revincx
d9d27b4229 readme: fix credits link title of genuine project (#446)
The credit link title of [genuine](https://github.com/brevent/genuine)
in `README_CN.md` and `README_TW.md` is `true`.
2023-05-01 16:56:31 +08:00
Sreeshankar K
a2a1b19758 Add OnePlus Nord (avicii) (#444) 2023-04-29 23:45:07 +08:00
github-actions[bot]
fb9d39d6d5 [add device]: (#443)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/442

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-29 12:03:07 +08:00
github-actions[bot]
0f3d425f64 [add device]: (#439)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/438

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-28 08:35:02 +08:00
Abdelhay-Ali
08e3580646 make huawei hi6250 4.9.319 kernel compile (#431) 2023-04-27 13:30:04 +08:00
Igor Sorocean
0fa4a4c6db Update ro strings (#434) 2023-04-26 17:22:53 +08:00
diphons
d452e01a3d [add device]: Xiaomi Poco X3 Pro | Vayu - Bhima (#433) 2023-04-26 11:45:50 +08:00
diphons
f7da373f8b [add device]: Xiaomi Poco F3 - F4 - MI10T/Pro (#432) 2023-04-25 14:55:32 +08:00
Koinu
b80cf7ba15 Update repos.json (#430)
他的内核已经不支持KernelSU了
2023-04-24 11:22:48 +08:00
Kung-chih
fe1cd4b27a website: add Traditional Chinese (#429)
Also README_TW added, hope it works :)
2023-04-23 18:54:33 +08:00
Hikari-no-Tenshi
925206f9c8 Add Ukrainian translation (#427) 2023-04-23 13:55:43 +08:00
Abdelhay-Ali
f24a317e2d Update repos.json (#428)
add Huawei P20 lite (hi6250) (Linux 4.9)
2023-04-23 10:28:29 +08:00
TireX228
aeaa3ce982 manager: Update Russian language (#423) 2023-04-22 23:26:53 +08:00
Kung-chih
8c6913a9af Update zh-rHK and zh-rTW (#425)
@cracky5322 For zh-rTW with Android Style: 

> Log: 記錄(檔)
Developer: 開發人員
Access: 存取(權)
Support: 支援(For users) 支持(For devs)
2023-04-22 23:26:37 +08:00
TinyHai
7795232a58 manager: fix ConfirmDialog (#426) 2023-04-22 23:26:21 +08:00
TinyHai
057330c68f manager: refine dialog component and make a small fix in AboutCard (#422)
Co-authored-by: weishu <twsxtd@gmail.com>
2023-04-22 18:40:11 +08:00
github-actions[bot]
91c80279bd [add device]: (#421)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/420

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-22 15:25:07 +08:00
Nullptr
5715df0b10 manager: small fix for navigation (#416) 2023-04-21 23:52:46 +08:00
github-actions[bot]
9f0c540fba [add device]: (#418)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/417

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-21 23:52:16 +08:00
Nullptr
f9d19a957a manager: refactor to use AGP 8.0.0 (#414) 2023-04-21 16:19:49 +08:00
73 changed files with 2275 additions and 713 deletions

View File

@@ -1,43 +0,0 @@
From dbdd2906c0b3a967ca28c6b870b46f905c170661 Mon Sep 17 00:00:00 2001
From: Park Ju Hyung <qkrwngud825@gmail.com>
Date: Wed, 13 Mar 2019 13:36:37 +0900
Subject: [PATCH] setlocalversion: don't check for uncommitted changes
I ofter push after the build is done and I hate seeing "-dirty"
Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
Signed-off-by: Danny Lin <danny@kdrag0n.dev>
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
Change-Id: I240c516520879da680794fd144b1f273f9e21e13
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
---
scripts/setlocalversion | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 842936656b84..ef27a273ebf5 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -107,19 +107,6 @@ scm_version()
printf -- '-svn%s' "$(git svn find-rev $head)"
fi
- # Check for uncommitted changes.
- # First, with git-status, but --no-optional-locks is only
- # supported in git >= 2.14, so fall back to git-diff-index if
- # it fails. Note that git-diff-index does not refresh the
- # index, so it may give misleading results. See
- # git-update-index(1), git-diff-index(1), and git-status(1).
- if {
- git --no-optional-locks status -uno --porcelain 2>/dev/null ||
- git diff-index --name-only HEAD
- } | grep -qvE '^(.. )?scripts/package'; then
- printf '%s' -dirty
- fi
-
# All done with git
return
fi
--
2.37.2

View File

@@ -1,46 +0,0 @@
From bbb9e7fb1ccadac47b58ba615e6874ddeaa9e628 Mon Sep 17 00:00:00 2001
From: Park Ju Hyung <qkrwngud825@gmail.com>
Date: Wed, 13 Mar 2019 13:36:37 +0900
Subject: [PATCH] setlocalversion: don't check for uncommitted changes
I ofter push after the build is done and I hate seeing "-dirty"
Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
Signed-off-by: Danny Lin <danny@kdrag0n.dev>
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
Change-Id: I240c516520879da680794fd144b1f273f9e21e13
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
---
scripts/setlocalversion | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 1b733ae4c..2a3ea7684 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -90,22 +90,6 @@ scm_version()
printf '%s%s' -g "$(echo $head | cut -c1-12)"
fi
- # Check for uncommitted changes.
- # This script must avoid any write attempt to the source tree,
- # which might be read-only.
- # You cannot use 'git describe --dirty' because it tries to
- # create .git/index.lock .
- # First, with git-status, but --no-optional-locks is only
- # supported in git >= 2.14, so fall back to git-diff-index if
- # it fails. Note that git-diff-index does not refresh the
- # index, so it may give misleading results. See
- # git-update-index(1), git-diff-index(1), and git-status(1).
- if {
- git --no-optional-locks status -uno --porcelain 2>/dev/null ||
- git diff-index --name-only HEAD
- } | read dummy; then
- printf '%s' -dirty
- fi
fi
}
--
2.37.2

View File

@@ -21,20 +21,14 @@ jobs:
strategy:
matrix:
include:
- sub_level: 66
os_patch_level: 2021-11
- sub_level: 81
os_patch_level: 2022-03
- sub_level: 101
os_patch_level: 2022-05
- sub_level: 110
os_patch_level: 2022-07
- sub_level: 136
os_patch_level: 2022-11
- sub_level: 149
os_patch_level: 2023-01
- sub_level: 160
os_patch_level: 2023-02
os_patch_level: 2023-03
- sub_level: 168
os_patch_level: 2023-04
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:

View File

@@ -18,7 +18,7 @@ jobs:
strategy:
matrix:
arch: [x86_64, arm64]
version: ["5.10.117.2", "5.15.78.1"]
version: ["5.10.117.2", "5.15.78.1", "5.15.94.1"]
include:
- arch: x86_64
file_name: "bzImage"
@@ -37,12 +37,22 @@ jobs:
- version: "5.15.78.1"
arch: arm64
make_config: config-wsa-arm64
- version: "5.15.94.1"
arch: x86_64
make_config: config-wsa-x64
- version: "5.15.94.1"
arch: arm64
make_config: config-wsa-arm64
- version: "5.10.117.2"
device_code: latte
kernel_version: "5.10"
- version: "5.15.78.1"
device_code: latte-2
kernel_version: "5.15"
- version: "5.15.94.1"
device_code: latte-2
kernel_version: "5.15"
name: Build WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
runs-on: ubuntu-20.04
@@ -54,8 +64,8 @@ jobs:
steps:
- name: Install Build Tools
run: |
sudo apt update
sudo apt 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
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
export LLVM_VERSION=12
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh

View File

@@ -1,16 +1,18 @@
name: Build Manager
on:
push:
branches: [ "main" ]
paths:
paths:
- '.github/workflows/build-manager.yml'
- 'manager/**'
- 'userspace/ksud/**'
pull_request:
branches: [ "main" ]
paths:
paths:
- 'manager/**'
workflow_call:
jobs:
build-ksud:
strategy:
@@ -21,87 +23,104 @@ jobs:
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
build-manager:
needs: build-ksud
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./manager
steps:
- uses: actions/checkout@v3
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: set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: gradle
- uses: nttld/setup-ndk@v1
with:
ndk-version: r25b
local-cache: true
- name: Extract keystore
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 }}' >> sign.properties
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> sign.properties
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> sign.properties
echo KEYSTORE_FILE='../key.jks' >> sign.properties
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
fi
- name: Download arm64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-aarch64-linux-android
path: .
- name: Download x86_64 ksud
uses: actions/download-artifact@v3
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: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew clean assembleRelease
- name: Upload build artifact
uses: actions/upload-artifact@v3
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Setup mutex for uploading
uses: ben-z/gh-action-mutex@v1.0-alpha-7
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_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 python-telegram-bot
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
fi
- name: Checkout
uses: actions/checkout@v3
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 }}' >> gradle.properties
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> gradle.properties
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> gradle.properties
echo KEYSTORE_FILE='../key.jks' >> gradle.properties
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
fi
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
- name: Download arm64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-aarch64-linux-android
path: .
- name: Download x86_64 ksud
uses: actions/download-artifact@v3
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' >> gradle.properties
echo 'org.gradle.vfs.watch=true' >> gradle.properties
echo 'org.gradle.jvmargs=-Xmx2048m' >> gradle.properties
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@v3
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Setup mutex for uploading
uses: ben-z/gh-action-mutex@v1.0-alpha-7
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_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 python-telegram-bot
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
fi

View File

@@ -103,6 +103,8 @@ jobs:
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch
echo "Patch script/setlocalversion"
sed -i 's/-dirty//g' $GKI_ROOT/common/scripts/setlocalversion
echo "[+] KernelSU setup done."
- name: Symbol magic

3
.gitignore vendored
View File

@@ -1 +1,2 @@
.vscode/
.idea
.vscode

View File

@@ -1,4 +1,4 @@
**English** | [中文](README_CN.md)
**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | **中文**
[English](README.md) | **简体中文** | [繁體中文](README_TW.md)
# KernelSU
@@ -37,6 +37,6 @@ WSA 和运行在容器上的 Android 也可以与 KernelSU 一起工作。
## 鸣谢
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的灵感。
- [true](https://github.com/brevent/genuine/)apk v2 签名验证。
- [genuine](https://github.com/brevent/genuine/)apk v2 签名验证。
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 的实现。

42
README_TW.md Normal file
View File

@@ -0,0 +1,42 @@
[English](README.md) | [简体中文](README_CN.md) | **繁體中文**
# KernelSU
一個基於核心的 Android 裝置 Root 解決方案
## 功能
- 基於核心的 Su 和 Root 存取權管理。
- 基於 Overlayfs 的模組系統。
## 相容性狀態
KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+);舊版核心同樣相容 (最低 4.14+),但需要自行編譯核心。
WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
目前支援架構:`arm64-v8a``x86_64`
## 使用方法
[安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
## 建置
[如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
### 討論
- Telegram[@KernelSU](https://t.me/KernelSU)
## 授權
- 目錄 `kernel` 下所有檔案為 [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目錄的其他部分均為 [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## 致謝
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的靈感。
- [genuine](https://github.com/brevent/genuine/)apk v2 簽章驗證。
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 實作。

View File

@@ -1,7 +1,6 @@
config KSU
tristate "KernelSU module"
default y
depends on KPROBES
depends on OVERLAY_FS
help
This is the KSU privilege driver for android system.

View File

@@ -5,6 +5,7 @@
#include "linux/kernel.h"
#include "linux/kprobes.h"
#include "linux/lsm_hooks.h"
#include "linux/nsproxy.h"
#include "linux/path.h"
#include "linux/printk.h"
#include "linux/uaccess.h"
@@ -364,6 +365,11 @@ static bool should_umount(struct path *path)
return false;
}
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
pr_info("ignore global mnt namespace process: %d\n", current_uid().val);
return false;
}
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
const char *fstype = path->mnt->mnt_sb->s_type->name;
return strcmp(fstype, "overlay") == 0;
@@ -385,7 +391,7 @@ static void try_umount(const char *mnt)
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
err = path_umount(&path, 0);
err = path_umount(&path, MNT_DETACH);
if (err) {
pr_info("umount %s failed: %d\n", mnt, err);
}

View File

@@ -1,5 +1,6 @@
#include "asm/current.h"
#include "linux/string.h"
#include "linux/compat.h"
#include "linux/cred.h"
#include "linux/dcache.h"
#include "linux/err.h"
@@ -158,6 +159,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
if (!memcmp(filename->name, system_bin_init,
sizeof(system_bin_init) - 1)) {
#ifdef __aarch64__
// /system/bin/init executed
struct user_arg_ptr *ptr = (struct user_arg_ptr*) argv;
int argc = count(*ptr, MAX_ARG_STRINGS);
@@ -183,6 +185,19 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
pr_err("/system/bin/init parse args err!\n");
}
}
#else
// The argument parse is incorrect becuase of the struct user_arg_ptr has 16bytes
// and it is passed by value(not pointer), in arm64, it is correct becuase the register
// is just arranged correct accidentally, but is not correct in x86_64
// i have no device to test, so revert it for x86_64
static int init_count = 0;
if (++init_count == 2) {
// 1: /system/bin/init selinux_setup
// 2: /system/bin/init second_stage
pr_info("/system/bin/init second_stage executed\n");
apply_kernelsu_rules();
}
#endif
}
if (first_app_process &&

View File

@@ -15,7 +15,7 @@
* From ss/ebitmap.h
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) && \
LINUX_VERSION_CODE <= KERNEL_VERSION(4, 9, 250)
LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#ifdef HISI_SELINUX_EBITMAP_RO
#define CONFIG_IS_HW_HISI
#endif

View File

@@ -32,7 +32,13 @@ cd "$GKI_ROOT"
echo "[+] GKI_ROOT: $GKI_ROOT"
echo "[+] Copy kernel su driver to $DRIVER_DIR"
test -e "$DRIVER_DIR/kernelsu" || ln -sf "$GKI_ROOT/KernelSU/kernel" "$DRIVER_DIR/kernelsu"
cd "$DRIVER_DIR"
if test -d "$GKI_ROOT/common/drivers"; then
ln -sf "../../KernelSU/kernel" "kernelsu"
elif test -d "$GKI_ROOT/drivers"; then
ln -sf "../KernelSU/kernel" "kernelsu"
fi
cd "$GKI_ROOT"
echo '[+] Add kernel su driver to Makefile'

18
manager/.gitignore vendored
View File

@@ -1,17 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
sign.properties
.idea
.DS_Store
build
captures
.cxx
key.jks

3
manager/.idea/.gitignore generated vendored
View File

@@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

1
manager/.idea/.name generated
View File

@@ -1 +0,0 @@
KernelSU

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="Embedded JDK" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@@ -1,37 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
</profile>
</component>

10
manager/.idea/misc.xml generated
View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

6
manager/.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@@ -1,37 +1,51 @@
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
plugins {
id("com.android.application")
id("com.google.devtools.ksp")
kotlin("android")
alias(libs.plugins.agp.app)
alias(libs.plugins.kotlin)
alias(libs.plugins.ksp)
alias(libs.plugins.lsplugin.apksign)
}
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"
ndkVersion = "25.1.8937393"
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters += listOf("arm64-v8a", "x86_64")
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
lint {
checkReleaseBuilds = false
}
buildFeatures {
aidl = true
buildConfig = true
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.3.2"
kotlinOptions {
jvmTarget = "17"
}
packagingOptions {
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
jniLibs {
useLegacyPackaging = true
}
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
@@ -39,15 +53,14 @@ android {
externalNativeBuild {
cmake {
path(file("src/main/cpp/CMakeLists.txt"))
version = "3.18.1"
path("src/main/cpp/CMakeLists.txt")
}
}
applicationVariants.all {
outputs.forEach {
val output = it as BaseVariantOutputImpl
output.outputFileName = "KernelSU_$versionName-${buildType.name}.apk"
output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk"
}
kotlin.sourceSets {
@@ -59,40 +72,40 @@ android {
}
dependencies {
val accompanistVersion = "0.28.0"
val composeDestinationsVersion = "1.7.27-beta"
implementation(platform("androidx.compose:compose-bom:2023.04.00"))
debugImplementation("androidx.compose.ui:ui-test-manifest")
debugImplementation("androidx.compose.ui:ui-tooling")
implementation("androidx.activity:activity-compose:1.7.0")
implementation("androidx.compose.material:material:1.5.0-alpha01")
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
implementation("androidx.navigation:navigation-compose:2.5.3")
implementation("com.google.accompanist:accompanist-drawablepainter:$accompanistVersion")
implementation("com.google.accompanist:accompanist-navigation-animation:$accompanistVersion")
implementation("com.google.accompanist:accompanist-systemuicontroller:$accompanistVersion")
implementation("io.github.raamcosta.compose-destinations:animations-core:$composeDestinationsVersion")
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.compose)
implementation("io.coil-kt:coil-compose:2.3.0")
implementation("me.zhanghai.android.appiconloader:appiconloader-coil:1.5.0")
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)
val libsuVersion = "5.0.5"
// change to official build(com.github.topjohnwu.libsu) when this pr is merged:
// https://github.com/topjohnwu/libsu/pull/151
implementation("com.github.tiann.libsu:core:$libsuVersion")
implementation("com.github.tiann.libsu:service:$libsuVersion")
implementation("dev.rikka.rikkax.parcelablelist:parcelablelist:2.0.0")
debugImplementation(libs.androidx.compose.ui.test.manifest)
debugImplementation(libs.androidx.compose.ui.tooling)
implementation("com.github.alorma:compose-settings-ui-m3:0.22.0")
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
ksp("io.github.raamcosta.compose-destinations:ksp:$composeDestinationsVersion")
implementation(libs.com.google.accompanist.drawablepainter)
implementation(libs.com.google.accompanist.navigation.animation)
implementation(libs.com.google.accompanist.systemuicontroller)
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
implementation(libs.compose.destinations.animations.core)
ksp(libs.compose.destinations.ksp)
implementation(libs.com.github.alorma.compose.settings.ui.m3)
implementation(libs.com.github.topjohnwu.libsu.core)
implementation(libs.com.github.topjohnwu.libsu.service)
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)
}

View File

@@ -1,21 +1,9 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-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

View File

@@ -1,24 +0,0 @@
package me.weishu.kernelsu
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("me.weishu.kernelsu", appContext.packageName)
}
}

View File

@@ -6,14 +6,13 @@
android:name=".KernelSUApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:enableOnBackInvokedCallback="true"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.KernelSU"
tools:targetApi="31">
tools:targetApi="33">
<activity
android:name=".ui.MainActivity"
android:exported="true"

View File

@@ -5,23 +5,29 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.*
import androidx.compose.material3.ExperimentalMaterial3Api
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.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.navigation.popBackStack
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
import me.weishu.kernelsu.ui.component.rememberDialogHostState
import me.weishu.kernelsu.ui.screen.BottomBarDestination
import me.weishu.kernelsu.ui.screen.NavGraphs
import me.weishu.kernelsu.ui.screen.appCurrentDestinationAsState
import me.weishu.kernelsu.ui.screen.destinations.Destination
import me.weishu.kernelsu.ui.screen.startAppDestination
import me.weishu.kernelsu.ui.theme.KernelSUTheme
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
@@ -58,31 +64,26 @@ class MainActivity : ComponentActivity() {
@Composable
private fun BottomBar(navController: NavHostController) {
val topDestination: Destination = navController.appCurrentDestinationAsState().value
?: NavGraphs.root.startAppDestination
val bottomBarRoutes = remember {
BottomBarDestination.values().map { it.direction.route }
}
NavigationBar(tonalElevation = 8.dp) {
BottomBarDestination.values().forEach { destination ->
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
NavigationBarItem(
selected = topDestination.route == destination.direction.route,
selected = isCurrentDestOnBackStack,
onClick = {
val firstRoute = navController.backQueue.reversed().first {
it.destination.route in bottomBarRoutes
}.destination.route
if (isCurrentDestOnBackStack) {
navController.popBackStack(destination.direction, false)
}
navController.navigate(destination.direction.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = firstRoute != destination.direction.route
popUpTo(NavGraphs.root.route) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
},
icon = {
if (topDestination.route == destination.direction.route) {
if (isCurrentDestOnBackStack) {
Icon(destination.iconSelected, stringResource(destination.label))
} else {
Icon(destination.iconNotSelected, stringResource(destination.label))

View File

@@ -3,16 +3,23 @@ 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.*
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.LocalTextStyle
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.MutableState
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
@@ -59,46 +66,43 @@ private fun AboutCardContent() {
modifier = Modifier
.fillMaxWidth()
) {
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodyMedium) {
val drawable = ResourcesCompat.getDrawable(
LocalContext.current.resources,
R.mipmap.ic_launcher,
LocalContext.current.theme
)
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)
)
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.width(12.dp))
Spacer(modifier = Modifier.height(8.dp))
Column {
Text(
stringResource(id = R.string.app_name),
style = MaterialTheme.typography.titleSmall,
fontSize = 18.sp
HtmlText(
html = stringResource(
id = R.string.about_source_code,
"<b><a href=\"https://github.com/tiann/KernelSU\">GitHub</a></b>",
"<b><a href=\"https://t.me/KernelSU\">Telegram</a></b>"
)
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,
"<b><a href=\"https://github.com/tiann/KernelSU\">GitHub</a></b>",
"<b><a href=\"https://t.me/KernelSU\">Telegram</a></b>"
)
)
}
)
}
}
}
@@ -106,6 +110,7 @@ private fun AboutCardContent() {
@Composable
fun HtmlText(html: String, modifier: Modifier = Modifier) {
val contentColor = LocalContentColor.current
AndroidView(
modifier = modifier,
factory = { context ->
@@ -113,6 +118,9 @@ fun HtmlText(html: String, modifier: Modifier = Modifier) {
it.movementMethod = LinkMovementMethod.getInstance()
}
},
update = { it.text = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT) }
update = {
it.text = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT)
it.setTextColor(contentColor.toArgb())
}
)
}

View File

@@ -1,56 +1,113 @@
package me.weishu.kernelsu.ui.component
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import me.weishu.kernelsu.ui.util.LocalDialogHost
import kotlin.coroutines.resume
sealed interface DialogResult {
object Confirmed : DialogResult
object Dismissed : DialogResult
}
interface DialogVisuals
interface DialogVisuals {
interface LoadingDialogVisuals : DialogVisuals
interface PromptDialogVisuals : DialogVisuals {
val title: String
val content: String
}
interface ConfirmDialogVisuals : PromptDialogVisuals {
val confirm: String?
val dismiss: String?
}
interface DialogData {
sealed interface DialogData {
val visuals: DialogVisuals
}
fun confirm()
interface LoadingDialogData : DialogData {
override val visuals: LoadingDialogVisuals
fun dismiss()
}
interface PromptDialogData : DialogData {
override val visuals: PromptDialogVisuals
fun dismiss()
}
interface ConfirmDialogData : PromptDialogData {
override val visuals: ConfirmDialogVisuals
fun confirm()
}
sealed interface ConfirmResult {
object Confirmed : ConfirmResult
object Canceled : ConfirmResult
}
class DialogHostState {
private data class DialogVisualsImpl(
private object LoadingDialogVisualsImpl : LoadingDialogVisuals
private data class PromptDialogVisualsImpl(
override val title: String,
override val content: String
) : PromptDialogVisuals
private data class ConfirmDialogVisualsImpl(
override val title: String,
override val content: String,
override val confirm: String?,
override val dismiss: String?
) : DialogVisuals
) : ConfirmDialogVisuals
private data class DialogDataImpl(
override val visuals: DialogVisuals,
val continuation: CancellableContinuation<DialogResult>
) : DialogData {
private data class LoadingDialogDataImpl(
override val visuals: LoadingDialogVisuals,
private val continuation: CancellableContinuation<Unit>,
) : LoadingDialogData {
override fun dismiss() {
if (continuation.isActive) continuation.resume(Unit)
}
}
private data class PromptDialogDataImpl(
override val visuals: PromptDialogVisuals,
private val continuation: CancellableContinuation<Unit>,
) : PromptDialogData {
override fun dismiss() {
if (continuation.isActive) continuation.resume(Unit)
}
}
private data class ConfirmDialogDataImpl(
override val visuals: ConfirmDialogVisuals,
private val continuation: CancellableContinuation<ConfirmResult>
) : ConfirmDialogData {
override fun confirm() {
if (continuation.isActive) continuation.resume(DialogResult.Confirmed)
if (continuation.isActive) continuation.resume(ConfirmResult.Confirmed)
}
override fun dismiss() {
if (continuation.isActive) continuation.resume(DialogResult.Dismissed)
if (continuation.isActive) continuation.resume(ConfirmResult.Canceled)
}
}
@@ -59,16 +116,58 @@ class DialogHostState {
var currentDialogData by mutableStateOf<DialogData?>(null)
private set
suspend fun showDialog(
suspend fun showLoading() {
try {
mutex.withLock {
suspendCancellableCoroutine { continuation ->
currentDialogData = LoadingDialogDataImpl(
visuals = LoadingDialogVisualsImpl,
continuation = continuation
)
}
}
} finally {
currentDialogData = null
}
}
suspend fun <R> withLoading(block: suspend () -> R) = coroutineScope {
val showLoading = launch {
showLoading()
}
val result = block()
showLoading.cancel()
result
}
suspend fun showPrompt(title: String, content: String) {
try {
mutex.withLock {
suspendCancellableCoroutine { continuation ->
currentDialogData = PromptDialogDataImpl(
visuals = PromptDialogVisualsImpl(title, content),
continuation = continuation
)
}
}
} finally {
currentDialogData = null
}
}
suspend fun showConfirm(
title: String,
content: String,
confirm: String? = null,
dismiss: String? = null
): DialogResult = mutex.withLock {
): ConfirmResult = mutex.withLock {
try {
return@withLock suspendCancellableCoroutine { continuation ->
currentDialogData = DialogDataImpl(
visuals = DialogVisualsImpl(title, content, confirm, dismiss),
currentDialogData = ConfirmDialogDataImpl(
visuals = ConfirmDialogVisualsImpl(title, content, confirm, dismiss),
continuation = continuation
)
}
@@ -85,82 +184,85 @@ fun rememberDialogHostState(): DialogHostState {
}
}
@Composable
fun BaseDialog(
state: DialogHostState = LocalDialogHost.current,
title: @Composable (String) -> Unit,
confirmButton: @Composable (String?, () -> Unit) -> Unit,
dismissButton: @Composable (String?, () -> Unit) -> Unit,
content: @Composable (String) -> Unit = { Text(text = it) },
) {
val currentDialogData = state.currentDialogData ?: return
val visuals = currentDialogData.visuals
AlertDialog(
onDismissRequest = {
currentDialogData.dismiss()
},
title = {
title(visuals.title)
},
text = {
content(visuals.content)
},
confirmButton = {
confirmButton(visuals.confirm, currentDialogData::confirm)
},
dismissButton = {
dismissButton(visuals.dismiss, currentDialogData::dismiss)
}
)
private inline fun <reified T : DialogData> DialogData?.tryInto(): T? {
return when (this) {
is T -> this
else -> null
}
}
@Composable
fun SimpleDialog(
fun LoadingDialog(
state: DialogHostState = LocalDialogHost.current,
content: @Composable (String) -> Unit
) {
BaseDialog(
state = state,
state.currentDialogData.tryInto<LoadingDialogData>() ?: return
val dialogProperties = remember {
DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false)
}
Dialog(onDismissRequest = {}, properties = dialogProperties) {
Surface(
modifier = Modifier
.size(100.dp),
shape = RoundedCornerShape(8.dp)
) {
Box(
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator()
}
}
}
}
@Composable
fun PromptDialog(
state: DialogHostState = LocalDialogHost.current,
) {
val promptDialogData = state.currentDialogData.tryInto<PromptDialogData>() ?: return
val visuals = promptDialogData.visuals
AlertDialog(
onDismissRequest = {
promptDialogData.dismiss()
},
title = {
Text(text = it)
Text(text = visuals.title)
},
confirmButton = { text, confirm ->
text?.let {
TextButton(onClick = confirm) {
Text(text = it)
}
text = {
Text(text = visuals.content)
},
confirmButton = {
TextButton(onClick = { promptDialogData.dismiss() }) {
Text(text = stringResource(id = android.R.string.ok))
}
},
dismissButton = { text, dismiss ->
text?.let {
TextButton(onClick = dismiss) {
Text(text = it)
}
}
},
content = content
dismissButton = null,
)
}
@Composable
fun ConfirmDialog(state: DialogHostState = LocalDialogHost.current) {
BaseDialog(
state = state,
title = {
Text(text = it)
val confirmDialogData = state.currentDialogData.tryInto<ConfirmDialogData>() ?: return
val visuals = confirmDialogData.visuals
AlertDialog(
onDismissRequest = {
confirmDialogData.dismiss()
},
confirmButton = { text, confirm ->
text?.let {
TextButton(onClick = confirm) {
Text(text = it)
}
title = {
Text(text = visuals.title)
},
text = {
Text(text = visuals.content)
},
confirmButton = {
TextButton(onClick = { confirmDialogData.confirm() }) {
Text(text = visuals.confirm ?: stringResource(id = android.R.string.ok))
}
},
dismissButton = { text, dismiss ->
text?.let {
TextButton(onClick = dismiss) {
Text(text = it)
}
dismissButton = {
TextButton(onClick = { confirmDialogData.dismiss() }) {
Text(text = visuals.dismiss ?: stringResource(id = android.R.string.cancel))
}
},
)

View File

@@ -207,6 +207,7 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
@Composable
fun LearnMoreCard() {
val uriHandler = LocalUriHandler.current
val url = stringResource(R.string.home_learn_kernelsu_url)
ElevatedCard {
@@ -214,7 +215,7 @@ fun LearnMoreCard() {
modifier = Modifier
.fillMaxWidth()
.clickable {
uriHandler.openUri("https://kernelsu.org/guide/what-is-kernelsu.html")
uriHandler.openUri(url)
}
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically

View File

@@ -34,7 +34,7 @@ import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.DialogResult
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
@@ -143,13 +143,13 @@ private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier
val snackBarHost = LocalSnackbarHost.current
suspend fun onModuleUninstall(module: ModuleViewModel.ModuleInfo) {
val dialogResult = dialogHost.showDialog(
val confirmResult = dialogHost.showConfirm(
moduleStr,
content = moduleUninstallConfirm.format(module.name),
confirm = uninstall,
dismiss = cancel
)
if (dialogResult != DialogResult.Confirmed) {
if (confirmResult != ConfirmResult.Confirmed) {
return
}

View File

@@ -2,21 +2,14 @@ package me.weishu.kernelsu.ui.screen
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color.Companion.White
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.core.content.FileProvider
import com.alorma.compose.settings.ui.*
import com.ramcosta.composedestinations.annotation.Destination
@@ -27,6 +20,7 @@ import kotlinx.coroutines.withContext
import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.AboutDialog
import me.weishu.kernelsu.ui.component.LoadingDialog
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.getBugreportFile
@@ -46,13 +40,11 @@ fun SettingScreen(navigator: DestinationsNavigator) {
})
}
) { paddingValues ->
LoadingDialog()
val showAboutDialog = remember { mutableStateOf(false) }
AboutDialog(showAboutDialog)
var showLoadingDialog by remember { mutableStateOf(false) }
LoadingDialog(showLoadingDialog)
Column(modifier = Modifier.padding(paddingValues)) {
val context = LocalContext.current
@@ -64,14 +56,12 @@ fun SettingScreen(navigator: DestinationsNavigator) {
},
onClick = {
scope.launch {
showLoadingDialog = true
val bugreport = withContext(Dispatchers.IO) {
getBugreportFile(context)
val bugreport = dialogHost.withLoading {
withContext(Dispatchers.IO) {
getBugreportFile(context)
}
}
showLoadingDialog = false
val uri: Uri =
FileProvider.getUriForFile(
context,
@@ -118,25 +108,4 @@ private fun TopBar(onBack: () -> Unit = {}) {
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) }
},
)
}
@Composable
fun LoadingDialog(showLoadingDialog: Boolean) {
if (!showLoadingDialog) {
return
}
Dialog(
onDismissRequest = { },
DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(100.dp)
.background(White, shape = RoundedCornerShape(8.dp))
) {
CircularProgressIndicator()
}
}
}

View File

@@ -25,7 +25,7 @@ import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.DialogResult
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.SearchAppBar
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
@@ -119,13 +119,13 @@ fun SuperUserScreen() {
AppItem(app, isChecked) { checked ->
scope.launch {
if (checked) {
val dialogResult = dialogHost.showDialog(
val confirmResult = dialogHost.showConfirm(
app.label,
content = content,
confirm = confirm,
dismiss = cancel
)
if (dialogResult != DialogResult.Confirmed) {
if (confirmResult != ConfirmResult.Confirmed) {
return@launch
}
}

View File

@@ -0,0 +1,68 @@
<resources>
<string name="app_name" translatable="false">KernelSU</string>
<string name="home">الرئيسية</string>
<string name="home_not_installed">غير مثبت</string>
<string name="home_click_to_install">اضغط لتثبيت</string>
<string name="home_working">يعمل</string>
<string name="home_working_version">الاصدار: %d</string>
<string name="home_superuser_count">مستخدمين الجذر: %d</string>
<string name="home_module_count">الوحدات: %d</string>
<string name="home_unsupported">غير مدعوم</string>
<string name="home_unsupported_reason">KernelSU يدعم GKI kernels الان</string>
<string name="home_copied_to_clipboard">نسخ الي حافظة</string>
<string name="home_support">مدعوم</string>
<string name="home_kernel">نواه</string>
<string name="home_arch">معمارية</string>
<string name="home_manager_version">اصدار المدير</string>
<string name="home_api">API Level</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">بصمة</string>
<string name="home_securitypatch">تصحيح الأمان</string>
<string name="home_selinux_status">وضع SELinux</string>
<string name="selinux_status_disabled">غير مفعل</string>
<string name="selinux_status_enforcing">فرض</string>
<string name="selinux_status_permissive">متساهل</string>
<string name="selinux_status_unknown">مجهول</string>
<string name="superuser">مستخدم الجذر</string>
<string name="superuser_failed_to_grant_root">فشل منح الجذر لـ %d</string>
<string name="superuser_allow_root_confirm">هل أنت متأكد من منح حق الوصول إلى الجذر إلى %s?</string>
<string name="module_failed_to_enable">فشل في تمكين الوحدة النمطية: %s</string>
<string name="module_failed_to_disable">فشل تعطيل الوحدة النمطية: %s</string>
<string name="module_empty">لا توجد وحدة مثبتة</string>
<string name="module">وحدة</string>
<string name="uninstall">الغاء التثبيت</string>
<string name="module_install">تثبيت</string>
<string name="install">تثبيت</string>
<string name="reboot">اعادة تشغيل</string>
<string name="settings">الاعدادات</string>
<string name="reboot_userspace">اعادة تشغيل سريع</string>
<string name="reboot_recovery">اعادة تشغيل الي ريكفيري</string>
<string name="reboot_bootloader">اعادة تشغيل الي بوت لودر</string>
<string name="reboot_download">اعادة تشغيل الي وضع داونلود</string>
<string name="reboot_edl">اعادة تشغيل الي وضع EDL</string>
<string name="about">من نحن</string>
<string name="require_kernel_version_8">يتطلب KernelSU اصدار 8+</string>
<string name="module_uninstall_confirm">Are you sure you want to uninstall module %s?</string>
<string name="module_uninstall_success">%s uninstalled</string>
<string name="module_uninstall_failed">Failed to uninstall: %s</string>
<string name="module_version">الاصدار</string>
<string name="module_author">مؤلف</string>
<string name="module_overlay_fs_not_available">التراكبات غير متوفرة ، لا يمكن للوحدة أن تعمل!</string>
<string name="refresh">رفريش</string>
<string name="show_system_apps">عرض تطبيقات النظام</string>
<string name="hide_system_apps">اخفاء تطبيقات النظام</string>
<string name="send_log">ارسال اللوج</string>
<string name="safe_mode">وضع الامن</string>
<string name="reboot_to_apply">اعادة تشغيل لتطبيق التغيرات</string>
<string name="module_magisk_conflict">تم تعطيل الوحدات النمطية لأنها تتعارض مع Magisk\'s!</string>
<string name="home_learn_kernelsu">تعلم KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">تعرف على كيفية تثبيت KernelSU واستخدام الوحدات النمطية</string>
<string name="home_support_title">ادعمنا</string>
<string name="home_support_content">KernelSU هو وسيظل دائمًا مجانيًا ومفتوح المصدر. ومع ذلك ، يمكنك أن تظهر لنا أنك تهتم بالتبرع.</string>
<string name="about_source_code"><![CDATA[View source code at %1$s<br/>Join our %2$s channel]]></string>
</resources>

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">কার্নেলএসইউ</string>
<string name="home">হোম</string>
<string name="home_not_installed">ইনস্টল করা হয়নি</string>
<string name="home_click_to_install">ইনস্টল করার জন্য ক্লিক করুন</string>
<string name="home_working"> ওয়ার্কিং</string>
<string name="home_working_version">ওয়ার্কিং সংস্করণ: %d</string>
<string name="home_superuser_count">সুপার ইউজার: %d</string>
<string name="home_module_count">মডিউল: %d</string>
<string name="home_unsupported">অসমর্থিত</string>
<string name="home_unsupported_reason">কার্নেলএসইউ শুধুমাত্র জিকেআই কার্নেল সমর্থন করে</string>
<string name="home_copied_to_clipboard">ক্লিপবোর্ডে কপি করা হয়েছে</string>
<string name="home_support">সমর্থন</string>
<string name="home_kernel">কার্নেল</string>
<string name="home_arch">খিলান</string>
<string name="home_manager_version">ম্যানেজার সংস্করণ</string>
<string name="home_api">এপিআই স্তর</string>
<string name="home_abi">এবিআই</string>
<string name="home_fingerprint">ফিঙ্গারপ্রিন্ট</string>
<string name="home_securitypatch">সিকিউরিটি প্যাচ</string>
<string name="home_selinux_status">সেলিনাক্স স্ট্যাটাস</string>
<string name="selinux_status_disabled">ডিজেবল</string>
<string name="selinux_status_enforcing">এনফোর্সিং</string>
<string name="selinux_status_permissive">অনুমতিমূলক</string>
<string name="selinux_status_unknown">অপরিচিত</string>
<string name="superuser">সুপার ইউজার</string>
<string name="superuser_failed_to_grant_root">এর জন্য রুট প্রদান করতে ব্যর্থ হয়েছে %d</string>
<string name="superuser_allow_root_confirm">নিশ্চিত আপনি রুট দিতে চান %s?</string>
<string name="module_failed_to_enable">মডিউল সক্ষম করতে ব্যর্থ হয়েছে: %s</string>
<string name="module_failed_to_disable">মডিউল নিষ্ক্রিয় করতে ব্যর্থ হয়েছে: %s</string>
<string name="module_empty">কোন মডিউল ইনস্টল করা নেই</string>
<string name="module">মডিউল</string>
<string name="uninstall">আনইন্সটল</string>
<string name="module_install">মডিউল ইনস্টল</string>
<string name="install">ইনস্টল</string>
<string name="reboot">রিবুট</string>
<string name="settings">সেটিংস</string>
<string name="reboot_userspace">সফট রিবুট</string>
<string name="reboot_recovery">রিবুট রিকোভারি</string>
<string name="reboot_bootloader">রিবুট বুটলোডার</string>
<string name="reboot_download">রিবুট ডাউনলোড</string>
<string name="reboot_edl">রিবুট ইডিএল</string>
<string name="about">এবাউট</string>
<string name="require_kernel_version_8">কার্নেলএসইউ সংস্করণ প্রয়োজন ৮+</string>
<string name="module_uninstall_confirm">মডিউল আনইনস্টল নিশ্চিত করুন %s?</string>
<string name="module_uninstall_success">%s আনইনস্টল সফল</string>
<string name="module_uninstall_failed">আনইন্সটল ব্যর্থ: %s</string>
<string name="module_version">ভার্সন</string>
<string name="module_author">লেখক</string>
<string name="module_overlay_fs_not_available">ওভারলেএফএস উপলব্ধ নয়, মডিউল কাজ করতে পারে না!</string>
<string name="refresh">রিফ্রেশ</string>
<string name="show_system_apps">শো সিস্টেম অ্যাপস</string>
<string name="hide_system_apps">হাইড সিস্টেম অ্যাপস</string>
<string name="send_log">সেন্ড লগ</string>
<string name="safe_mode">সেইফ মোড</string>
<string name="reboot_to_apply">রিবুট এপ্লাই</string>
<string name="module_magisk_conflict">মডিউলগুলি অক্ষম কারণ তারা ম্যাজিস্কের সাথে বিরোধিতা করে!</string>
<string name="home_learn_kernelsu">লার্ন কার্নেলএসইউ</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">কিভাবে কার্নেলএসইউ ইনস্টল করতে হয় এবং মডিউল ব্যবহার করতে হয় তা শিখুন</string>
<string name="home_support_title">সাপোর্ট টাইটেল</string>
<string name="home_support_content">কার্নেলএসইউ বিনামূল্যে এবং ওপেন সোর্স, এবং সবসময় থাকবে। আপনি সবসময় একটি অনুদান দিয়ে আপনার কৃতজ্ঞতা প্রদর্শন করতে পারেন.</string>
<string name="about_source_code"><![CDATA[Bekijk source code op %1$s<br/>আমাদের %2$s চ্যানেল মার্জ করুন]]></string>
</resources>

View File

@@ -56,6 +56,7 @@
<string name="reboot_to_apply">Restart untuk menerapkan</string>
<string name="module_magisk_conflict">Module akan di nonaktifkan karna konflik dengan magisk\'s!</string>
<string name="home_learn_kernelsu">Belajar KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/id_ID/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Cara menginstall KernelSu dan menggunakan Module</string>
<string name="home_support_title">Dukung kami</string>
<string name="home_support_content">KernelSU akan selalu gratis dan open source. Namun Anda dapat menunjukkan kepada kami bahwa Anda peduli dengan memberikan sedikit donasi.</string>

View File

@@ -0,0 +1,66 @@
<resources>
<string name="home">Home</string>
<string name="home_not_installed">Non installato</string>
<string name="home_click_to_install">Clicca per installare</string>
<string name="home_working">In esecuzione</string>
<string name="home_working_version">Versione: %d</string>
<string name="home_superuser_count">Superuser: %d</string>
<string name="home_module_count">Moduli: %d</string>
<string name="home_unsupported">Non supportato</string>
<string name="home_unsupported_reason">KernelSU ora supporta solo i kernel GKI</string>
<string name="home_copied_to_clipboard">Copiato negli appunti</string>
<string name="home_support">Supporto</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Architettura</string>
<string name="home_manager_version">Versione del manager</string>
<string name="home_api">Livello API</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">Patch di sicurezza</string>
<string name="home_selinux_status">Stato SELinux</string>
<string name="selinux_status_disabled">Disabilitato</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">Sconosciuto</string>
<string name="superuser">Accesso root</string>
<string name="superuser_failed_to_grant_root">Impossibile concedere l\'accesso root per %d</string>
<string name="superuser_allow_root_confirm">Sei sicuro di concedere l\'accesso root a %s?</string>
<string name="module_failed_to_enable">Impossibile abilitare il modulo: %s</string>
<string name="module_failed_to_disable">Impossibile disabilitare il modulo: %s</string>
<string name="module_empty">Nessun modulo installato</string>
<string name="module">Moduli</string>
<string name="uninstall">Disinstalla</string>
<string name="module_install">Installa</string>
<string name="install">Installa</string>
<string name="reboot">Riavvia</string>
<string name="settings">Impostazioni</string>
<string name="reboot_userspace">Riavvio veloce</string>
<string name="reboot_recovery">Riavvia in Recovery</string>
<string name="reboot_bootloader">Riavvia in modalità Bootloader</string>
<string name="reboot_download">Riavvia in modalità Download</string>
<string name="reboot_edl">Riavvia in modalità EDL</string>
<string name="about">Informazioni</string>
<string name="require_kernel_version_8">Richiede KernelSU versione 8+</string>
<string name="module_uninstall_confirm">Sei sicuro di voler disinstallare il modulo %s?</string>
<string name="module_uninstall_success">%s disinstallato</string>
<string name="module_uninstall_failed">Impossibile disinstallare: %s</string>
<string name="module_version">Versione</string>
<string name="module_author">Autore</string>
<string name="module_overlay_fs_not_available">overlayfs non è disponibile, il modulo non può funzionare!</string>
<string name="refresh">Aggiorna</string>
<string name="show_system_apps">Mostra app di sistema</string>
<string name="hide_system_apps">Nascondi app di sistema</string>
<string name="send_log">Invia log</string>
<string name="safe_mode">Modalità provvisoria</string>
<string name="reboot_to_apply">Riavvia per applicare la modifica</string>
<string name="module_magisk_conflict">I moduli sono disabilitati perché in conflitto con quelli di Magisk!</string>
<string name="home_learn_kernelsu">Scopri KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Scopri come installare KernelSU e utilizzare i moduli</string>
<string name="home_support_title">Supportaci</string>
<string name="home_support_content">KernelSU è, e sempre sarà, gratuito e open source. Puoi comunque mostrarci il tuo apprezzamento facendo una donazione.</string>
<string name="about_source_code"><![CDATA[Visualizza il codice sorgente su %1$s<br/>Unisciti al nostro canale %2$s]]></string>
</resources>

View File

@@ -51,4 +51,5 @@
<string name="send_log">ログを送信</string>
<string name="safe_mode">セーフモード</string>
<string name="reboot_to_apply">再起動をして有効化する</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
</resources>

View File

@@ -0,0 +1,64 @@
<resources>
<string name="home"></string>
<string name="home_not_installed">설치되지 않음</string>
<string name="home_click_to_install">이 곳을 눌러 설치하기</string>
<string name="home_working">정상 작동 중</string>
<string name="home_working_version">버전: %d</string>
<string name="home_superuser_count">루트 권한: %d개</string>
<string name="home_module_count">설치된 모듈: %d개</string>
<string name="home_unsupported">지원되지 않음</string>
<string name="home_unsupported_reason">KernelSU는 현재 GKI 커널만 지원합니다</string>
<string name="home_copied_to_clipboard">클립보드로 복사됨</string>
<string name="home_support">지원</string>
<string name="home_kernel">커널</string>
<string name="home_arch">아키텍처</string>
<string name="home_manager_version">매니저 버전</string>
<string name="home_api">API 레벨</string>
<string name="home_fingerprint">빌드 정보</string>
<string name="home_securitypatch">보안 패치 버전</string>
<string name="home_selinux_status">SELinux 상태</string>
<string name="selinux_status_disabled">비활성화됨</string>
<string name="selinux_status_enforcing">적용</string>
<string name="selinux_status_permissive">허용</string>
<string name="selinux_status_unknown">알 수 없음</string>
<string name="superuser">슈퍼유저</string>
<string name="superuser_failed_to_grant_root">%d에 루트 권한 부여 실패</string>
<string name="superuser_allow_root_confirm">%s에 루트 권한을 부여할까요?</string>
<string name="module_failed_to_enable">모듈 활성화 실패: %s</string>
<string name="module_failed_to_disable">모듈 비활성화 실패: %s</string>
<string name="module_empty">설치된 모듈 없음</string>
<string name="module">모듈</string>
<string name="uninstall">삭제</string>
<string name="module_install">설치</string>
<string name="install">설치</string>
<string name="reboot">다시 시작</string>
<string name="settings">설정</string>
<string name="reboot_userspace">빠른 다시 시작</string>
<string name="reboot_recovery">복구 모드로 다시 시작</string>
<string name="reboot_bootloader">부트로더로 다시 시작</string>
<string name="reboot_download">다운로드 모드로 다시 시작</string>
<string name="reboot_edl">EDL 모드로 다시 시작</string>
<string name="about">정보</string>
<string name="require_kernel_version_8">버전 8 이상의 KernelSU가 필요합니다</string>
<string name="module_uninstall_confirm">%s 모듈을 삭제할까요?</string>
<string name="module_uninstall_success">%s 모듈 삭제됨</string>
<string name="module_uninstall_failed">모듈 삭제 실패: %s</string>
<string name="module_version">버전</string>
<string name="module_author">제작자</string>
<string name="module_overlay_fs_not_available">overlayfs 사용 불가, 모듈을 사용할 수 없습니다!</string>
<string name="refresh">새로고침</string>
<string name="show_system_apps">시스템 앱 보이기</string>
<string name="hide_system_apps">시스템 앱 숨기기</string>
<string name="send_log">로그 보내기</string>
<string name="safe_mode">안전 모드</string>
<string name="reboot_to_apply">다시 시작하여 변경 사항 적용</string>
<string name="module_magisk_conflict">Magisk와의 충돌로 인해 모듈을 사용할 수 없습니다!</string>
<string name="home_learn_kernelsu">KernelSU 알아보기</string>
<string name="home_click_to_learn_kernelsu">KernelSU 설치 방법과 모듈 사용 방법을 확인합니다.</string>
<string name="home_support_title">지원이 필요해요!</string>
<string name="home_support_content">KernelSU는 지금도, 앞으로도 항상 무료이며 오픈 소스로 유지됩니다. 기부를 통해 여러분의 관심을 보여주세요.</string>
<string name="about_source_code"><![CDATA[%1$s에서 소스 코드 보기<br/>%2$s 채널 참가하기]]></string>
</resources>

View File

@@ -0,0 +1,68 @@
<resources>
<string name="app_name" translatable="false">KernelSU</string>
<string name="home">Home</string>
<string name="home_not_installed">Niet geïnstalleerd</string>
<string name="home_click_to_install">Klik om te installeren</string>
<string name="home_working">Werkend</string>
<string name="home_working_version">Versie: %d</string>
<string name="home_superuser_count">Superusers: %d</string>
<string name="home_module_count">Modules: %d</string>
<string name="home_unsupported">Niet ondersteund</string>
<string name="home_unsupported_reason">KernelSU ondersteunt alleen GKI kernels</string>
<string name="home_copied_to_clipboard">Gekopiëerd naar clipboard</string>
<string name="home_support">Ondersteuning</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Arch</string>
<string name="home_manager_version">Manager Versie</string>
<string name="home_api">API Niveau</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">Veiligheidspatch</string>
<string name="home_selinux_status">SELinux status</string>
<string name="selinux_status_disabled">Uitgeschakeld</string>
<string name="selinux_status_enforcing">Afgedwongen</string>
<string name="selinux_status_permissive">Permissief</string>
<string name="selinux_status_unknown">Niet gekend</string>
<string name="superuser">Superuser</string>
<string name="superuser_failed_to_grant_root">Mislukt om root te geven voor %d</string>
<string name="superuser_allow_root_confirm">Zeker dat je root wil geven aan %s?</string>
<string name="module_failed_to_enable">Mislukt om module in te schakelen: %s</string>
<string name="module_failed_to_disable">Mislukt om module uit te schakelen: %s</string>
<string name="module_empty">Geen module geïnstalleerd</string>
<string name="module">Module</string>
<string name="uninstall">Verwijderen</string>
<string name="module_install">Installeren</string>
<string name="install">Installeren</string>
<string name="reboot">Herstart</string>
<string name="settings">Instellingen</string>
<string name="reboot_userspace">Soft herstart</string>
<string name="reboot_recovery">Herstart naar Recovery</string>
<string name="reboot_bootloader">Herstart naar Bootloader</string>
<string name="reboot_download">Herstart om te downloaden</string>
<string name="reboot_edl">Herstart naar EDL</string>
<string name="about">Over</string>
<string name="require_kernel_version_8">Vereist KernelSU versie 8+</string>
<string name="module_uninstall_confirm">Zeker van het verwijderen van module %s?</string>
<string name="module_uninstall_success">%s verwijderd</string>
<string name="module_uninstall_failed">Mislukt om te verwijderen: %s</string>
<string name="module_version">Versie</string>
<string name="module_author">Auteur</string>
<string name="module_overlay_fs_not_available">overlayfs is niet beschikbaar, module kan niet werken!</string>
<string name="refresh">Vernieuwen</string>
<string name="show_system_apps">Toon system apps</string>
<string name="hide_system_apps">Verberg system apps</string>
<string name="send_log">Stuur Log</string>
<string name="safe_mode">Safe mode</string>
<string name="reboot_to_apply">Herstart om effect te hebben</string>
<string name="module_magisk_conflict">Modules zijn uitgeschakeld omdat ze in conflict zijn met magisk!</string>
<string name="home_learn_kernelsu">Leer KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Leer hoe KernelSU te installeren en modules te gebruiken</string>
<string name="home_support_title">Ondersteun ons</string>
<string name="home_support_content">KernelSU is, en zal altijd, vrij en open source zijn. Je kan altijd je appreciatie tonen met een donatie.</string>
<string name="about_source_code"><![CDATA[Bekijk source code op %1$s<br/>Vervoeg ons %2$s kanaal]]></string>
</resources>

View File

@@ -56,4 +56,10 @@
<string name="safe_mode">Mod sigur</string>
<string name="reboot_to_apply">Repornește pentru ca modificările să intre în vigoare</string>
<string name="module_magisk_conflict">Modulele sunt dezactivate deoarece sunt în conflict cu cele ale Magisk-ului!</string>
<string name="home_learn_kernelsu">Află mai multe despre KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Află cum să instalezi KernelSU și să utilizezi module</string>
<string name="home_support_title">Suport</string>
<string name="home_support_content">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.</string>
<string name="about_source_code"><![CDATA[Vezi codul sursă la %1$s<br/>Alătură-te canalului nostru %2$s]]></string>
</resources>

View File

@@ -58,8 +58,9 @@
<string name="reboot_to_apply">Перезагрузите, чтобы вступить в силу</string>
<string name="module_magisk_conflict">Модули отключены, потому что они конфликтуют с модулями Magisk!</string>
<string name="home_learn_kernelsu">Узнайте о KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Узнайте, как установить KernelSU и использовать модули</string>
<string name="home_support_title">Поддержите нас</string>
<string name="home_support_content">KernelSU был и всегда будет бесплатным и открытым проектом. Однако Вы всегда можете поддержать нас, отправив небольшое пожертвование.</string>
<string name="about_source_code"><![CDATA[View source code at %1$s<br/>Join our %2$s channel]]></string>
<string name="about_source_code"><![CDATA[Посмотреть исходники на %1$s<br/>Присоединяйтесь к каналу %2$s]]></string>
</resources>

View File

@@ -0,0 +1,66 @@
<resources>
<string name="home">Ana menü</string>
<string name="home_not_installed">Yüklü değil</string>
<string name="home_click_to_install">Yüklemek için dokun</string>
<string name="home_working">Çalışıyor</string>
<string name="home_working_version">Sürüm: %d</string>
<string name="home_superuser_count">Süper kullanıcılar: %d</string>
<string name="home_module_count">Modüller: %d</string>
<string name="home_unsupported">Desteklenmiyor</string>
<string name="home_unsupported_reason">KernelSU artık yalnızca GKI çekirdeklerini destekliyor</string>
<string name="home_copied_to_clipboard">Panoya kopyalandı</string>
<string name="home_support">Destek</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Arch</string>
<string name="home_manager_version">Yönetici Sürümü</string>
<string name="home_api">API Seviyesi</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Parmak izi</string>
<string name="home_securitypatch">Güvenlik Yaması</string>
<string name="home_selinux_status">SELinux durumu</string>
<string name="selinux_status_disabled">Devre dışı</string>
<string name="selinux_status_enforcing">Zorunlu</string>
<string name="selinux_status_permissive">Serbest</string>
<string name="selinux_status_unknown">Bilinmiyor</string>
<string name="superuser">Süper kullanıcı</string>
<string name="superuser_failed_to_grant_root">%d için root erişimi verilemedi</string>
<string name="superuser_allow_root_confirm">%s için root erişimi vereceğinizden emin misiniz?</string>
<string name="module_failed_to_enable">Modül etkinleştirilemedi: %s</string>
<string name="module_failed_to_disable">Modül devre dışı bırakılamadı: %s</string>
<string name="module_empty">Yüklü modül yok</string>
<string name="module">Modül</string>
<string name="uninstall">Kaldır</string>
<string name="module_install">Yükle</string>
<string name="install">Yükle</string>
<string name="reboot">Yeniden başlat</string>
<string name="settings">Ayarlar</string>
<string name="reboot_userspace">Hızlı yeniden Başlat</string>
<string name="reboot_recovery">Kurtarma modunda Başlat</string>
<string name="reboot_bootloader">Bootloader modunda Başlat</string>
<string name="reboot_download">İndirme modunda Başlat</string>
<string name="reboot_edl">EDL modunda Başlat</string>
<string name="about">Hakkında</string>
<string name="require_kernel_version_8">KernelSU sürüm 8+ gerektir</string>
<string name="module_uninstall_confirm">%s modülünü kaldırmak istediğinizden emin misiniz?</string>
<string name="module_uninstall_success">%s kaldırıldı</string>
<string name="module_uninstall_failed">Kaldırılamadı: %s</string>
<string name="module_version">Sürüm</string>
<string name="module_author">Yazar</string>
<string name="module_overlay_fs_not_available">overlayfs mevcut değil, modül çalışamıyor!</string>
<string name="refresh">Yenile</string>
<string name="show_system_apps">Sistem uygulamalarını göster</string>
<string name="hide_system_apps">Sistem uygulamalarını gizle</string>
<string name="send_log">Log gönder</string>
<string name="safe_mode">Güvenli mod</string>
<string name="reboot_to_apply">Etkili olması için yeniden başlat</string>
<string name="module_magisk_conflict">Modüller Magisk ile çakıştığı için devre dışı bırakıldı!</string>
<string name="home_learn_kernelsu">KernelSU\'yu Öğrenin</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">KernelSU\'yu nasıl kuracağınızı ve modülleri nasıl kullanacağınızı öğrenin</string>
<string name="home_support_title">Bizi destekle</string>
<string name="home_support_content">KernelSU ücretsiz ve açık kaynaktır ve her zaman öyle kalacaktır. Ancak bağış yaparak bize değer verdiğinizi gösterebilirsiniz.</string>
<string name="about_source_code"><![CDATA[%1$s kaynak kodunu görüntüle<br/>%2$s kanalımıza katılın]]></string>
</resources>

View File

@@ -0,0 +1,66 @@
<resources>
<string name="home">Головна</string>
<string name="home_not_installed">Не встановлено</string>
<string name="home_click_to_install">Натисніть щоб встановити</string>
<string name="home_working">Працює</string>
<string name="home_working_version">Версія: %d</string>
<string name="home_superuser_count">Суперкористувачі: %d</string>
<string name="home_module_count">Модулі: %d</string>
<string name="home_unsupported">Не підтримується</string>
<string name="home_unsupported_reason">KernelSU підтримує лише ядра GKI</string>
<string name="home_copied_to_clipboard">Скопійовано в буфер обміну</string>
<string name="home_support">Підтримка</string>
<string name="home_kernel">Ядро</string>
<string name="home_arch">Архітектура</string>
<string name="home_manager_version">Версія менеджера</string>
<string name="home_api">Рівень API</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Відбиток</string>
<string name="home_securitypatch">Патч безпеки</string>
<string name="home_selinux_status">Статус SELinux</string>
<string name="selinux_status_disabled">Вимкнено</string>
<string name="selinux_status_enforcing">Примусовий</string>
<string name="selinux_status_permissive">Дозвільний</string>
<string name="selinux_status_unknown">Невідомо</string>
<string name="superuser">Суперкористувачі</string>
<string name="superuser_failed_to_grant_root">Не вдалося надати root-доступ для %d</string>
<string name="superuser_allow_root_confirm">Ви впевнені, що хочете надати root-доступ для %s?</string>
<string name="module_failed_to_enable">Не вдалося ввімкнути модуль: %s</string>
<string name="module_failed_to_disable">Не вдалося вимкнути модуль: %s</string>
<string name="module_empty">Немає встановлених модулів</string>
<string name="module">Модулі</string>
<string name="uninstall">Видалити</string>
<string name="module_install">Встановити</string>
<string name="install">Встановити</string>
<string name="reboot">Перезавантажити</string>
<string name="settings">Налаштування</string>
<string name="reboot_userspace">М\'яке перезавантаження</string>
<string name="reboot_recovery">Перезавантажити до Recovery</string>
<string name="reboot_bootloader">Перезавантажити до Bootloader</string>
<string name="reboot_download">Перезавантажити до Download</string>
<string name="reboot_edl">Перезавантажити до EDL</string>
<string name="about">Про додаток</string>
<string name="require_kernel_version_8">Потрібна версія KernelSU 8+</string>
<string name="module_uninstall_confirm">Ви впевнені, що хочете видалити модуль %s?</string>
<string name="module_uninstall_success">%s видалено</string>
<string name="module_uninstall_failed">Не вдалося видалити: %s</string>
<string name="module_version">Версія</string>
<string name="module_author">Автор</string>
<string name="module_overlay_fs_not_available">overlayfs не доступний, модуль не може працювати!</string>
<string name="refresh">Оновити</string>
<string name="show_system_apps">Показати системні додатки</string>
<string name="hide_system_apps">Сховати системні додатки</string>
<string name="send_log">Надіслати лог</string>
<string name="safe_mode">Безпечний режим</string>
<string name="reboot_to_apply">Перезавантажте, щоб застосувати</string>
<string name="module_magisk_conflict">Модулі вимкнено, оскільки вони конфліктують із модулями Magisk!</string>
<string name="home_learn_kernelsu">Дізнайтеся про KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Дізнайтеся, як інсталювати KernelSU і використовувати модулі</string>
<string name="home_support_title">Підтримайте нас</string>
<string name="home_support_content">KernelSU є і завжди буде безкоштовним і з відкритим кодом. Однак Ви можете показати нам, що Вам не байдуже, зробивши пожертву.</string>
<string name="about_source_code"><![CDATA[Переглянути вихідний код на %1$s<br/>Приєднуйтесь до нашого каналу %2$s]]></string>
</resources>

View File

@@ -57,4 +57,5 @@
<string name="hide_system_apps">Ẩn ứng dụng hệ thống</string>
<string name="safe_mode">Chế độ an toàn</string>
<string name="reboot_to_apply">Khởi động lại để có hiệu lực</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/vi_VN/guide/what-is-kernelsu.html</string>
</resources>

View File

@@ -56,6 +56,7 @@
<string name="module_magisk_conflict">所有模块已被禁用,因为它与 Magisk 的模块系统有冲突!</string>
<string name="home_module_count">模块数:%d</string>
<string name="home_learn_kernelsu">了解 KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/zh_CN/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">了解如何安装 KernelSU 以及如何开发模块</string>
<string name="home_support_title">支持开发</string>
<string name="home_support_content">KernelSU 将保持免费和开源,向开发者捐赠以表示支持。</string>

View File

@@ -5,6 +5,8 @@
<string name="home_click_to_install">按一下以安裝</string>
<string name="home_working">正在處理</string>
<string name="home_working_version">版本:%d</string>
<string name="home_superuser_count">超級使用者:%d 個</string>
<string name="home_module_count">模組:%d 個</string>
<string name="home_unsupported">不支援</string>
<string name="home_unsupported_reason">KernelSU 現在僅支援 GKI 核心</string>
<string name="home_copied_to_clipboard">已複製到剪貼簿</string>
@@ -24,8 +26,8 @@
<string name="selinux_status_permissive">寬鬆</string>
<string name="selinux_status_unknown">未知</string>
<string name="superuser">超級使用者</string>
<string name="superuser_failed_to_grant_root">無法為 %d 授予 Root 存取權</string>
<string name="superuser_allow_root_confirm">您確定要授予 %s Root 存取權嗎?</string>
<string name="superuser_failed_to_grant_root">無法為%d授予 Root 存取權</string>
<string name="superuser_allow_root_confirm">您確定要授予%sRoot 存取權嗎?</string>
<string name="module_failed_to_enable">無法啟用模組:%s</string>
<string name="module_failed_to_disable">無法停用模組:%s</string>
<string name="module_empty">尚未安裝模組</string>
@@ -43,8 +45,8 @@
<string name="reboot_edl">重新啟動至 EDL</string>
<string name="about">關於</string>
<string name="require_kernel_version_8">需要 KernelSU 8+ 版本</string>
<string name="module_uninstall_confirm">您確定要解除安裝模組 %s 嗎?</string>
<string name="module_uninstall_success">%s 已解除安裝</string>
<string name="module_uninstall_confirm">您確定要解除安裝模組%s嗎?</string>
<string name="module_uninstall_success">%s已解除安裝</string>
<string name="module_uninstall_failed">無法解除安裝:%s</string>
<string name="module_version">版本</string>
<string name="module_author">作者</string>
@@ -56,4 +58,10 @@
<string name="safe_mode">安全模式</string>
<string name="reboot_to_apply">重新啟動以生效</string>
<string name="module_magisk_conflict">模組已停用,因其與 Magisk 的模組存在衝突!</string>
<string name="home_learn_kernelsu">深入瞭解 KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">瞭解如何安裝 KernelSU 和使用模組</string>
<string name="home_support_title">支持我們</string>
<string name="home_support_content">KernelSU 是免費且開源的,您可以透過捐贈來向我們展示您對我們的關心。</string>
<string name="about_source_code"><![CDATA[在 %1$s 中檢視原始碼<br/>加入我們的 %2$s 頻道]]></string>
</resources>

View File

@@ -5,8 +5,8 @@
<string name="home_click_to_install">按一下以安裝</string>
<string name="home_working">正在處理</string>
<string name="home_working_version">版本:%d</string>
<string name="home_superuser_count">已 Root 授權%d 個</string>
<string name="home_module_count">已安裝模組: %d 個</string>
<string name="home_superuser_count">超級使用者%d 個</string>
<string name="home_module_count">模組:%d 個</string>
<string name="home_unsupported">不支援</string>
<string name="home_unsupported_reason">KernelSU 現在僅支援 GKI 核心</string>
<string name="home_copied_to_clipboard">已複製到剪貼簿</string>
@@ -26,8 +26,8 @@
<string name="selinux_status_permissive">寬鬆</string>
<string name="selinux_status_unknown">未知</string>
<string name="superuser">超級使用者</string>
<string name="superuser_failed_to_grant_root">無法為「%d」授予 Root 權</string>
<string name="superuser_allow_root_confirm">您確定要授予「%s」Root 權嗎?</string>
<string name="superuser_failed_to_grant_root">無法為「%d」授予 Root 存取</string>
<string name="superuser_allow_root_confirm">您確定要授予「%s」Root 存取權嗎?</string>
<string name="module_failed_to_enable">無法啟用模組:%s</string>
<string name="module_failed_to_disable">無法停用模組:%s</string>
<string name="module_empty">尚未安裝模組</string>
@@ -54,13 +54,14 @@
<string name="refresh">重新整理</string>
<string name="show_system_apps">顯示系統應用程式</string>
<string name="hide_system_apps">隱藏系統應用程式</string>
<string name="send_log">傳送日誌</string>
<string name="send_log">傳送記錄</string>
<string name="safe_mode">安全模式</string>
<string name="reboot_to_apply">重新啟動以生效</string>
<string name="module_magisk_conflict">模組已停用,因其與 Magisk 的模組存在衝突!</string>
<string name="home_learn_kernelsu">瞭解 KernelSU</string>
<string name="home_learn_kernelsu">深入瞭解 KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">瞭解如何安裝 KernelSU 以及如何開發模組</string>
<string name="home_support_title">開發</string>
<string name="home_support_content">KernelSU 將保持免費和開源,您可以慮向開發捐贈以表示支</string>
<string name="about_source_code"><![CDATA[在 %1$s 檢視原始碼<br/>加入我們的 %2$s 頻道<br/>]]></string>
<string name="home_support_title">開發</string>
<string name="home_support_content">KernelSU 將保持免費和開源,您可以慮向開發人員捐贈以表示支</string>
<string name="about_source_code"><![CDATA[在 %1$s 檢視原始碼<br/>加入我們的 %2$s 頻道]]></string>
</resources>

View File

@@ -60,6 +60,7 @@
<string name="reboot_to_apply">Reboot to take effect</string>
<string name="module_magisk_conflict">Modules are disabled because it is conflict with Magisk\'s!</string>
<string name="home_learn_kernelsu">Learn KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Learn how to install KernelSU and use modules</string>
<string name="home_support_title">Support Us</string>
<string name="home_support_content">KernelSU is, and always will be, free, and open source. You can however show us that you care by making a donation.</string>

View File

@@ -1,17 +0,0 @@
package me.weishu.kernelsu
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

View File

@@ -1,33 +1,46 @@
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.gradle.BaseExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.konan.properties.Properties
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 {
id("com.android.application") apply false
id("com.android.library") apply false
kotlin("android") apply false
alias(libs.plugins.agp.app) apply false
alias(libs.plugins.agp.lib) apply false
alias(libs.plugins.kotlin) apply false
alias(libs.plugins.lsplugin.cmaker)
}
buildscript {
repositories {
google()
mavenCentral()
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")
}
dependencies {
classpath(kotlin("gradle-plugin", version = "1.7.20"))
buildTypes {
if (it.name == "release") {
arguments += "-DDEBUG_SYMBOLS_PATH=${buildDir.absolutePath}/symbols"
}
}
}
val androidMinSdk = 26
val androidTargetSdk = 33
val androidCompileSdk = 33
val androidBuildToolsVersion = "33.0.1"
val androidSourceCompatibility = JavaVersion.VERSION_11
val androidTargetCompatibility = JavaVersion.VERSION_11
val managerVersionCode = getVersionCode()
val managerVersionName = getVersionName()
val androidMinSdkVersion = 26
val androidTargetSdkVersion = 33
val androidCompileSdkVersion = 33
val androidBuildToolsVersion = "33.0.2"
val androidCompileNdkVersion = "25.2.9519653"
val androidSourceCompatibility = JavaVersion.VERSION_17
val androidTargetCompatibility = JavaVersion.VERSION_17
val managerVersionCode by extra(getVersionCode())
val managerVersionName by extra(getVersionName())
tasks.register<Delete>("clean") {
delete(rootProject.buildDir)
@@ -61,71 +74,31 @@ fun getVersionName(): String {
return getGitDescribe()
}
fun Project.configureBaseExtension() {
extensions.findByType<BaseExtension>()?.run {
compileSdkVersion(androidCompileSdk)
buildToolsVersion = androidBuildToolsVersion
subprojects {
plugins.withType(AndroidBasePlugin::class.java) {
extensions.configure(CommonExtension::class.java) {
compileSdk = androidCompileSdkVersion
ndkVersion = androidCompileNdkVersion
buildToolsVersion = androidBuildToolsVersion
defaultConfig {
minSdk = androidMinSdk
targetSdk = androidTargetSdk
versionCode = managerVersionCode
versionName = managerVersionName
consumerProguardFiles("proguard-rules.pro")
}
val signFile = rootProject.file("sign.properties")
val config = if (signFile.canRead()) {
val prop = Properties()
prop.load(signFile.inputStream())
signingConfigs.create("config") {
storeFile = file(prop.getProperty("KEYSTORE_FILE"))
storePassword = prop.getProperty("KEYSTORE_PASSWORD")
keyAlias = prop.getProperty("KEY_ALIAS")
keyPassword = prop.getProperty("KEY_PASSWORD")
}
} else {
signingConfigs["debug"]
}
buildTypes {
all {
signingConfig = config
}
named("release") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = androidSourceCompatibility
targetCompatibility = androidTargetCompatibility
}
extensions.findByType<ApplicationExtension>()?.run {
buildTypes {
named("release") {
isShrinkResources = true
defaultConfig {
minSdk = androidMinSdkVersion
if (this is ApplicationDefaultConfig) {
targetSdk = androidTargetSdkVersion
versionCode = managerVersionCode
versionName = managerVersionName
}
}
}
extensions.findByType<KotlinCompile>()?.run {
kotlinOptions {
jvmTarget = "11"
lint {
abortOnError = true
checkReleaseBuilds = false
}
compileOptions {
sourceCompatibility = androidSourceCompatibility
targetCompatibility = androidTargetCompatibility
}
}
}
}
subprojects {
plugins.withId("com.android.application") {
configureBaseExtension()
}
plugins.withId("com.android.library") {
configureBaseExtension()
}
}

View File

@@ -1,23 +1,3 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.experimental.enableNewResourceShrinker.preciseShrinking=true
android.enableAppCompileTimeRClass=true
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

View File

@@ -0,0 +1,55 @@
[versions]
agp = "8.0.0"
kotlin = "1.8.10"
ksp = "1.8.10-1.0.9"
compose-bom = "2023.04.01"
lifecycle = "2.6.1"
accompanist = "0.30.0"
navigation = "2.5.3"
compose-destination = "1.9.40-beta"
libsu = "5.0.5"
[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" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
lsplugin-apksign = { id = "org.lsposed.lsplugin.apksign", version = "1.1" }
lsplugin-cmaker = { id = "org.lsposed.lsplugin.cmaker", version = "1.1" }
[libraries]
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version = "1.7.1" }
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 = "lifecycle" }
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-github-alorma-compose-settings-ui-m3 = { module = "com.github.alorma:compose-settings-ui-m3", version = "0.22.0" }
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" }
dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:parcelablelist", version = "2.0.1" }
io-coil-kt-coil-compose = { group = "io.coil-kt", name = "coil-compose", version = "2.3.0" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.6.4" }
me-zhanghai-android-appiconloader-coil = { group = "me.zhanghai.android.appiconloader", name = "appiconloader-coil", version = "1.5.0" }
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" }

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

@@ -6,14 +6,6 @@ pluginManagement {
google()
mavenCentral()
}
plugins {
val agp = "7.4.2"
val kotlin = "1.7.20"
id("com.android.application") version agp
id("com.android.library") version agp
id("com.google.devtools.ksp") version "$kotlin-1.0.8"
kotlin("android") version kotlin
}
}
dependencyResolutionManagement {

View File

@@ -278,7 +278,9 @@ mark_remove() {
}
mark_replace() {
mkdir -p ${1%/*} 2>/dev/null
# REPLACE must be directory!!!
# https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories
mkdir -p $1 2>/dev/null
setfattr -n trusted.overlay.opaque -v y $1
chmod 644 $1
}

View File

@@ -149,6 +149,7 @@ fn mount_overlayfs(
Mount::builder()
.fstype(FilesystemType::from("overlay"))
.data(&options)
.flags(MountFlags::RDONLY)
.mount(KSU_OVERLAY_SOURCE, dest.as_ref())
.with_context(|| {
format!(

View File

@@ -1,6 +1,7 @@
import { defineConfig } from 'vitepress'
import en from './en'
import zh_CN from './zh_CN'
import zh_TW from './zh_TW'
import vi_VN from './vi_VN'
import id_ID from './id_ID'
@@ -18,6 +19,12 @@ export default defineConfig({
themeConfig: zh_CN.themeConfig,
description: zh_CN.description
},
zh_TW: {
label: '繁體中文',
lang: zh_TW.lang,
themeConfig: zh_TW.themeConfig,
description: zh_TW.description
},
vi_VN: {
label: 'Tiếng Việt',
lang: vi_VN.lang,

View File

@@ -0,0 +1,60 @@
import { createRequire } from 'module'
import { defineConfig } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export default defineConfig({
lang: 'zh-TW',
description: '一個以核心為基礎,適用於 Android GKI 的 Root 解決方案。',
themeConfig: {
nav: nav(),
lastUpdatedText: '上次更新',
sidebar: {
'/zh_TW/guide/': sidebarGuide()
},
socialLinks: [
{ icon: 'github', link: 'https://github.com/tiann/KernelSU' }
],
footer: {
message: '係依據 GPL3 授權發行。',
copyright: 'Copyright © 2022-目前 KernelSU 開發人員'
},
editLink: {
pattern: 'https://github.com/tiann/KernelSU/edit/main/website/docs/:path',
text: '在 GitHub 中編輯本頁面'
}
}
})
function nav() {
return [
{ text: '指南', link: '/zh_TW/guide/what-is-kernelsu' },
{ text: 'Github', link: 'https://github.com/tiann/KernelSU' }
]
}
function sidebarGuide() {
return [
{
text: 'Guide',
items: [
{ text: '什麼是 KernelSU', link: '/zh_TW/guide/what-is-kernelsu' },
{ text: '安裝', link: '/zh_TW/guide/installation' },
{ text: '如何建置?', link: '/zh_TW/guide/how-to-build' },
{ text: '如何為非 GKI 核心整合 KernelSU', link: '/zh_TW/guide/how-to-integrate-for-non-gki'},
{ text: '非官方支援裝置', link: '/zh_TW/guide/unofficially-support-devices.md' },
{ text: '模組指南', link: '/zh_TW/guide/module.md' },
{ text: '搶救開機迴圈', link: '/zh_TW/guide/rescue-from-bootloop.md' },
{ text: '常見問題', link: '/zh_TW/guide/faq' },
{ text: '隱藏功能', link: '/zh_TW/guide/hidden-features' },
]
}
]
}

View File

@@ -1,4 +1,18 @@
[
{
"maintainer": "diphons",
"maintainer_link": "https://github.com/diphons",
"kernel_name": "D8G_Kernel_oxygen",
"kernel_link": "https://github.com/diphons/D8G_Kernel_oxygen/tree/13",
"devices": "Poco F3: alioth | Poco F4: munch | MI10T/PRO: Apollo"
},
{
"maintainer": "diphons",
"maintainer_link": "https://github.com/diphons",
"kernel_name": "D8G_Kernel_ROG",
"kernel_link": "https://github.com/diphons/D8G_Kernel_Vayuasu/tree/main",
"devices": "Poco X3 Pro: Vayu | Bhima"
},
{
"maintainer": "SpectreDev-007",
"maintainer_link": "https://github.com/SpectreDev-007",
@@ -97,6 +111,13 @@
"kernel_link": "https://github.com/lateautumn233/android_kernel_oneplus_sm8250",
"devices": "OnePlus 8 Serials"
},
{
"maintainer": "Sreeshankar K",
"maintainer_link": "https://github.com/Sanju0910",
"kernel_name": "android_kernel_oneplus_avicii",
"kernel_link": "https://github.com/Sanju0910/android_kernel_oneplus_avicii",
"devices": "OnePlus Nord (avicii)"
},
{
"maintainer": "Molyuu",
"maintainer_link": "https://github.com/Molyuu",
@@ -188,13 +209,6 @@
"kernel_link": "https://github.com/RooGhz720/kernel_asus_X01BD",
"devices": "Asus Zenfone Max Pro M1/M2"
},
{
"maintainer": "TheNoFace",
"maintainer_link": "https://github.com/TheNoFace",
"kernel_name": "kernel_oneplus_msm8998",
"kernel_link": "https://github.com/TheNoFace/kernel_oneplus_msm8998",
"devices": "OnePlus 5/5T"
},
{
"maintainer": "Evans Mike",
"maintainer_link": "https://github.com/etnperlong",
@@ -215,5 +229,75 @@
"kernel_name": "kernel_xiaomi_sdm660",
"kernel_link": "https://github.com/tedomi2705/kernel_xiaomi_sdm660",
"devices": "Xiaomi Redmi Note 6 Pro (tulip)"
},
{
"maintainer": "RyuujiX",
"maintainer_link": "https://github.com/RyuujiX",
"kernel_name": "android_kernel_asus_sdm660-4.19",
"kernel_link": "https://github.com/RyuujiX/android_kernel_asus_sdm660-4.19",
"devices": "Asus Zenfone Max Pro M1 (X00TD)/ M2 (X01BD) (Linux 4.19)"
},
{
"maintainer": "liqidecg",
"maintainer_link": "https://github.com/liqidecg",
"kernel_name": "android_kernel_xiaomi_sdm710",
"kernel_link": "https://github.com/liqidecg/android_kernel_xiaomi_sdm710",
"devices": "Mi 8 SE (sirius) (Linux 4.9)"
},
{
"maintainer": "Abdelhay-Ali",
"maintainer_link": "https://github.com/Abdelhay-Ali",
"kernel_name": "android_kernel_huawei_hi6250",
"kernel_link": "https://github.com/Abdelhay-Ali/android_kernel_huawei_hi6250_KernelSU",
"devices": "Huawei P20 lite (hi6250) (Linux 4.9)"
},
{
"maintainer": "reocat",
"maintainer_link": "https://github.com/reocat",
"kernel_name": "android_kernel_nokia_sdm660_ksu",
"kernel_link": "https://github.com/reocat/android_kernel_nokia_sdm660_ksu",
"devices": "Nokia 6.1 (2018)"
},
{
"maintainer": "bggRGjQaUbCoE",
"maintainer_link": "https://github.com/bggRGjQaUbCoE",
"kernel_name": "android_kernel_samsung_sm8250",
"kernel_link": "https://github.com/bggRGjQaUbCoE/android_kernel_samsung_sm8250",
"devices": "Samsung Galaxy S20+ 5G (y2q)"
},
{
"maintainer": "SOVIET-ANDROID",
"maintainer_link": "https://github.com/SOVIET-ANDROID",
"kernel_name": "kernel_xiaomi_raphael",
"kernel_link": "https://github.com/SOVIET-ANDROID/kernel_xiaomi_raphael",
"devices": "XK20 Pro Raphael DSP & A only SAR support "
},
{
"maintainer": "AkariOficial",
"maintainer_link": "https://github.com/AkariOficial",
"kernel_name": "kernel_Moe_ginkgo",
"kernel_link": "https://github.com/AkariOficial/kernel_Moe_ginkgo",
"devices": "Xiaomi Redmi Note 8 (Ginkgo)"
},
{
"maintainer": "Coconutat",
"maintainer_link": "https://github.com/Coconutat",
"kernel_name": "android_kernel_huawei_vtr_emui9_KernelSU",
"kernel_link": "https://github.com/Coconutat/android_kernel_huawei_vtr_emui9_KernelSU",
"devices": "Huawei P10,P10 Plus,Mate9,Mate9 Pro(Kirin960 Series),Stable For GSI"
},
{
"maintainer": "dabao1955",
"maintainer_link": "https://github.com/dabao1955",
"kernel_name": "android_kernel_OPPO_PEQM00",
"kernel_link": "https://github.com/dabao1955/android_kernel_OPPO_PEQM00",
"devices": "MediaTek devices in the OPPO Reno series on ColorOS13.x"
},
{
"maintainer": "Aflaungos",
"maintainer_link": "https://github.com/Aflaungos",
"kernel_name": "android_kernel_motorola_msm8998",
"kernel_link": "https://github.com/Aflaungos/android_kernel_motorola_msm8998",
"devices": "Moto G6 Plus (evert)"
}
]

View File

@@ -8,7 +8,7 @@
- 模块安装目录: 都在 `/data/adb/modules`
- systemless: 都支持通过模块的形式以 systemless 修改 /system
- `post-fs-data.sh`: 执行时机完全一致,语义也完全一致
- `service.sh`: 执行世纪完全一致,语义也完全一致
- `service.sh`: 执行时机完全一致,语义也完全一致
- `system.prop`: 完全相同
- `sepolicy.rule`: 完全相同
- BusyBox脚本都在 BusyBox 中以“独立模式”运行

View File

@@ -0,0 +1,26 @@
# KernelSU 模組與 Magisk 的差異 {#title}
儘管 KernelSU 模組和 Magisk 模組之間有許多相似之處,但由於它們完全不同的實作機制,不可避免地存在一些差異;如果您想讓您的模組同時在 Magisk 和 KernelSU 上運作,那麼您必須瞭解這些差異。
## 相同之處 {#similarities}
- 模組檔案格式:都以 Zip 的格式組織模組,並且模組的格式幾乎相同
- 模組安裝目錄:都位於 `/data/adb/modules`
- Systemless都支援透過模組的形式以 systemless 修改 /system
- `post-fs-data.sh`:執行時間和語義完全相同
- `service.sh`:執行時間和語義完全相同
- `system.prop`:完全相同
- `sepolicy.rule`:完全相同
- BusyBox指令碼在 BusyBox 中以「獨立模式」執行
## 不同之處 {#differences}
在瞭解不同之處之前,您需要知道如何區分您的模組是在 KernelSU 還是 Magisk 中執行;在所有可以執行模組指令碼的位置 (`customize.sh`, `post-fs-data.sh`, `service.sh`),您都可以使用環境變數 `KSU` 來區分,在 KernelSU 中,這個環境變數將被設定為 `true`
以下是一些不同之處:
1. KernelSU 的模組不支援在 Recovery 中安裝。
2. KernelSU 的模組沒有內建的 Zygisk 支援 (但您可以透過 [ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) 來使用 Zygisk 模組)。
3. KernelSU 模組取代或刪除檔案與 Magisk 完全不同。KernelSU 不支援 `.replace` 方法,相反,您需要透過 `mknod filename c 0 0` 建立相同名稱的資料夾以刪除對應檔案。
4. BusyBox 的目錄不同KernelSU 內建的 BusyBox 在 `/data/adb/ksu/bin/busybox` 而 Magisk 在 `/data/adb/magisk/busybox`**注意此為 KernelSU 內部行為,未來可能會變更!**
5. KernelSU 不支援 `.replace` 檔案;但 KernelSU 支援 `REPLACE``REMOVE` 變數以移除或取代檔案 (資料夾)。

View File

@@ -0,0 +1,67 @@
# 常見問題
## KernelSU 是否支援我的裝置?
首先,您的裝置應該能解鎖 Bootloader。如果不能則不支援。
然後在您的裝置上安裝 KernelSU 管理員並開啟它,如果它顯示 `不支援`,那麼您的裝置沒有官方支援的開箱即用的 Boot 映像;但您可以自行建置核心來源並整合 KernelSU 以繼續使用。
## KernelSU 是否需要解鎖 Bootloader
當然需要。
## KernelSU 是否支援模組?
支援,但它是早期版本,可能存在問題。請等候它逐漸穩定 :)
## KernelSU 是否支援 Xposed
支援。[Dreamland](https://github.com/canyie/Dreamland) 和 [TaiChi](https://taichi.cool) 可以正常運作。LSPosed 可以在 [Zygisk on KernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) 的支援下正常運作。
## KernelSU 支援 Zygisk 嗎?
KernelSU 沒有內建 Zygisk 支援,但是您可以用 [Zygisk on KernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) 來使用 Zygisk 模組。
## KernelSU 與 Magisk 相容嗎?
KernelSU 的模組系統與 Magisk 的 magic mount 存在衝突,如果在 KernelSU 中啟用了任何模組,那麼整個 Magisk 將無法正常運作。
但是如果您只使用 KernelSU 的 `su`,那么它會和 Magisk 一同運作KernelSU 修改 `kernel` 、 Magisk 修改 `ramdisk`,它們可以搭配使用。
## KernelSU 会取代 Magisk 嗎?
我們不這樣認為這也不是我們的目標。Magisk 對於使用者空間 Root 解決方案來說已經足夠優秀了它會存在很長一段時間。KernelSU 的目標是為使用者提供核心介面,而非取代 Magisk。
## KernelSU 可以支援非 GKI 裝置嗎?
可以。但是您應該下載核心來源並整合 KernelSU 至來源樹狀結構並自行編譯核心。
## KernelSU 支援 Android 12 以下的裝置嗎?
影響 KernelSU 相容性的是裝置的核心版本,它與 Android 版本並無直接關係。唯一有關聯的是:**原廠** Android 12 的裝置,一定是 5.10 或更高的核心 (GKI 裝置);因此結論如下:
1. 原廠 Android 12 的裝置必定支援 (GKI 裝置)
2. 舊版核心的裝置 (即使是 Android 12也可能是舊版核心) 是相容的 (您需要自行建置核心)
## KernelSU 可以支援舊版核心嗎?
可以,目前最低支援到 4.14;更低的版本您需要手動移植它,歡迎 PR
## 如何為舊版核心整合 KernelSU
請參閱[指南](how-to-integrate-for-non-gki)
## 為何我的 Android 版本為 13但核心版本卻是 "android12-5.10"
核心版本與 Android 版本無關,如果您要刷新 KernelSU請一律使用**核心版本**而非 Android 版本,如果你為 "android12-5.10" 的裝置刷新 Android 13 的核心,等候您的將會是開機迴圈。
## KernelSU 支援 --mount-master/全域掛接命名空間嗎?
目前沒有 (未來可能會支援),但實際上有很多種方法手動進入全域命名空間,無需 Su 內建支援,比如:
1. `nsenter -t 1 -m sh` 可以取得一個全域 mount namespace 的 shell.
2. 在您要執行的命令前新增 `nsenter --mount=/proc/1/ns/mnt` 即可使此命令在全域 mount namespace 下執行。KernelSU 本身也使用了 [這種方法](https://github.com/tiann/KernelSU/blob/77056a710073d7a5f7ee38f9e77c9fd0b3256576/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt#L115)
## 我是 GKI1.0,能用 KernelSU 嗎?
GKI1 與 GKI2 完全不同,所以您需要自行編譯核心。

View File

@@ -0,0 +1,7 @@
# 隱藏功能
## ksurc
預設狀況下,`/system/bin/sh` 會載入 `/system/etc/mkshrc`
可以透過建立 `/data/adb/ksu/.ksurc` 檔案來讓 Su 載入此檔案而非 `/system/etc/mkshrc`

View File

@@ -0,0 +1,65 @@
# 如何建置 KernelSU?
首先,您需要閱讀核心建置的 Android 官方文件:
1. [建置核心](https://source.android.com/docs/setup/build/building-kernels)
2. [標準核心映像 (GKI) 發行組建](https://source.android.com/docs/core/architecture/kernel/gki-release-builds)
::: warning
此文件適用於 GKI 裝置,如果您是舊版核心,請參閱[如何為非 GKI 裝置整合 KernelSU](how-to-integrate-for-non-gki)
:::
## 建置核心
### 同步核心原始碼
```sh
repo init -u https://android.googlesource.com/kernel/manifest
mv <kernel_manifest.xml> .repo/manifests
repo init -m manifest.xml
repo sync
```
`<kernel_manifest.xml>` 是一個可以唯一確定組建的資訊清單檔案,您可以使用這個資訊清單進行可重新預測的組建。您需要從[標準核心映像 (GKI) 發行組建](https://source.android.com/docs/core/architecture/kernel/gki-release-builds) 下載資訊清單檔案
### 建置
請先查看[官方文件](https://source.android.com/docs/setup/build/building-kernels)。
例如,我們需要建置 aarch64 核心映像:
```sh
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
```
不要忘記新增 `LTO=thin`,否則,如果您的電腦記憶體小於 24GB建置可能會失敗。
從 Android 13 開始,核心由 `bazel` 建置:
```sh
tools/bazel build --config=fast //common:kernel_aarch64_dist
```
## 使用 KernelSU 建置核心
如果您可以成功建置核心,那麼建置 KernelSU 就會非常輕鬆,依自己的需求在核心原始碼根目錄中執行以下任一命令:
- 最新 tag (穩定版本)
```sh
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
```
- main 分支 (開發版本)
```sh
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
```
- 選取 tag (例如 v0.5.2)
```sh
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
```
然後重新建置核心,您將會得到一個帶有 KernelSU 的核心映像!

View File

@@ -0,0 +1,240 @@
# 如何為非 GKI 核心整合 KernelSU {#introduction}
KernelSU 可以被整合到非 GKI 核心中,現在它最低支援到核心 4.14 版本;理論上也可以支援更低的版本。
由於非 GKI 核心的片段化極其嚴重,因此通常沒有統一的方法來建置它,所以我們也無法為非 GKI 裝置提供 Boot 映像。但您完全可以自行整合 KernelSU 並建置核心以繼續使用。
首先,您必須有能力從您裝置的核心原始碼建置出一個可以開機並且能夠正常使用的核心,如果核心並非開放原始碼,這通常難以做到。
如果您已經做好了上述準備,那有兩個方法來將 KernelSU 整合至您的核心之中。
1. 藉助 `kprobe` 自動整合
2. 手動修改核心原始碼
## 使用 kprobe 整合 {#using-kprobes}
KernelSU 使用 kprobe 機制來處理核心的相關 hook如果 *kprobe* 可以在您建置的核心中正常運作,那麼建議使用這個方法進行整合。
首先,把 KernelSU 新增至您的核心來源樹狀結構,再核心的根目錄執行以下命令:
- 最新 tag (稳定版本)
```sh
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
```
- main 分支(開發版本)
```sh
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
```
- 選取 tag (例如 v0.5.2)
```sh
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
```
然後,您需要檢查您的核心是否啟用 *kprobe* 相關組態,如果未啟用,則需要新增以下組態:
```
CONFIG_KPROBES=y
CONFIG_HAVE_KPROBES=y
CONFIG_KPROBE_EVENTS=y
```
最後,重新建置您的核心即可。
如果您發現 KPROBES 仍未生效,很有可能是因為它的相依性 `CONFIG_MODULES` 並未被啟用 (如果還是未生效請輸入 `make menuconfig` 搜尋 KPROBES 的其他相依性並啟用)
如果您在整合 KernelSU 之後手機無法啟動,那麼很可能您的核心中 **kprobe 無法正常運作**,您需要修正這個錯誤,或者使用第二種方法。
:::tip 如何檢查 kprobe 是否損毀?
`KernelSU/kernel/ksu.c` 中的 `ksu_enable_sucompat()``ksu_enable_ksud()` 取消註解,如果正常開機,即 kprobe 已損毀;或者您可以手動嘗試使用 kprobe 功能,如果不正常,手機會直接重新啟動。
:::
## 手動修改核心原始碼 {#modify-kernel-source-code}
如果 kprobe 無法正常運作 (可能是上游的錯誤或核心版本過低),那您可以嘗試這種方法:
首先,將 KernelSU 新增至您的原始碼樹狀結構,再核心的根目錄執行以下命令:
```sh
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
```
然後,手動修改核心原始碼,您可以參閱下方的 patch
```diff
diff --git a/fs/exec.c b/fs/exec.c
index ac59664eaecf..bdd585e1d2cc 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1890,11 +1890,14 @@ static int __do_execve_file(int fd, struct filename *filename,
return retval;
}
+extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
+ void *envp, int *flags);
static int do_execveat_common(int fd, struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags)
{
+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags);
return __do_execve_file(fd, filename, argv, envp, flags, NULL);
}
diff --git a/fs/open.c b/fs/open.c
index 05036d819197..965b84d486b8 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -348,6 +348,8 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
return ksys_fallocate(fd, mode, offset, len);
}
+extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
+ int *flags);
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and
@@ -355,6 +357,7 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
*/
long do_faccessat(int dfd, const char __user *filename, int mode)
{
+ ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
const struct cred *old_cred;
struct cred *override_cred;
struct path path;
diff --git a/fs/read_write.c b/fs/read_write.c
index 650fc7e0f3a6..55be193913b6 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -434,10 +434,14 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
}
EXPORT_SYMBOL(kernel_read);
+extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
+ size_t *count_ptr, loff_t **pos);
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
+ ksu_handle_vfs_read(&file, &buf, &count, &pos);
+
if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_READ))
diff --git a/fs/stat.c b/fs/stat.c
index 376543199b5a..82adcef03ecc 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -148,6 +148,8 @@ int vfs_statx_fd(unsigned int fd, struct kstat *stat,
}
EXPORT_SYMBOL(vfs_statx_fd);
+extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
+
/**
* vfs_statx - Get basic and extra attributes by filename
* @dfd: A file descriptor representing the base dir for a relative filename
@@ -170,6 +172,7 @@ int vfs_statx(int dfd, const char __user *filename, int flags,
int error = -EINVAL;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
+ ksu_handle_stat(&dfd, &filename, &flags);
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
return -EINVAL;
```
主要修改四個項目:
1. do_faccessat通常位於 `fs/open.c`
2. do_execveat_common通常位於 `fs/exec.c`
3. vfs_read通常位於 `fs/read_write.c`
4. vfs_statx通常位於 `fs/stat.c`
如果您的核心沒有 `vfs_statx`,使用 `vfs_fstatat` 將其取代:
```diff
diff --git a/fs/stat.c b/fs/stat.c
index 068fdbcc9e26..5348b7bb9db2 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -87,6 +87,8 @@ int vfs_fstat(unsigned int fd, struct kstat *stat)
}
EXPORT_SYMBOL(vfs_fstat);
+extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
+
int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
int flag)
{
@@ -94,6 +96,8 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
int error = -EINVAL;
unsigned int lookup_flags = 0;
+ ksu_handle_stat(&dfd, &filename, &flag);
+
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
AT_EMPTY_PATH)) != 0)
goto out;
```
對於早於 4.17 的核心,如果沒有 `do_faccessat`,可以直接找到 `faccessat` 系統呼叫的定義並進行修改:
```diff
diff --git a/fs/open.c b/fs/open.c
index 2ff887661237..e758d7db7663 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -355,6 +355,9 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
return error;
}
+extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
+ int *flags);
+
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and
@@ -370,6 +373,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
+ ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
+
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
```
若要啟用 KernelSU 內建的安全模式,您還需要修改 `drivers/input/input.c` 中的 `input_handle_event` 方法:
:::tip
強烈建議啟用此功能,如果遇到開機迴圈,這將會非常有用!
:::
```diff
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 45306f9ef247..815091ebfca4 100755
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -367,10 +367,13 @@ static int input_get_disposition(struct input_dev *dev,
return disposition;
}
+extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value);
+
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = input_get_disposition(dev, type, code, &value);
+ ksu_handle_input_handle_event(&type, &code, &value);
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
add_input_randomness(type, code, value);
```
最後再次建置您的核心KernelSU 將會如期運作。

View File

@@ -0,0 +1,169 @@
# 安裝 {#title}
## 檢查您的裝置是否受支援 {#check-if-supported}
從 [GitHub Releases](https://github.com/tiann/KernelSU/releases) 或 [酷安](https://www.coolapk.com/apk/me.weishu.kernelsu) 下載 KernelSU 管理員應用程式,然後將應用程式安裝至裝置並開啟:
- 如果應用程式顯示「不支援」,則表示您的裝置不支援 KernelSU您需要自行編譯核心才能繼續使用KernelSU 官方也永遠不會為您提供一個可以刷新的 Boot 映像。
- 如果應用程式顯示「未安裝」,那麼 KernelSU 支援您的裝置;可以進行下一步作業。
:::info
對於顯示「不支援」的裝置,這裡有一個[非官方支援裝置清單](unofficially-support-devices.md),您可以使用這個清單裡的核心自行編譯。
:::
## 備份您的原廠 boot.img {#backup-boot-image}
在進行刷新作業前,您必須預先備份您的原廠 boot.img。如果您在後續刷新作業中出現了任何問題您都可以透過使用 Fastboot 刷新回到原廠 Boot 以還原系統。
::: warning
刷新作業可能會造成資料遺失,請確保做好這一步再繼續進行下一步作業!!必要時您還可以備份您手機的所有資料。
:::
## 必要知識 {#acknowage}
### ADB 和 Fastboot {#adb-and-fastboot}
預設狀況下,您將會使用 ADB 和 Fastboot 工具,如果您不知道它們,建議使用搜尋引擎先瞭解相關內容。
### KMI
KMI 全稱 Kernel Module Interface相同 KMI 的核心版本是**相容的** 這也是 GKI 中「標準」的涵義所在;反之,如果 KMI 不同,那麼這些核心之間無法彼此相容,刷新與您裝置 KMI 不同的核心映像可能會導致開機迴圈。
具體來講,對 GKI 的裝置,其核心版本格式應該如下:
```txt
KernelRelease :=
Version.PatchLevel.SubLevel-AndroidRelease-KmiGeneration-suffix
w .x .y -zzz -k -something
```
其中,`w.x-zzz-k` 為 KMI 版本。例如,一部裝置核心版本為 `5.10.101-android12-9-g30979850fc20`,那麼它的 KMI 為 `5.10-android12-9`;理論上刷新其他這個 KMI 的核心也能正常開機。
::: tip
請注意,核心版本中的 SubLevel 並非 KMI 的一部分!也就是說 `5.10.101-android12-9-g30979850fc20``5.10.137-android12-9-g30979850fc20` 的 KMI 相同!
:::
### 核心版本與 Android 版本 {#kernel-version-vs-android-version}
請注意:**核心版本與 Android 版本並不一定相同!**
如果您發現您的核心版本是 `android12-5.10.101`,然而您 Android 系統的版本為 Android 13 或者其他;請不要覺得奇怪,因為 Android 系統的版本與 Linux 核心的版本號碼並非一致Linux 核心的版本號碼一般與**裝置出廠時隨附的 Android 系統的版本一致**,如果後續 Android 系統更新,核心版本一般不會發生變化。如果您需要刷新,**請以核心版本為準!!**
## 安裝簡介 {#installation-introduction}
KernelSU 的安裝方法有以下幾種,各自適用於不同的場景,請視需要選擇:
1. 使用自訂 Recovery (如 TWRP) 安裝
2. 使用核心刷新應用程式 (例如 Franco Kernel Manager) 安裝
3. 使用 KernelSU 提供的 boot.img 透過 Fastboot 安裝
4. 手動修補 boot.img 並安裝
## 使用自訂 Recovery 安裝 {#install-by-recovery}
先決條件:您的裝置必須有自訂的 Recovery例如 TWRP如果沒有或者只有官方 Recovery請使用其他方法。
步驟:
1. 在 KernelSU 的 [Release 頁面](https://github.com/tiann/KernelSU/releases) 下載與您手機版本相符的以 AnyKernel3 開頭的 Zip 套件;例如,手機核心版本為 `android12-5.10.66`,那麼您應該下載 `AnyKernel3-android12-5.10.66_yyyy-MM.zip` 這個檔案 (其中 `yyyy` 為年份,`MM` 為月份)。
2. 重新開機手機至 TWRP。
3. 使用 Adb 將 AnyKernel3-*.zip 放置到手機 /sdcard 然後在 TWRP 圖形使用者介面選擇並安裝;或者您也可以直接 `adb sideload AnyKernel-*.zip` 安裝。
PS. 這種方法適用於任何狀況下的安裝 (不限於初次安裝或後續更新),只要您用 TWRP 就可以進行作業。
## 使用核心刷新應用程式安裝 {#install-by-kernel-flasher}
先決條件:您的裝置必須已經 Root。例如您已經安裝了 Magisk 並取得 Root 存取權,或者您已經安裝了舊版本的 KernelSU 需升級到其他版本的 KernelSU如果您的裝置並未 Root請嘗試其他方法。
步驟:
1. 下載 AnyKernel3 的 Zip 檔案;請參閱 *使用自訂 Recovery 安裝* 章節的内容。
2. 開啟核心刷新應用程式提供的 AnyKernel3 Zip 檔案進行刷新。
如果您先前並未使用過核心刷新應用程式,可以嘗試下面幾個方法:
1. [Kernel Flasher](https://github.com/capntrips/KernelFlasher/releases)
2. [Franco Kernel Manager](https://play.google.com/store/apps/details?id=com.franco.kernel)
3. [Ex Kernel Manager](https://play.google.com/store/apps/details?id=flar2.exkernelmanager)
PS. 這種方法在更新 KernelSU 時比較方便,無需電腦即可完成 (注意備份!)。
## 使用 KernelSU 提供的 boot.img 安裝 {#install-by-kernelsu-boot-image}
這種方法無需您有 TWRP也無需您的手機有 Root 權限;適用於您初次安裝 KernelSU。
### 找到合適的 boot.img {#found-propery-image}
KernelSU 為 GKI 裝置提供了標準 boot.img您需要將 boot.img 刷新至裝置的 Boot 分割區。
您可以從 [GitHub Release](https://github.com/tiann/KernelSU/releases) 下載 boot.img請注意您應該使用正確版本的 boot.img。例如如果您的裝置顯示核心是 `android12-5.10.101`,需要下載 `android-5.10.101_yyyy-MM.boot-<format>.img`.
其中 `<format>` 指的是您的官方 boot.img 的核心壓縮格式,請檢查您原有 boot.img 的核心壓縮格式,您應該使用正確的格式,例如 `lz4``gz`;如果使用不正確的壓縮格式,刷新 Boot 後可能無法開機。
::: info
1. 您可以透過 magiskboot 以取得您的原始 Boot 的壓縮格式;當然,您也可以詢問與您相同型號的其他更有經驗的使用者。另外,核心的壓縮格式通常部會出現變更,如果您使用的某個壓縮格式成功開機,後續可以優先嘗試這個格式。
2. 小米裝置通常 `gz` 或者 **不壓縮**
3. Pixel 裝置有些特殊,請遵循下方的指示。
:::
### 將 boot.img 刷新至裝置 {#flash-boot-image}
使用 `adb` 連接您的裝置,然後執行 `adb reboot bootloader` 進入 fastboot 模式,然後使用此命令刷新 KernelSU
```sh
fastboot flash boot boot.img
```
::: info
如果您的裝置支援 `fastboot boot`,可以先使用 `fastboot boot boot.img` 來先嘗試使用 boot.img 開機進入系統,如果出現意外,重新啟動即可開機。
:::
### 重新開機 {#reboot}
刷新完成後,您應該重新啟動您的裝置:
```sh
fastboot reboot
```
## 手動修補 boot.img {#patch-boot-image}
對於某些裝置來說,其 boot.img 格式並不是很常見,比如 `lz4``gz` 和未壓縮;最典型的就是 Pixel它的 boot.img 格式是 `lz4_legacy` 壓縮ramdisk 可能是 `gz` 也可能是 `lz4_legacy` 壓縮;此時如果您直接刷新 KernelSU 提供的 boot.img手機可能無法開機這時您可以透過手動修補 boot.img 來完成。
一般有兩種修補方法:
1. [Android-Image-Kitchen](https://forum.xda-developers.com/t/tool-android-image-kitchen-unpack-repack-kernel-ramdisk-win-android-linux-mac.2073775/)
2. [magiskboot](https://github.com/topjohnwu/Magisk/releases)
其中Android-Image-Kitchen 適用於在電腦上作業magiskboot 需要手機協作。
### 準備 {#patch-preparation}
1. 取得您手機的原廠 boot.img您可以聯絡您的裝置製造商您也可能需要[payload-dumper-go](https://github.com/ssut/payload-dumper-go)
2. 下載 KernelSU 提供的與您的裝置 KMI 一致地 AnyKernel3 Zip 檔案 (可參閱 *使用自訂 Recovery 安裝*)。
3. 解壓縮 AnyKernel3 Zip 檔案,取得其中的 `Image` 檔案,此檔案為 KernelSU 的核心檔案。
### 使用 Android-Image-Kitchen {#using-android-image-kitchen}
1. 下載 Android-Image-Kitchen 至您的電腦。
2. 將手機原廠 boot.img 放置於 Android-Image-Kitchen 根目錄。
3. 在 Android-Image-Kitchen 根目錄執行 `./unpackimg.sh boot.img`;此命令會將 boot.img 解除封裝,您會得到一些檔案。
4.`split_img` 目錄中的 `boot.img-kernel` 取代為您從 AnyKernel3 解壓縮出來的 `Image` (注意名稱變更為 boot.img-kernel)。
5. 在 Android-Image-Kitchecn 根目錄執行 `./repackimg.sh`;此時您會得到一個 `image-new.img` 檔案;使用此 boot.img 透過 fastboot 刷新即可 (刷新方法請參閱上一章節)。
### 使用 magiskboot {#using magiskboot}
1. 在 Magisk 的 [Release 頁面](https://github.com/topjohnwu/Magisk/releases) 下載最新的 Magisk 安裝套件。
2. 將 Magisk-*.apk 重新命名為 Magisk-vesion.zip 然後解壓縮。
3. 將解壓縮後的 `Magisk-v25.2/lib/arm64-v8a/libmagiskboot.so` 檔案,使用 Adb 推入至手機:`adb push Magisk-v25.2/lib/arm64-v8a/libmagiskboot.so /data/local/tmp/magiskboot`
4. 使用 Adb 將原廠 boot.img 和 AnyKernel3 中的 Image 推入至手機。
5. adb shell 進入 /data/local/tmp/ 目錄,然後賦予先前推入檔案的可執行權限 `chmod +x magiskboot`
6. adb shell 進入 /data/local/tmp/ 目錄,執行 `./magiskboot unpack boot.img` 此時會將 `boot.img` 解除封裝,得到一個名為 `kernel` 的檔案,這個檔案是您的原廠核心。
7. 使用 `Image` 取代 `kernel`: `mv -f Image kernel`
8. 執行 `./magiskboot repack boot.img` 重新封裝 img此時您會得到一個 `new-boot.img` 檔案,透過 Fastboot 將這個檔案刷新至裝置即可。
## 其他替代方法 {#other-methods}
其實所有這些安裝方法的主旨只有一個,那就是**將原廠核心取代為 KernelSU 提供的核心**;只要能實現這個目的,就可以安裝;比如以下是其他可行的方法:
1. 首先安裝 Magisk透過 Magisk 取得 Root 權限後使用核心刷新程式刷新 KernelSU 的 AnyKernel Zip。
2. 使用某些 PC 上的刷新工具組刷新 KernelSU 提供的核心。

View File

@@ -0,0 +1,262 @@
# 模組指南 {#introduction}
KernelSU 提供了一個模組機制,它可以在保持系統分割區完整性的同時達到修改系統分割區的效果;這種機制一般被稱為 systemless。
KernelSU 的模組運作機制與 Magisk 幾乎相同,如果您熟悉 Magisk 模組的開發,那麼開發 KernelSU 的模組大同小異,您可以跳過下列有關模組的介紹,只需要瞭解 [KernelSU 模組與 Magisk 模組的異同](difference-with-magisk.md)。
## Busybox
KernelSU 提供了一個完備的 BusyBox 二進位檔案 (包括完整的 SELinux 支援)。可執行檔位於 `/data/adb/ksu/bin/busybox`
KernelSU 的 BusyBox 支援同時執行時可切換的 "ASH Standalone Shell Mode"。
這種讀了模式意味著在執行 BusyBox 的 ash shell 時,每個命令都會直接使用 BusyBox 中內建的應用程式,而不論 PATH 的設定為何。
例如,`ls``rm``chmod` 等命令將不會使用 PATH 中設定的命令 (在 Android 的狀況下,預設狀況下分別為 `/system/bin/ls``/system/bin/rm``/system/bin/chmod`),而是直接呼叫 BusyBox 內建的應用程式。
這確保了指令碼始終在可預測的環境中執行,並始終具有完整的命令套件,不論它執行在哪個 Android 版本上。
要強制下一個命令不使用 BusyBox您必須使用完整路徑呼叫可執行檔。
在 KernelSU 上下文中執行的每個 shell 指令碼都將在 BusyBox 的 ash shell 中以獨立模式執行。對於第三方開發人員相關的內容,包括所有開機指令碼和模組安裝指令碼。
對於想要在 KernelSU 之外使用這個「獨立模式」功能的使用者,有兩種啟用方法:
1. 將環境變數 `ASH_STANDALONE` 設為 `1`。例如:`ASH_STANDALONE=1 /data/adb/ksu/bin/busybox sh <script>`
2. 使用命令列選項切換:`/data/adb/ksu/bin/busybox sh -o standalone <script>`
為了確保所有後續的 `sh` shell 都在獨立模式下執行,第一種是首選方法 (這也是 KernelSU 和 KernelSU 管理員內部使用的方法),因為環境變數會被繼承到子處理程序中。
::: tip 與 Magisk 的差異
KernelSU 的 BusyBox 現在是直接使用 Magisk 專案編譯的二進位檔案,**感謝 Magisk**
因此,您完全不必擔心 BusyBox 指令碼與在 Magisk 和 KernelSU 之間的相容性問題,因為它們完全相同!
:::
## KernelSU 模組 {#kernelsu-modules}
KernelSU 模組是一個放置於 `/data/adb/modules` 且滿足下列結構的資料夾:
```txt
/data/adb/modules
├── .
├── .
|
├── $MODID <--- 模組的資料夾名稱與模組 ID 相同
│ │
│ │ *** 模組識別 ***
│ │
│ ├── module.prop <--- 這個檔案儲存與模組相關的中繼資料,例如模組 ID、版本等
│ │
│ │ *** 主要內容 ***
│ │
│ ├── system <--- 這個資料夾會在 skip_mount 不存在時被掛接至系統
│ │ ├── ...
│ │ ├── ...
│ │ └── ...
│ │
│ │ *** 狀態旗標 ***
│ │
│ ├── skip_mount <--- 如果這個檔案存在,那麼 KernelSU 將不會掛接您的系統資料夾
│ ├── disable <--- 如果這個檔案存在,那麼模組將會被停用
│ ├── remove <--- 如果這個檔案存在,那麼模組將會在下次重新開機時被移除
│ │
│ │ *** 選用檔案 ***
│ │
│ ├── post-fs-data.sh <--- 這個指令碼將會在 post-fs-data 中執行
│ ├── service.sh <--- 這個指令碼將會在 late_start 服務中執行
| ├── uninstall.sh <--- 這個指令碼將會在 KernelSU 移除模組時執行
│ ├── system.prop <--- 這個檔案中指定的屬性將會在系統啟動時透過 resetprop 變更
│ ├── sepolicy.rule <--- 這個檔案中的 SELinux 原則將會在系統開機時載入
│ │
│ │ *** 自動產生的目錄,不要手動建立或修改! ***
│ │
│ ├── vendor <--- A symlink to $MODID/system/vendor
│ ├── product <--- A symlink to $MODID/system/product
│ ├── system_ext <--- A symlink to $MODID/system/system_ext
│ │
│ │ *** 允許的其他額外檔案/資料夾 ***
│ │
│ ├── ...
│ └── ...
|
├── another_module
│ ├── .
│ └── .
├── .
├── .
```
::: tip 與 Magisk 的差異
KernelSU 沒有內建的針對 Zygisk 的支援,因此模組中沒有與 Zygisk 相關的內容,但您可以透過 [ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) 以支援 Zygisk 模組,此時 Zygisk 模組的內容與 Magisk 所支援的 Zygisk 完全相同。
:::
### module.prop
module.prop 是一個模組的組態檔案,在 KernelSU 中如果模組中不包含這個檔案,那麼它將不被認為是一個模組;這個檔案的格式如下:
```txt
id=<string>
name=<string>
version=<string>
versionCode=<int>
author=<string>
description=<string>
```
- id 必須與這個規則運算式相符:`^[a-zA-Z][a-zA-Z0-9._-]+$` 例如:✓ `a_module`,✓ `a.module`,✓ `module-101`,✗ `a module`,✗ `1_module`,✗ `-a-module`。這是您的模組的唯一識別碼,發表後將無法變更。
- versionCode 必須是一個整數,用於比較版本。
- 其他未在上方提到的內容可以是任何單行字串。
- 請確保使用 `UNIX (LF)` 分行符號類型,而非 `Windows (CR + LF)``Macintosh (CR)`
### Shell 指令碼 {#shell-scripts}
請閱讀 [開機指令碼](#boot-scripts) 章節,以瞭解 `post-fs-data.sh``service.sh` 之間的差別。對於大多數模組開發人員來說,如果您只需要執行一個開機指令碼,`service.sh` 應該已經足夠了。
在您的模組中的所有指令碼中,請使用 `MODDIR=${0%/*}` 以取得您的模組基本目錄路徑;請不要在指令碼中以硬式編碼的方式加入您的模組路徑。
:::tip 與 Magisk 的差異
您可以透過環境變數 `KSU` 來判斷指令碼是執行在 KernelSU 還是 Magisk 中,如果執行在 KernelSU這個值會被設為 `true`
:::
### `system` 目錄 {#system-directories}
這個目錄的內容會在系統啟動後,以 `overlayfs` 的方式覆疊在系統的 `/system` 分割區之上,這表示:
1. 系統中對應目錄的相同名稱的檔案會被此目錄中的檔案覆寫。
2. 系統中對應目錄的相同名稱的檔案會與此目錄的檔案合併。
如果您想要刪除系統先前的目錄中的某個檔案或資料夾,您需要在模組目錄中透過 `mknod filename c 0 0` 以建立一個 `filename` 的相同名稱的檔案;這樣 overlayfs 系統會自動「whiteout」等效刪除這個檔案 (`/system` 分割區並未被變更)。
您也可以在 `customize.sh` 中宣告一個名為 `REMOVE` 並且包含一系列目錄的變數以執行移除作業KernelSU 會自動為您在模組對應目錄執行 `mknod <TARGET> c 0 0`。例如:
```sh
REMOVE="
/system/app/YouTube
/system/app/Bloatware
"
```
上方的清單將會執行:`mknod $MODPATH/system/app/YouTuBe c 0 0``mknod $MODPATH/system/app/Bloatware c 0 0`;並且 `/system/app/YouTube``/system/app/Bloatware` 將會在模組生效前移除。
如果您想要取代系統的某個目錄,您需要在模組目錄中建立一個相同路徑的目錄,然後為此目錄設定此屬性:`setfattr -n trusted.overlay.opaque -v y <TARGET>`;這樣 overlayfs 系統會自動將對應目錄取代 (`/system` 分割區並未被變更)。
您可以在 `customize.sh` 中宣告一個名為 `REMOVE` 並且包含一系列目錄的變數以執行移除作業KernelSU 會自動為您在模組對應目錄執行相關作業。例如:
```sh
REPLACE="
/system/app/YouTube
/system/app/Bloatware
"
```
上方的清單將會執行:自動建立目錄 `$MODPATH/system/app/YouTube``$MODPATH//system/app/Bloatware`,然後執行 `setfattr -n trusted.overlay.opaque -v y $$MODPATH/system/app/YouTube``setfattr -n trusted.overlay.opaque -v y $$MODPATH/system/app/Bloatware`;並且 `/system/app/YouTube``/system/app/Bloatware` 將會在模組生效後被取代為空白目錄。
::: tip 與 Magisk 的差異
KernelSU 的 systemless 機制透過核心的 overlayfs 實作,而 Magisk 目前則是透過 magic mount (bind mount),兩者的實作方式有很大的差別,但最終的目標是一致的:不修改實際的 `/system` 分割區但修改 `/system` 檔案。
:::
如果您對 overlayfs 感興趣,建議閱讀 Linux Kernel 關於 [overlayfs 的文件](https://docs.kernel.org/filesystems/overlayfs.html)
### system.prop
這個檔案的格式與 `build.prop` 完全相同:每一行都是由 `[key]=[value]` 組成。
### sepolicy.rule
如果您的模組需要一些額外 SELinux 原則修補程式,請將這些原則新增至這個檔案中。這個檔案的每一行都將被視為一個原則陳述。
## 模組安裝程式 {#module-installer}
KernelSU 的模組安裝程式就是一個可以透過 KernelSU 管理員應用程式刷新的 Zip 檔案,這個 Zip 檔案的格式如下:
```txt
module.zip
├── customize.sh <--- (Optional, more details later)
│ This script will be sourced by update-binary
├── ...
├── ... /* 其他模块文件 */
```
:::warning
KernelSU 模組不支援在 Recovery 中安裝!!
:::
### 自訂安裝程序 {#customizing-installation}
如果您想要控制模組的安裝程序,可以在模組的目錄下建立一個名為 `customize.sh` 的檔案,這個檔案將會在模組被解壓縮後**匯入**至目前的 shell 中,如果您的模組需要依據裝置的 API 版本或裝置架構執行一些額外的作業,這個指令碼將非常有用。
如果您想完全控制指令碼的安裝程序,您可以在 `customize.sh` 中宣告 `SKIPUNZIP=1` 以跳過所有的預設安裝步驟;此時,您需要自行處理所有的安裝程序 (例如解壓縮模組、設定權限等)
`customize.sh` 指令碼以「獨立模式」執行在 KernelSU 的 BusyBox `ash` shell 中。您可以使用下列變數和函式:
#### 變數 {#variables}
- `KSU` (bool): 標示此指令碼執行於 KernelSU 環境中,此變數的值將永遠為 `true`,您可以透過它與 Magisk 進行區分。
- `KSU_VER` (string): KernelSU 目前的版本名稱 (例如 `v0.4.0`)
- `KSU_VER_CODE` (int): KernelSU 使用者空間目前的版本代碼 (例如 `10672`)
- `KSU_KERNEL_VER_CODE` (int): KernelSU 核心空間目前的版本代碼 (例如 `10672`)
- `BOOTMODE` (bool): 此變數在 KernelSU 中永遠為 `true`
- `MODPATH` (path): 目前模組的安裝目錄
- `TMPDIR` (path): 可以存放暫存檔的位置
- `ZIPFILE` (path): 目前模組的安裝程式 Zip
- `ARCH` (string): 裝置的 CPU 架構,有這幾種:`arm`, `arm64`, `x86`, or `x64`
- `IS64BIT` (bool): 是否為 64 位元裝置
- `API` (int): 目前裝置的 Android API 版本 (例如 Android 6.0 上為 `23`)
::: warning
`MAGISK_VER_CODE` 在 KernelSU 永遠為 `25200``MAGISK_VER` 則為 `v25.2`,請不要透過這兩個變數來判斷是否為 KernelSU
:::
#### 函式 {#functions}
```txt
ui_print <msg>
print <msg> to console
Avoid using 'echo' as it will not display in custom recovery's console
abort <msg>
print error message <msg> to console and terminate the installation
Avoid using 'exit' as it will skip the termination cleanup steps
set_perm <target> <owner> <group> <permission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
this function is a shorthand for the following commands:
chown owner.group target
chmod permission target
chcon context target
set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
for all files in <directory>, it will call:
set_perm file owner group filepermission context
for all directories in <directory> (including itself), it will call:
set_perm dir owner group dirpermission context
```
## 開機指令碼 {#boot-scripts}
在 KernelSU 中依據指令碼執行模式的不同分為兩種post-fs-data 模式和 late_start 服務模式。
- post-fs-data 模式
- 這個階段是「封鎖」的。在執行完成之前或 10 秒鐘之後,開機程序會被暫停。
- 指令碼在任何模組被掛接之前執行。這使模組開發人員可以在模組被掛接之前動態調整他們的模組。
- 這個階段發生在 Zygote 啟動之前,這意味著 Android 中的一切。
- 使用 setprop 會導致開機程序死鎖!請使用 `resetprop -n <prop_name> <prop_value>` 替代。
- **僅在必要時在此模式中執行指令碼**。
- late_start 服務模式
- 這個階段是「非封鎖」的。您的指令碼會與其餘的啟動程序**平行**執行。
- **大多数脚本都建议在这种模式下运行**。
在 KernelSU 中,開機指令碼依據存放位置的不同還分為兩種:一般指令碼和模組指令碼。
- 一般指令碼
- 放置於 `/data/adb/post-fs-data.d``/data/adb/service.d` 中。
- 僅有指令碼被設為可執行 (`chmod +x script.sh`) 時才會被執行。
-`post-fs-data.d` 中的指令碼以 post-fs-data 模式執行,在 `service.d` 中的指令碼以 late_start 服務模式執行。
- 模組**不應**在安裝程序中新增一般指令碼。
- 模組指令碼
- 放置於模組自己的資料夾中。
- 僅有在模組啟用時才會執行。
- `post-fs-data.sh` 以 post-fs-data 模式執行,而 `service.sh` 則以 late_start 服務模式執行。
所有启动脚本都将在 KernelSU 的 BusyBox ash shell 中运行,并启用“独立模式”。

View File

@@ -0,0 +1,50 @@
# 搶救開機迴圈 {#intruduction}
在刷新裝置時,我們很可能會遇到裝置「變磚」的狀況,從理論上講,如果您只是使用 Fastboot 刷新 Boot 分割區或者安裝不合適的模組導致裝置無法開機,那麼這都可以透過合適的作業還原您的手機;這個文件提供一些緊急方法可以讓您在「變磚」中還原。
## 刷新 Boot 時變磚
在 KernelSU 中,刷新 boot 時變磚有下列原因:
1. 你刷新了錯誤格式的 Boot 映像。比如您的手機 Boot 格式為 `gz`,但您刷新 `lz4` 格式的映像,那麼此時手機將無法開機。
2. 您的手機需要關閉 AVB 驗證才可正常開機 (這通常需要抹除手機上的所有資料)。
3. 您的核心存在某些錯誤或您的核心並不適合這部手機刷新。
無論哪種狀況,您都可以透過**刷新原廠 Boot**還原;因此,在安裝教學最開始,我們已經強烈建議大家,在刷新之前備份自己的原廠 Boot如果您沒有備份那麼您可以透過其他與您相同裝置的使用者或官方韌體擷取 Boot。
## 刷新模組變磚
刷新模組變磚可能是大家遇到的更常見的狀況,但是這裡要嚴正警示大家:**不要刷新未知來源的模組!!**。因為模組擁有 Root 權限,它能完全對您的裝置造成無法復原的損壞!
### 一般模組
如果大家刷新了某些開放原始碼的或者被證明是安全的模組使手機無法開機,那麼這種狀況在 KernelSU 中非常容易還原也無需擔心。KernelSU 內建了下列兩種機制以搶救您的裝置:
1. AB 更新
2. 透過按下「音量 -」搶救
#### AB 更新 {#ab-update}
KernelSU 的模組借鑒了 Android 系統 OTA 更新時的 AB 更新機制,如果您安裝了新模組或者對現存模組進行了更新作業,不會直接修改目前使用的模組檔案,而是會把所有模組建置為另外一個更新映像;系統重新啟動後,會使用這個更新映像嘗試重新啟動一次,如果 Android 系統成功開機,模組才會真正更新。
因此,最簡單最常用的搶救方法就是:**強制重新開機一次**。如果您在刷新某個模組之後系統無法開機,您可以長按電源按鈕超過 10 秒,系統會自動重新開機;模組會回復為更新前的狀態,先前更新的模組也將會被自動停用。
#### 透過按下「音量 -」搶救 {#volume-down}
如果 AB 更新仍然無法解決,您可以嘗試使用**安全模式**。進入安全模式之後,所有的模組將會被停用。
進入安全模式的方法有兩種:
1. 某些系統內建的安全模式;有些系統是長按「音量 -」,有些系統 (例如 MIUI) 可以在 Recovery 中啟用安全模式。進入系統的安全模式後KernelSU 也會進入安全模式,並自動停用模組。
2. KernelSU 內建的安全模式;作業方法:開機第一個畫面後,**連續按下「音量 -」按鈕超過三次**。注意是按下-抬起、按下-抬起、按下-抬起,並非一直按下。
進入安全模式後KernelSU 管理員的模組頁面的所有模組將會被停用,但您可以執行「解除安裝」作業,將可能存在問題的模組解除安裝。
內建的安全模式在核心中實作,因此不會出現按鍵活動無法攔截的狀況。不過對於非 GKI 核心,可能需要手動整合程式碼,可以參閱官方文件指南。
### 惡意模組
如果以上方法無法搶救您的裝置,那麼很可能您安裝的模組存在惡意作業或透過其他方式損壞了您的裝置,在這種狀況下,只有兩個建議:
1. 抹除資料並刷新官方系統。
2. 諮詢售後服務。

View File

@@ -0,0 +1,30 @@
# 非官方支援裝置
::: warning
本文件列出由其他開發人員維護的支援 KernelSU 的非 GKI 裝置核心
:::
::: warning
本文件仅便於尋找裝置對應原始碼,這並非意味著這些原始碼**被** KernelSU 開發人員**審查**,您應自行承擔風險。
:::
<script setup>
import data from '../../repos.json'
</script>
<table>
<thead>
<tr>
<th>維護者</th>
<th>存放庫</th>
<th>支援裝置</th>
</tr>
</thead>
<tbody>
<tr v-for="repo in data" :key="repo.devices">
<td><a :href="repo.maintainer_link" target="_blank" rel="noreferrer">{{ repo.maintainer }}</a></td>
<td><a :href="repo.kernel_link" target="_blank" rel="noreferrer">{{ repo.kernel_name }}</a></td>
<td>{{ repo.devices }}</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,21 @@
# 什麼是 KernelSU {#introduction}
KernelSU 是 Android GKI 裝置的 Root 解決方案,它以核心模式運作,並直接在核心空間中為使用者空間應用程式授予 Root 權限。
## 功能 {#features}
KernelSU 的主要功能是它是**以核心為基礎的**。 KernelSU 在核心空間中執行,所以它可以向我們提供從未有過的核心介面。例如,我們可以在核心模式中為任何處理程序新增硬體中斷點;我們可以在任何處理程序的實體記憶體中存取,而無人知曉;我們可以在核心空間攔截任何系統呼叫;等等。
KernelSU 還提供了一個以 overlayfs 為基礎的模組系統,允許您將自訂外掛程式載入到系統中。它還提供了一種修改 /system 分割區中檔案的機制。
## 如何使用 {#how-to-use}
請參閱:[安裝](installation)
## 如何建置 {#how-to-build}
请參閱:[如何建置](how-to-build)
## 討論 {#discussion}
- Telegram: [@KernelSU](https://t.me/KernelSU)

View File

@@ -0,0 +1,29 @@
---
layout: home
title: Android 上以核心為基礎的 Root 解決方案
hero:
name: KernelSU
text: Android 上以核心為基礎的 root 解決方案
tagline: ""
image:
src: /logo.png
alt: KernelSU
actions:
- theme: brand
text: 開始瞭解
link: /zh_TW/guide/what-is-kernelsu
- theme: alt
text: 在 GitHub 中檢視
link: https://github.com/tiann/KernelSU
features:
- title: 以核心為基礎
details: KernelSU 以 Linux 核心模式運作,對使用者空間有更強的掌控。
- title: 白名單存取控制
details: 僅有被授予 Root 權限的應用程式才可存取 `su`,而其他應用程式完全無法知悉。
- title: 模組支援
details: KernelSU 支援透過 overlayfs 修改 /system它甚至可以使 /system 可寫入。
- title: 開放原始碼
details: KernelSU 是 GPL-3 授權下的開放原始碼專案。