You've already forked KernelSU
mirror of
https://github.com/tiann/KernelSU.git
synced 2025-08-27 23:46:34 +00:00
Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f341a4e3a | ||
|
|
40d7bc6256 | ||
|
|
56dbc980f4 | ||
|
|
bf71ff133c | ||
|
|
a9b156df43 | ||
|
|
1690e5db02 | ||
|
|
300d9d4cca | ||
|
|
3f12080dfe | ||
|
|
b670db2d22 | ||
|
|
62a31b3dc2 | ||
|
|
a395b1011e | ||
|
|
406070914a | ||
|
|
8685fa1f60 | ||
|
|
c95163b144 | ||
|
|
648d56da39 | ||
|
|
33c0a9eebd | ||
|
|
3f86fb016d | ||
|
|
66316e76f5 | ||
|
|
5591a94f87 | ||
|
|
f855f8148a | ||
|
|
0c52f24612 | ||
|
|
9635a00036 | ||
|
|
cbc04ff6df | ||
|
|
8e448767a5 | ||
|
|
2820779947 | ||
|
|
a99c69f9b4 | ||
|
|
a829707b16 | ||
|
|
77d16ac896 | ||
|
|
d02855a40a | ||
|
|
b904680f13 | ||
|
|
811c68cac0 | ||
|
|
f20ccc1728 | ||
|
|
66e7db2a4e | ||
|
|
e6b05b1d3c | ||
|
|
329010a694 | ||
|
|
9c4d20c0f2 | ||
|
|
355b55a01d | ||
|
|
e85646fad4 | ||
|
|
4969c5f548 | ||
|
|
55f8f2da90 | ||
|
|
65bff7bf03 | ||
|
|
30dfbbdc0e | ||
|
|
fceffc9cfe | ||
|
|
01b685ce58 | ||
|
|
cbd184421c | ||
|
|
b0a42abf4f | ||
|
|
cfc982f2f3 | ||
|
|
e0e7058d14 | ||
|
|
e0802b0d15 | ||
|
|
81f15ef120 | ||
|
|
20c19d7126 | ||
|
|
a360cd87c0 | ||
|
|
ea9b572402 | ||
|
|
6bf9e0478e | ||
|
|
abf0dacb36 | ||
|
|
263b986bcd | ||
|
|
15bdd9f507 | ||
|
|
810a62f795 | ||
|
|
07e475c5dc | ||
|
|
eb02e42bc7 | ||
|
|
5db51b0715 | ||
|
|
60d2685f7e | ||
|
|
a4b9ea04a4 | ||
|
|
f80d0764b5 | ||
|
|
f80769a82a | ||
|
|
64269c8c4f | ||
|
|
9f04482b90 | ||
|
|
aca505c3e6 | ||
|
|
d4826bc97c | ||
|
|
4efc8164f1 | ||
|
|
0fc25cf091 | ||
|
|
ca438291cc | ||
|
|
d6cab60e6d | ||
|
|
4d4bd4793f | ||
|
|
c1a2cbf1e4 | ||
|
|
4b1fb121b4 | ||
|
|
883a3e3407 | ||
|
|
27bd18f60e | ||
|
|
7cb5fb47e1 | ||
|
|
d43b40572d | ||
|
|
c99b5b31c1 | ||
|
|
ca960a2a8f | ||
|
|
cce423a2f6 | ||
|
|
946fb6f999 | ||
|
|
b6ecce4317 | ||
|
|
be70a91f16 | ||
|
|
71c2790f08 | ||
|
|
8733b390ca | ||
|
|
c4e106d6f8 | ||
|
|
b612efcfad | ||
|
|
7f53882007 | ||
|
|
23ba3182cf | ||
|
|
8abd37a35c | ||
|
|
d7bc853bfc | ||
|
|
16c5aba4ff | ||
|
|
3914242457 | ||
|
|
eaa12161d6 | ||
|
|
0f985917f9 | ||
|
|
a569b1c76e | ||
|
|
7f1ea2e178 | ||
|
|
da89a45d56 | ||
|
|
dc2fb20d24 | ||
|
|
d7625722db | ||
|
|
4144f10d9a | ||
|
|
aaddaf1a78 | ||
|
|
2fec279de3 | ||
|
|
1e676e5dc2 | ||
|
|
7b63e099ce | ||
|
|
aef943ebe3 | ||
|
|
1637864636 | ||
|
|
e934bfb648 | ||
|
|
653225bb5b | ||
|
|
decbdeb5d7 | ||
|
|
51ca19f267 | ||
|
|
5b920f8230 | ||
|
|
601ce2120a | ||
|
|
6d79060e4c | ||
|
|
e95e87a7a4 | ||
|
|
144b0cc8e9 | ||
|
|
d9d9066316 | ||
|
|
3af293f991 | ||
|
|
60c9fabb44 | ||
|
|
23ffc2a3b2 | ||
|
|
2bab388bbf | ||
|
|
e9997a07c1 | ||
|
|
757e69b15e | ||
|
|
506385cfad | ||
|
|
4b27a9a324 | ||
|
|
1326fd32c5 |
@@ -1,48 +0,0 @@
|
||||
From f1e398602b989ac197cdd0fda4a7c4c323b03eb9 Mon Sep 17 00:00:00 2001
|
||||
From: DozNaka <dozdguide@gmail.com>
|
||||
Date: Mon, 11 Apr 2022 20:43:45 -0400
|
||||
Subject: [PATCH] Makefile: Use CCACHE for faster compilation
|
||||
|
||||
---
|
||||
Makefile | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index e8b8d5894..51e8aac6e 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -442,21 +442,21 @@ KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
|
||||
# Make variables (CC, etc...)
|
||||
CPP = $(CC) -E
|
||||
ifneq ($(LLVM),)
|
||||
-CC = clang
|
||||
-LD = ld.lld
|
||||
-AR = llvm-ar
|
||||
+CC = $(CCACHE) clang
|
||||
+LD = $(CCACHE) ld.lld
|
||||
+AR = $(CCACHE) llvm-ar
|
||||
NM = llvm-nm
|
||||
-OBJCOPY = llvm-objcopy
|
||||
-OBJDUMP = llvm-objdump
|
||||
+OBJCOPY = $(CCACHE) llvm-objcopy
|
||||
+OBJDUMP = $(CCACHE) llvm-objdump
|
||||
READELF = llvm-readelf
|
||||
STRIP = llvm-strip
|
||||
else
|
||||
-CC = $(CROSS_COMPILE)gcc
|
||||
-LD = $(CROSS_COMPILE)ld
|
||||
-AR = $(CROSS_COMPILE)ar
|
||||
+CC = $(CCACHE) $(CROSS_COMPILE)gcc
|
||||
+LD = $(CCACHE) $(CROSS_COMPILE)ld
|
||||
+AR = $(CCACHE) $(CROSS_COMPILE)ar
|
||||
NM = $(CROSS_COMPILE)nm
|
||||
-OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
-OBJDUMP = $(CROSS_COMPILE)objdump
|
||||
+OBJCOPY = $(CCACHE) $(CROSS_COMPILE)objcopy
|
||||
+OBJDUMP = $(CCACHE) $(CROSS_COMPILE)objdump
|
||||
READELF = $(CROSS_COMPILE)readelf
|
||||
STRIP = $(CROSS_COMPILE)strip
|
||||
endif
|
||||
--
|
||||
2.37.2
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
From f1e398602b989ac197cdd0fda4a7c4c323b03eb9 Mon Sep 17 00:00:00 2001
|
||||
From: DozNaka <dozdguide@gmail.com>
|
||||
Date: Mon, 11 Apr 2022 20:43:45 -0400
|
||||
Subject: [PATCH] Makefile: Use CCACHE for faster compilation
|
||||
|
||||
---
|
||||
Makefile | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index e8b8d5894..51e8aac6e 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -442,21 +442,21 @@ KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
|
||||
# Make variables (CC, etc...)
|
||||
CPP = $(CC) -E
|
||||
ifneq ($(LLVM),)
|
||||
-CC = clang
|
||||
-LD = ld.lld
|
||||
-AR = llvm-ar
|
||||
+CC = $(CCACHE) clang
|
||||
+LD = $(CCACHE) ld.lld
|
||||
+AR = $(CCACHE) llvm-ar
|
||||
NM = llvm-nm
|
||||
-OBJCOPY = llvm-objcopy
|
||||
-OBJDUMP = llvm-objdump
|
||||
+OBJCOPY = $(CCACHE) llvm-objcopy
|
||||
+OBJDUMP = $(CCACHE) llvm-objdump
|
||||
READELF = llvm-readelf
|
||||
STRIP = llvm-strip
|
||||
else
|
||||
-CC = $(CROSS_COMPILE)gcc
|
||||
-LD = $(CROSS_COMPILE)ld
|
||||
-AR = $(CROSS_COMPILE)ar
|
||||
+CC = $(CCACHE) $(CROSS_COMPILE)gcc
|
||||
+LD = $(CCACHE) $(CROSS_COMPILE)ld
|
||||
+AR = $(CCACHE) $(CROSS_COMPILE)ar
|
||||
NM = $(CROSS_COMPILE)nm
|
||||
-OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
-OBJDUMP = $(CROSS_COMPILE)objdump
|
||||
+OBJCOPY = $(CCACHE) $(CROSS_COMPILE)objcopy
|
||||
+OBJDUMP = $(CCACHE) $(CROSS_COMPILE)objdump
|
||||
READELF = $(CROSS_COMPILE)readelf
|
||||
STRIP = $(CROSS_COMPILE)strip
|
||||
endif
|
||||
--
|
||||
2.37.2
|
||||
|
||||
7
.github/workflows/build-kernel-a12.yml
vendored
7
.github/workflows/build-kernel-a12.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Build Kernel - Android 12
|
||||
on:
|
||||
push:
|
||||
branches: ["main", "ci"]
|
||||
branches: ["main", "ci", "checkci"]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a12.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-kernel:
|
||||
if: github.event_name != 'pull_request'
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -53,6 +53,7 @@ jobs:
|
||||
tag: android12-5.10-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: "5.10"
|
||||
|
||||
upload-artifacts:
|
||||
needs: build-kernel
|
||||
runs-on: ubuntu-latest
|
||||
@@ -124,7 +125,7 @@ jobs:
|
||||
path: Image-android12*/*.img.gz
|
||||
|
||||
check-build-kernel:
|
||||
if: github.event_name == 'pull_request' && !github.event.pull_request.draft
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android12-5.10
|
||||
|
||||
7
.github/workflows/build-kernel-a13.yml
vendored
7
.github/workflows/build-kernel-a13.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Build Kernel - Android 13
|
||||
on:
|
||||
push:
|
||||
branches: ["main", "ci"]
|
||||
branches: ["main", "ci", "checkci"]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a13.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-kernel:
|
||||
if: github.event_name != 'pull_request'
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -80,6 +80,7 @@ jobs:
|
||||
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
|
||||
upload-artifacts:
|
||||
needs: build-kernel
|
||||
runs-on: ubuntu-latest
|
||||
@@ -151,7 +152,7 @@ jobs:
|
||||
path: Image-android13*/*.img.gz
|
||||
|
||||
check-build-kernel:
|
||||
if: github.event_name == 'pull_request' && !github.event.pull_request.draft
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
|
||||
7
.github/workflows/build-kernel-a14.yml
vendored
7
.github/workflows/build-kernel-a14.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Build Kernel - Android 14
|
||||
on:
|
||||
push:
|
||||
branches: ["main", "ci"]
|
||||
branches: ["main", "ci", "checkci"]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a14.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-kernel:
|
||||
if: github.event_name != 'pull_request'
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -44,6 +44,7 @@ jobs:
|
||||
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
|
||||
upload-artifacts:
|
||||
needs: build-kernel
|
||||
runs-on: ubuntu-latest
|
||||
@@ -115,7 +116,7 @@ jobs:
|
||||
path: Image-android14*/*.img.gz
|
||||
|
||||
check-build-kernel:
|
||||
if: github.event_name == 'pull_request' && !github.event.pull_request.draft
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
|
||||
4
.github/workflows/build-kernel-arcvm.yml
vendored
4
.github/workflows/build-kernel-arcvm.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Build Kernel - ChromeOS ARCVM
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
branches: ["main", "ci", "checkci"]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-arcvm.yml"
|
||||
- "kernel/**"
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
|
||||
|
||||
echo "[+] Apply KernelSU patches"
|
||||
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch
|
||||
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch || echo "[-] No patch found"
|
||||
|
||||
echo "[+] Patch script/setlocalversion"
|
||||
sed -i 's/-dirty//g' $KERNEL_ROOT/scripts/setlocalversion
|
||||
|
||||
138
.github/workflows/build-kernel-wsa.yml
vendored
138
.github/workflows/build-kernel-wsa.yml
vendored
@@ -1,142 +1,38 @@
|
||||
name: Build Kernel - WSA
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
branches: ["main", "ci", "checkci"]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-wsa.yml"
|
||||
- ".github/workflows/wsa-kernel.yml"
|
||||
- "kernel/**"
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-wsa.yml"
|
||||
- ".github/workflows/wsa-kernel.yml"
|
||||
- "kernel/**"
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && !github.event.pull_request.draft)
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
version: ["5.15.94.2", "5.15.104.1", "5.15.104.2", "5.15.104.3", "5.15.104.4"]
|
||||
uses: ./.github/workflows/wsa-kernel.yml
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
version: ${{ matrix.version }}
|
||||
|
||||
name: Build WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||
CCACHE_NOHASHDIR: "true"
|
||||
CCACHE_HARDLINK: "true"
|
||||
|
||||
steps:
|
||||
- name: Install Build Tools
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1
|
||||
with:
|
||||
packages: bc bison build-essential flex libelf-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu gzip ccache
|
||||
version: 1.0
|
||||
|
||||
- name: Cache LLVM
|
||||
id: cache-llvm
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ./llvm
|
||||
key: llvm-12.0.1
|
||||
|
||||
- name: Setup LLVM
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
with:
|
||||
version: "12.0.1"
|
||||
force-version: true
|
||||
ubuntu-version: "16.04"
|
||||
cached: ${{ steps.cache-llvm.outputs.cache-hit }}
|
||||
|
||||
- name: Checkout KernelSU
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup kernel source
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: microsoft/WSA-Linux-Kernel
|
||||
ref: android-lts/latte-2/${{ matrix.version }}
|
||||
path: WSA-Linux-Kernel
|
||||
|
||||
- name: Setup Ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
|
||||
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
max-size: 2G
|
||||
|
||||
- name: Setup KernelSU
|
||||
working-directory: WSA-Linux-Kernel
|
||||
run: |
|
||||
echo "[+] KernelSU setup"
|
||||
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
|
||||
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
|
||||
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
|
||||
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
|
||||
echo "[+] Add KernelSU driver to Makefile"
|
||||
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
|
||||
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
|
||||
echo "[+] Apply KernelSU patches"
|
||||
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch
|
||||
echo "[+] KernelSU setup done."
|
||||
cd $GITHUB_WORKSPACE/KernelSU
|
||||
VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||
echo "VERSION: $VERSION"
|
||||
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Kernel
|
||||
working-directory: WSA-Linux-Kernel
|
||||
run: |
|
||||
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
|
||||
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
|
||||
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||
fi
|
||||
declare -A ARCH_MAP=(["x86_64"]="x64" ["arm64"]="arm64")
|
||||
cp configs/wsa/config-wsa-${ARCH_MAP[${{ matrix.arch }}]} .config
|
||||
make olddefconfig
|
||||
declare -A FILE_NAME=(["x86_64"]="bzImage" ["arm64"]="Image")
|
||||
make -j`nproc` LLVM=1 ARCH=${{ matrix.arch }} $(if [ "${{ matrix.arch }}" == "arm64" ]; then echo CROSS_COMPILE=aarch64-linux-gnu; fi) ${FILE_NAME[${{ matrix.arch }}]} CCACHE="/usr/bin/ccache"
|
||||
declare -A ARCH_MAP_FILE=(["x86_64"]="x86" ["arm64"]="arm64")
|
||||
echo "file_path=WSA-Linux-Kernel/arch/${ARCH_MAP_FILE[${{ matrix.arch }}]}/boot/${FILE_NAME[${{ matrix.arch }}]}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload kernel-${{ matrix.arch }}-${{ matrix.version }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: kernel-WSA-${{ matrix.arch }}-${{ matrix.version }}
|
||||
path: "${{ env.file_path }}"
|
||||
|
||||
- name: Bot session cache
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: scripts/ksubot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Post to Telegram
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
|
||||
env:
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
TITLE=kernel-${{ matrix.arch }}-WSA-${{ matrix.version }}
|
||||
echo "[+] title: $TITLE"
|
||||
export TITLE
|
||||
export VERSION="${{ env.kernelsu_version }}"
|
||||
echo "[+] Compress images"
|
||||
gzip -n -f -9 "${{ env.file_path }}"
|
||||
echo "[+] Image to upload"
|
||||
ls -l "${{ env.file_path }}.gz"
|
||||
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
pip3 install telethon==1.31.1
|
||||
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
|
||||
fi
|
||||
check_build:
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||
uses: ./.github/workflows/wsa-kernel.yml
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
version: "5.15.104.4"
|
||||
20
.github/workflows/build-manager.yml
vendored
20
.github/workflows/build-manager.yml
vendored
@@ -50,11 +50,13 @@ jobs:
|
||||
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
|
||||
{
|
||||
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
|
||||
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
|
||||
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
|
||||
echo KEYSTORE_FILE='../key.jks'
|
||||
} >> gradle.properties
|
||||
echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
|
||||
fi
|
||||
|
||||
- name: Setup Java
|
||||
@@ -104,10 +106,16 @@ jobs:
|
||||
name: manager
|
||||
path: manager/app/build/outputs/apk/release/*.apk
|
||||
|
||||
- name: Upload mappings
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: "mappings"
|
||||
path: "manager/app/build/outputs/mapping/release/"
|
||||
|
||||
- name: Bot session cache
|
||||
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: scripts/ksubot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
2
.github/workflows/gki-kernel.yml
vendored
2
.github/workflows/gki-kernel.yml
vendored
@@ -171,7 +171,7 @@ jobs:
|
||||
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||
fi
|
||||
if [ -e build/build.sh ]; then
|
||||
CCACHE="/usr/bin/ccache" LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
|
||||
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
|
||||
else
|
||||
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
|
||||
fi
|
||||
|
||||
135
.github/workflows/wsa-kernel.yml
vendored
Normal file
135
.github/workflows/wsa-kernel.yml
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
name: Build Kernel - WSA
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
arch:
|
||||
required: true
|
||||
type: string
|
||||
description: >
|
||||
Build arch: x86_64 / arm64
|
||||
version:
|
||||
required: true
|
||||
type: string
|
||||
description: >
|
||||
Build version
|
||||
jobs:
|
||||
build:
|
||||
name: Build WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }}
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||
CCACHE_NOHASHDIR: "true"
|
||||
CCACHE_HARDLINK: "true"
|
||||
|
||||
steps:
|
||||
- name: Install Build Tools
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1
|
||||
with:
|
||||
packages: bc bison build-essential flex libelf-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu gzip ccache
|
||||
version: 1.0
|
||||
|
||||
- name: Cache LLVM
|
||||
id: cache-llvm
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ./llvm
|
||||
key: llvm-12.0.1
|
||||
|
||||
- name: Setup LLVM
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
with:
|
||||
version: "12.0.1"
|
||||
force-version: true
|
||||
ubuntu-version: "16.04"
|
||||
cached: ${{ steps.cache-llvm.outputs.cache-hit }}
|
||||
|
||||
- name: Checkout KernelSU
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup kernel source
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: microsoft/WSA-Linux-Kernel
|
||||
ref: android-lts/latte-2/${{ inputs.version }}
|
||||
path: WSA-Linux-Kernel
|
||||
|
||||
- name: Setup Ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }}
|
||||
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
max-size: 2G
|
||||
|
||||
- name: Setup KernelSU
|
||||
working-directory: WSA-Linux-Kernel
|
||||
run: |
|
||||
echo "[+] KernelSU setup"
|
||||
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
|
||||
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
|
||||
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
|
||||
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
|
||||
echo "[+] Add KernelSU driver to Makefile"
|
||||
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
|
||||
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
|
||||
echo "[+] Apply KernelSU patches"
|
||||
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch || echo "[-] No patch found"
|
||||
echo "[+] KernelSU setup done."
|
||||
cd $GITHUB_WORKSPACE/KernelSU
|
||||
VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||
echo "VERSION: $VERSION"
|
||||
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Kernel
|
||||
working-directory: WSA-Linux-Kernel
|
||||
run: |
|
||||
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
|
||||
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
|
||||
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||
fi
|
||||
declare -A ARCH_MAP=(["x86_64"]="x64" ["arm64"]="arm64")
|
||||
cp configs/wsa/config-wsa-${ARCH_MAP[${{ inputs.arch }}]} .config
|
||||
make olddefconfig
|
||||
declare -A FILE_NAME=(["x86_64"]="bzImage" ["arm64"]="Image")
|
||||
make -j`nproc` LLVM=1 ARCH=${{ inputs.arch }} $(if [ "${{ inputs.arch }}" == "arm64" ]; then echo CROSS_COMPILE=aarch64-linux-gnu; fi) ${FILE_NAME[${{ inputs.arch }}]} CCACHE="/usr/bin/ccache"
|
||||
declare -A ARCH_MAP_FILE=(["x86_64"]="x86" ["arm64"]="arm64")
|
||||
echo "file_path=WSA-Linux-Kernel/arch/${ARCH_MAP_FILE[${{ inputs.arch }}]}/boot/${FILE_NAME[${{ inputs.arch }}]}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload kernel-${{ inputs.arch }}-${{ inputs.version }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: kernel-WSA-${{ inputs.arch }}-${{ inputs.version }}
|
||||
path: "${{ env.file_path }}"
|
||||
|
||||
- name: Bot session cache
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: scripts/ksubot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Post to Telegram
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
|
||||
env:
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
TITLE=kernel-${{ inputs.arch }}-WSA-${{ inputs.version }}
|
||||
echo "[+] title: $TITLE"
|
||||
export TITLE
|
||||
export VERSION="${{ env.kernelsu_version }}"
|
||||
echo "[+] Compress images"
|
||||
gzip -n -f -9 "${{ env.file_path }}"
|
||||
echo "[+] Image to upload"
|
||||
ls -l "${{ env.file_path }}.gz"
|
||||
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
pip3 install telethon==1.31.1
|
||||
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
|
||||
fi
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
@@ -7,13 +6,12 @@
|
||||
|
||||
A Kernel-based root solution for Android devices.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
1. Kernel-based `su` and root access management.
|
||||
@@ -43,12 +41,13 @@ To help translate KernelSU or improve existing translations, please use [Weblate
|
||||
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||
|
||||
## Security
|
||||
|
||||
For information on reporting security vulnerabilities in KernelSU, see [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## License
|
||||
|
||||
- Files under the `kernel` directory are [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- All other parts except the `kernel` directory are [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
- Files under the `kernel` directory are [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- All other parts except the `kernel` directory are [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
一个 Android 上基于内核的 root 方案。
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## 特性
|
||||
|
||||
- 基于内核的 su 和权限管理。
|
||||
- 基于 overlayfs 的模块系统。
|
||||
- [App Profile](https://kernelsu.org/guide/app-profile.html): 把 Root 权限关进笼子里。
|
||||
- 基于内核的 `su` 和权限管理。
|
||||
- 基于 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模块系统。
|
||||
- [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html): 把 Root 权限关进笼子里。
|
||||
|
||||
## 兼容状态
|
||||
|
||||
@@ -16,25 +24,30 @@ KernelSU 官方支持 GKI 2.0 的设备(内核版本5.10以上);旧内核
|
||||
|
||||
WSA, ChromeOS 和运行在容器上的 Android 也可以与 KernelSU 一起工作。
|
||||
|
||||
目前支持架构 : `arm64-v8a` 和 `x86_64`
|
||||
目前支持架构 : `arm64-v8a` 和 `x86_64`。
|
||||
|
||||
## 使用方法
|
||||
|
||||
- [安装教程](https://kernelsu.org/zh_CN/guide/installation.html)
|
||||
- [如何构建?](https://kernelsu.org/zh_CN/guide/how-to-build.html)
|
||||
- [官方网站](https://kernelsu.org/zh_CN/)
|
||||
|
||||
## 参与翻译
|
||||
|
||||
要将 KernelSU 翻译成您的语言,或完善现有的翻译,请使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。
|
||||
要将 KernelSU 翻译成您的语言,或完善现有的翻译,请使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。现已不再接受有关管理器翻译的PR,因为这会与Weblate冲突。
|
||||
|
||||
## 讨论
|
||||
|
||||
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||
|
||||
## 安全性
|
||||
|
||||
有关报告 KernelSU 安全漏洞的信息,请参阅 [SECURITY.md](/SECURITY.md)。
|
||||
|
||||
## 许可证
|
||||
|
||||
- 目录 `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` 下所有文件为 [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。
|
||||
- 除 `kernel` 目录的其他部分均为 [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。
|
||||
|
||||
## 鸣谢
|
||||
|
||||
|
||||
@@ -1,47 +1,56 @@
|
||||
[ 🇬🇧 English](README.md) | 🇪🇸 **Español** | [🇨🇳 简体中文](README_CN.md) | [🇹🇼 繁體中文](README_TW.md) | [ 🇯🇵 日本語](README_JP.md) | [🇵🇱 Polski](README_PL.md) | [🇧🇷 Portuguese-Brazil](README_PT-BR.md) | [🇹🇷 Türkçe](README_TR.md) | [🇷🇺Русский](README_RU.md) | [🇻🇳Tiếng Việt](README_VI.md) | [ɪᴅ indonesia](README_ID.md) | [עברית](README_iw.md) | [🇮🇳हिंदी](README_IN.md)
|
||||
[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="">
|
||||
<div style="margin-left: 20px;">
|
||||
<span style="font-size: large; "><b>KernelSU</b></span>
|
||||
<br>
|
||||
<span style="font-size: medium; "><i>Una solución root basada en el kernel para dispositivos Android.</i></span>
|
||||
</div>
|
||||
</div>
|
||||
# KernelSU
|
||||
|
||||
## 🚀 Características
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
**1.** Binario `su` basado en el kernel y gestión de acceso root.<br/>
|
||||
**2.** Sistema de módulos basado en **OverlayFS**.
|
||||
Una solución root basada en el kernel para dispositivos Android.
|
||||
|
||||
## ✅ Estado de compatibilidad
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Características
|
||||
|
||||
1. Binario `su` basado en el kernel y gestión de acceso root.
|
||||
2. Sistema de módulos basado en [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
|
||||
## Estado de compatibilidad
|
||||
|
||||
**KernelSU** soporta de forma oficial dispositivos Android con **GKI 2.0** (a partir de la versión **5.10** del kernel). Los kernels antiguos (a partir de la versión **4.14**) también son compatibles, pero necesitas compilarlos por tu cuenta.
|
||||
|
||||
El **Subsistema de Windows para Android (WSA)** e implementaciones de Android basadas en contenedores, como **Waydroid**, también deberían funcionar con **KernelSU** integrado.
|
||||
Con esto, WSA, ChromeOS y Android basado en contenedores están todos compatibles.
|
||||
|
||||
Actualmente se soportan las siguientes **ABIs**: `arm64-v8a`; `x86_64`.
|
||||
Actualmente, solo se admiten las arquitecturas `arm64-v8a` y `x86_64`.
|
||||
|
||||
## 📖 Uso
|
||||
## Uso
|
||||
|
||||
[¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
|
||||
- [¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
|
||||
- [¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
|
||||
- [Site oficial](https://kernelsu.org/)
|
||||
|
||||
## 🔨 Compilación
|
||||
## Traducción
|
||||
|
||||
[¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
|
||||
Para ayudar a traducir KernelSU o mejorar las traducciones existentes, utilice [Weblate](https://hosted.weblate.org/engage/kernelsu/). Ya no se aceptan PR de la traducción de Manager porque entrará en conflicto con Weblate.
|
||||
|
||||
## 💬 Discusión
|
||||
## Discusión
|
||||
|
||||
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||
|
||||
## ⚖️ Licencia
|
||||
## Seguridad
|
||||
|
||||
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
Para obtener información sobre cómo informar vulnerabilidades de seguridad en KernelSU, consulte [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## 👥 Créditos
|
||||
## Licencia
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de **KernelSU**.
|
||||
- [genuine](https://github.com/brevent/genuine/): la validación del **esquema de firmas APK v2**.
|
||||
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Créditos
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): la poderosa herramienta root.
|
||||
- [genuine](https://github.com/brevent/genuine/): validación de firma apk v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): algunas habilidades de rootkit.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): la implementación de la **política de SELinux (SEPolicy)**.
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portugis-Brasil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Solusi root berbasis Kernel untuk perangkat Android.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Fitur
|
||||
|
||||
1. Manajemen akses root dan `su` berbasis kernel.
|
||||
2. Sistem modul berdasarkan overlayfs.
|
||||
2. Sistem modul berdasarkan [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Profil Aplikasi](https://kernelsu.org/guide/app-profile.html): Kunci daya root di dalam sangkar.
|
||||
|
||||
## Status Kompatibilitas
|
||||
@@ -20,9 +28,9 @@ Dan ABI yang didukung saat ini adalah: `arm64-v8a` dan `x86_64`
|
||||
|
||||
## Penggunaan
|
||||
|
||||
- [Petunjuk Instalasi](https://kernelsu.org/guide/installation.html)
|
||||
- [Bagaimana cara membuat?](https://kernelsu.org/guide/how-to-build.html)
|
||||
- [Situs Web Resmi](https://kernelsu.org/)
|
||||
- [Petunjuk Instalasi](https://kernelsu.org/id_ID/guide/installation.html)
|
||||
- [Bagaimana cara membuat?](https://kernelsu.org/id_ID/guide/how-to-build.html)
|
||||
- [Situs Web Resmi](https://kernelsu.org/id_ID/)
|
||||
|
||||
## Terjemahan
|
||||
|
||||
@@ -34,8 +42,8 @@ Untuk menerjemahkan KernelSU ke dalam bahasa Anda atau menyempurnakan terjemahan
|
||||
|
||||
## Lisensi
|
||||
|
||||
- File di bawah direktori `kernel` adalah [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
- File di bawah direktori `kernel` adalah [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Kredit
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | **हिंदी**
|
||||
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | **हिंदी**
|
||||
# KernelSU
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="">
|
||||
<div style="margin-left: 20px;">
|
||||
<span style="font-size: large; "><b>KernelSU</b></span>
|
||||
<br>
|
||||
<span style="font-size: medium; "><i>Android उपकरणों के लिए कर्नेल-आधारित रूट समाधान।</i></span>
|
||||
</div>
|
||||
</div>
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Android उपकरणों के लिए कर्नेल-आधारित रूट समाधान।
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## विशेषताएँ
|
||||
|
||||
1. कर्नेल-आधारित `su` और रूट एक्सेस प्रबंधन।
|
||||
2. Overlayfs पर आधारित मॉड्यूल प्रणाली।
|
||||
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) पर आधारित मॉड्यूल प्रणाली।
|
||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Root शक्ति को पिंजरे में बंद कर दो।
|
||||
|
||||
## अनुकूलता अवस्था
|
||||
@@ -40,8 +42,8 @@ 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` निर्देशिका के अंतर्गत फ़ाइलें हैं [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- `Kernel` निर्देशिका को छोड़कर अन्य सभी भाग हैं [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
## आभार सूची
|
||||
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
פתרון לניהול root מבוסס על Kernel עבור מכשירי Android.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## תכונות
|
||||
|
||||
1. ניהול root ו־`su` מבוססים על Kernel.
|
||||
2. מערכת מודולים מבוססת overlayfs.
|
||||
2. מערכת מודולים מבוססת [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [פרופיל אפליקציה](https://kernelsu.org/guide/app-profile.html): נעילת גישת root בכלוב.
|
||||
|
||||
## מצב תאימות
|
||||
@@ -34,12 +42,12 @@ KernelSU תומך במכשירי Android GKI 2.0 (kernel 5.10+) באופן רש
|
||||
|
||||
## רשיון
|
||||
|
||||
- קבצים תחת הספרייה `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` מוגנים על פי [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- כל החלקים האחרים, למעט הספרייה `kernel`, מוגנים על פי [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## קרדיטים
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): הרעיון של KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): הכלי הסופר חזק לניהול root.
|
||||
- [genuine](https://github.com/brevent/genuine/): אימות חתימת apk v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): כמה יכולות רוט.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): כמה יכולות רוט.
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
@@ -6,19 +6,18 @@
|
||||
|
||||
Android におけるカーネルベースの root ソリューションです。
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## 特徴
|
||||
|
||||
1. カーネルベースの `su` と権限管理
|
||||
2. OverlayFS に基づくモジュールシステム
|
||||
1. カーネルベースの `su` と権限管理。
|
||||
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) に基づくモジュールシステム。
|
||||
3. [アプリのプロファイル](https://kernelsu.org/guide/app-profile.html): root の権限をケージ内に閉じ込めます。
|
||||
|
||||
|
||||
## 対応状況
|
||||
|
||||
KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上)を公式にサポートしています。古いカーネル(4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。
|
||||
@@ -31,7 +30,7 @@ WSA 、ChromeOS とコンテナ上で動作する Android でも KernelSU を統
|
||||
|
||||
- [インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html)
|
||||
- [ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html)
|
||||
- [公式サイト](https://kernelsu.org)
|
||||
- [公式サイト](https://kernelsu.org/ja_JP/)
|
||||
|
||||
## 翻訳
|
||||
|
||||
@@ -43,13 +42,12 @@ 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` ディレクトリの下にあるすべてのファイル: [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。
|
||||
- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。
|
||||
|
||||
## クレジット
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU のアイデア元
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk):強力な root ツール
|
||||
- [genuine](https://github.com/brevent/genuine/):apk v2 の署名検証
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU のアイデア元。
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk):強力な root ツール。
|
||||
- [genuine](https://github.com/brevent/genuine/):apk v2 の署名検証。
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル。
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Polski** | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Polski** | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Rozwiązanie root oparte na jądrze dla urządzeń z systemem Android.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Cechy
|
||||
|
||||
1. Oparte na jądrze `su` i zarządzanie dostępem roota.
|
||||
2. System modułów oparty na overlayfs.
|
||||
2. System modułów oparty na [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
|
||||
## Kompatybilność
|
||||
|
||||
@@ -19,24 +27,29 @@ Aktualnie obsługiwane ABI to : `arm64-v8a` i `x86_64`.
|
||||
|
||||
## Użycie
|
||||
|
||||
[Instalacja](https://kernelsu.org/guide/installation.html)
|
||||
- [Instalacja](https://kernelsu.org/guide/installation.html)
|
||||
- [Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
|
||||
|
||||
## Kompilacja
|
||||
## Tłumaczenie
|
||||
|
||||
[Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
|
||||
Aby pomóc w tłumaczeniu KernelSU lub ulepszyć istniejące tłumaczenia, użyj [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR tłumaczenia Managera nie jest już akceptowany, ponieważ będzie kolidował z Weblate.
|
||||
|
||||
## Dyskusja
|
||||
|
||||
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||
|
||||
## Bezpieczeństwo
|
||||
|
||||
Informacje na temat zgłaszania luk w zabezpieczeniach w KernelSU można znaleźć w pliku [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Licencja
|
||||
|
||||
- Pliki w katalogu `kernel` są na licencji [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
- Pliki w katalogu `kernel` są na licencji [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Podziękowania
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): pomysłodawca KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.
|
||||
- [genuine](https://github.com/brevent/genuine/): walidacja podpisu apk v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): cenna znajomość rootkitów.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
@@ -6,21 +6,19 @@
|
||||
|
||||
Uma solução root baseada em kernel para dispositivos Android.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Características
|
||||
|
||||
1. `su` e gerenciamento de acesso root baseado em kernel.
|
||||
|
||||
2. Sistema modular baseado em overlayfs.
|
||||
|
||||
2. Sistema modular baseado em [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Perfil do Aplicativo](https://kernelsu.org/pt_BR/guide/app-profile.html): Tranque o poder root em uma gaiola.
|
||||
|
||||
## Estado de Compatibilidade
|
||||
## Estado de compatibilidade
|
||||
|
||||
O KernelSU oferece suporte oficial a dispositivos Android GKI 2.0 (kernel 5.10+). Kernels mais antigos (4.14+) também são compatíveis, mas o kernel terá que ser construído manualmente.
|
||||
|
||||
@@ -29,22 +27,27 @@ Com isso, WSA, ChromeOS e Android baseado em contêiner são todos suportados.
|
||||
Atualmente, apenas `arm64-v8a` e `x86_64` são suportados.
|
||||
|
||||
## Uso
|
||||
|
||||
- [Instalação](https://kernelsu.org/pt_BR/guide/installation.html)
|
||||
- [Como construir o KernelSU?](https://kernelsu.org/pt_BR/guide/how-to-build.html)
|
||||
- [Site oficial](https://kernelsu.org/pt_BR/)
|
||||
|
||||
## Tradução
|
||||
|
||||
Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, utilize o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Gerenciador não são mais aceitas, pois podem entrar em conflito com o Weblate.
|
||||
|
||||
## Discussão
|
||||
|
||||
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||
|
||||
## Segurança
|
||||
|
||||
Para obter informações sobre como relatar vulnerabilidades de segurança do KernelSU, consulte [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Licença
|
||||
|
||||
- Os arquivos no diretório `kernel` são [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
|
||||
- Todas as outras partes, exceto o diretório `kernel` são [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
- Os arquivos no diretório `kernel` são [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Todas as outras partes, exceto o diretório `kernel` são [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Créditos
|
||||
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Решение на основе ядра root для Android-устройств.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Особенности
|
||||
|
||||
1. Управление `su` и root-доступом на основе ядра.
|
||||
2. Система модулей на основе overlayfs.
|
||||
2. Система модулей на основе [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Профиль приложений](https://kernelsu.org/ru_RU/guide/app-profile.html): Запри корневую силу в клетке.
|
||||
|
||||
## Совместимость
|
||||
|
||||
@@ -19,11 +28,9 @@ WSA и Android на основе контейнеров также должны
|
||||
|
||||
## Использование
|
||||
|
||||
[Установка](https://kernelsu.org/ru_RU/guide/installation.html)
|
||||
|
||||
## Сборка
|
||||
|
||||
[Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
|
||||
- [Установка](https://kernelsu.org/ru_RU/guide/installation.html)
|
||||
- [Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
|
||||
- [официальный сайт](https://kernelsu.org/ru_RU/)
|
||||
|
||||
## Обсуждение
|
||||
|
||||
@@ -31,12 +38,12 @@ WSA и Android на основе контейнеров также должны
|
||||
|
||||
## Лицензия
|
||||
|
||||
- Файлы в директории `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` [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Все остальные части, кроме директории `kernel` [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Благодарности
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): идея KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): реализация sepolicy.
|
||||
- [genuine](https://github.com/brevent/genuine/): проверка подписи apk v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): некоторые навыки руткита.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): реализация sepolicy.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
@@ -6,17 +6,16 @@
|
||||
|
||||
Android cihazlar için kernel tabanlı root çözümü.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
|
||||
## Özellikler
|
||||
|
||||
1. Kernel-tabanlı `su` ve root erişimi yönetimi.
|
||||
2. Overlayfs'ye dayalı modül sistemi.
|
||||
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)'ye dayalı modül sistemi.
|
||||
3. [Uygulama profili](https://kernelsu.org/guide/app-profile.html): Root gücünü bir kafese kapatın.
|
||||
|
||||
## Uyumluluk Durumu
|
||||
@@ -41,10 +40,14 @@ KernelSU'nun çevirisine veya mevcut çevirilerin iyileştirilmesine yardımcı
|
||||
|
||||
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||
|
||||
## Güvenlik
|
||||
|
||||
KernelSU'daki güvenlik açıklarını bildirme hakkında bilgi için, bkz [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Lisans
|
||||
|
||||
- `kernel` klasöründeki dosyalar [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır.
|
||||
- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
|
||||
- `kernel` klasöründeki dosyalar [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır.
|
||||
- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3-veya-sonraki](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
|
||||
|
||||
## Krediler
|
||||
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
一個基於核心的 Android 裝置 Root 解決方案
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## 功能
|
||||
|
||||
- 基於核心的 Su 和 Root 存取權管理。
|
||||
- 基於 Overlayfs 的模組系統。
|
||||
- 基於核心的 `su` 和 Root 存取權管理。
|
||||
- 基於 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模組系統。
|
||||
|
||||
## 相容性狀態
|
||||
|
||||
@@ -15,15 +23,12 @@ KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+);舊版核
|
||||
|
||||
WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
|
||||
|
||||
目前支援架構:`arm64-v8a` 和 `x86_64`
|
||||
目前支援架構:`arm64-v8a` 和 `x86_64`。
|
||||
|
||||
## 使用方法
|
||||
|
||||
[安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
|
||||
|
||||
## 建置
|
||||
|
||||
[如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
|
||||
- [安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
|
||||
- [如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
|
||||
|
||||
### 討論
|
||||
|
||||
@@ -31,12 +36,12 @@ WSA 和執行在容器中的 Android 也可以與 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` 下所有檔案為 [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。
|
||||
- 除 `kernel` 目錄的其他部分均為 [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。
|
||||
|
||||
## 致謝
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU 的靈感。
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk):sepolicy 實作。
|
||||
- [genuine](https://github.com/brevent/genuine/):apk v2 簽章驗證。
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk):sepolicy 實作。
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
|
||||
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||
|
||||
# KernelSU
|
||||
|
||||
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Giải pháp root thông qua thay đổi trên Kernel hệ điều hành cho các thiết bị Android.
|
||||
|
||||
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||
[](https://hosted.weblate.org/engage/kernelsu)
|
||||
[](https://t.me/KernelSU)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Tính năng
|
||||
|
||||
1. Hỗ trợ gói thực thi `su` và quản lý quyền root.
|
||||
2. Hệ thống mô-đun thông qua overlayfs.
|
||||
2. Hệ thống mô-đun thông qua [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Hạn chế quyền root của ứng dụng.
|
||||
|
||||
## Tình trạng tương thích
|
||||
@@ -16,7 +24,7 @@ KernelSU chính thức hỗ trợ các thiết bị Android với kernel GKI 2.0
|
||||
|
||||
WSA, ChromeOS và Android dựa trên container(container-based) cũng được hỗ trợ bởi KernelSU.
|
||||
|
||||
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a` và `x86_64`
|
||||
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a` và `x86_64`.
|
||||
|
||||
## Sử dụng
|
||||
|
||||
@@ -34,12 +42,12 @@ Nếu bạn muốn hỗ trợ dịch KernelSU sang một ngôn ngữ khác hoặ
|
||||
|
||||
## Giấy phép
|
||||
|
||||
- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- Tất cả các thành phần khác ngoại trừ thư mục `kernel` dùng giấy phép [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Tất cả các thành phần khác ngoại trừ thư mục `kernel` dùng giấy phép [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Lời cảm ơn
|
||||
|
||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ý tưởng cho KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): công cụ root mạnh mẽ.
|
||||
- [genuine](https://github.com/brevent/genuine/): phương pháp xác thực apk v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit .
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit.
|
||||
|
||||
111
js/README.md
Normal file
111
js/README.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Library for KernelSU's module WebUI
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
yarn add kernelsu
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### exec
|
||||
|
||||
Spawns a **root** shell and runs a command within that shell, passing the `stdout` and `stderr` to a Promise when complete.
|
||||
|
||||
- `command` `<string>` The command to run, with space-separated arguments.
|
||||
- `options` `<Object>`
|
||||
- `cwd` - Current working directory of the child process
|
||||
- `env` - Environment key-value pairs
|
||||
|
||||
```javascript
|
||||
import { exec } from 'kernelsu';
|
||||
|
||||
const { errno, stdout, stderr } = await exec('ls -l', { cwd: '/tmp' });
|
||||
if (errno === 0) {
|
||||
// success
|
||||
console.log(stdout);
|
||||
}
|
||||
```
|
||||
|
||||
### spawn
|
||||
|
||||
Spawns a new process using the given `command` in **root** shell, with command-line arguments in `args`. If omitted, `args` defaults to an empty array.
|
||||
|
||||
Returns a `ChildProcess`, Instances of the ChildProcess represent spawned child processes.
|
||||
|
||||
- `command` `<string>` The command to run.
|
||||
- `args` `<string[]>` List of string arguments.
|
||||
- `options` `<Object>`:
|
||||
- `cwd` `<string>` - Current working directory of the child process
|
||||
- `env` `<Object>` - Environment key-value pairs
|
||||
|
||||
Example of running `ls -lh /data`, capturing `stdout`, `stderr`, and the exit code:
|
||||
|
||||
```javascript
|
||||
import { spawn } from 'kernelsu';
|
||||
|
||||
const ls = spawn('ls', ['-lh', '/data']);
|
||||
|
||||
ls.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
});
|
||||
|
||||
ls.stderr.on('data', (data) => {
|
||||
console.log(`stderr: ${data}`);
|
||||
});
|
||||
|
||||
ls.on('exit', (code) => {
|
||||
console.log(`child process exited with code ${code}`);
|
||||
});
|
||||
```
|
||||
|
||||
#### ChildProcess
|
||||
|
||||
##### Event 'exit'
|
||||
|
||||
- `code` `<number>` The exit code if the child exited on its own.
|
||||
|
||||
The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise null
|
||||
|
||||
##### Event 'error'
|
||||
|
||||
- `err` `<Error>` The error.
|
||||
|
||||
The `'error'` event is emitted whenever:
|
||||
|
||||
- The process could not be spawned.
|
||||
- The process could not be killed.
|
||||
|
||||
##### `stdout`
|
||||
|
||||
A `Readable Stream` that represents the child process's `stdout`.
|
||||
|
||||
```javascript
|
||||
const subprocess = spawn('ls');
|
||||
|
||||
subprocess.stdout.on('data', (data) => {
|
||||
console.log(`Received chunk ${data}`);
|
||||
});
|
||||
```
|
||||
|
||||
#### `stderr`
|
||||
|
||||
A `Readable Stream` that represents the child process's `stderr`.
|
||||
|
||||
### fullScreen
|
||||
|
||||
Request the WebView enter/exit full screen.
|
||||
|
||||
```javascript
|
||||
import { fullScreen } from 'kernelsu';
|
||||
fullScreen(true);
|
||||
```
|
||||
|
||||
### toast
|
||||
|
||||
Show a toast message.
|
||||
|
||||
```javascript
|
||||
import { toast } from 'kernelsu';
|
||||
toast('Hello, world!');
|
||||
```
|
||||
115
js/index.js
Normal file
115
js/index.js
Normal file
@@ -0,0 +1,115 @@
|
||||
let callbackCounter = 0;
|
||||
function getUniqueCallbackName(prefix) {
|
||||
return `${prefix}_callback_${Date.now()}_${callbackCounter++}`;
|
||||
}
|
||||
|
||||
export function exec(command, options) {
|
||||
if (typeof options === "undefined") {
|
||||
options = {};
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// Generate a unique callback function name
|
||||
const callbackFuncName = getUniqueCallbackName("exec");
|
||||
|
||||
// Define the success callback function
|
||||
window[callbackFuncName] = (errno, stdout, stderr) => {
|
||||
resolve({ errno, stdout, stderr });
|
||||
cleanup(callbackFuncName);
|
||||
};
|
||||
|
||||
function cleanup(successName) {
|
||||
delete window[successName];
|
||||
}
|
||||
|
||||
try {
|
||||
ksu.exec(command, JSON.stringify(options), callbackFuncName);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
cleanup(callbackFuncName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function Stdio() {
|
||||
this.listeners = {};
|
||||
}
|
||||
|
||||
Stdio.prototype.on = function (event, listener) {
|
||||
if (!this.listeners[event]) {
|
||||
this.listeners[event] = [];
|
||||
}
|
||||
this.listeners[event].push(listener);
|
||||
};
|
||||
|
||||
Stdio.prototype.emit = function (event, ...args) {
|
||||
if (this.listeners[event]) {
|
||||
this.listeners[event].forEach((listener) => listener(...args));
|
||||
}
|
||||
};
|
||||
|
||||
function ChildProcess() {
|
||||
this.listeners = {};
|
||||
this.stdin = new Stdio();
|
||||
this.stdout = new Stdio();
|
||||
this.stderr = new Stdio();
|
||||
}
|
||||
|
||||
ChildProcess.prototype.on = function (event, listener) {
|
||||
if (!this.listeners[event]) {
|
||||
this.listeners[event] = [];
|
||||
}
|
||||
this.listeners[event].push(listener);
|
||||
};
|
||||
|
||||
ChildProcess.prototype.emit = function (event, ...args) {
|
||||
if (this.listeners[event]) {
|
||||
this.listeners[event].forEach((listener) => listener(...args));
|
||||
}
|
||||
};
|
||||
|
||||
export function spawn(command, args, options) {
|
||||
if (typeof args === "undefined") {
|
||||
args = [];
|
||||
} else if (typeof args === "object") {
|
||||
// allow for (command, options) signature
|
||||
options = args;
|
||||
}
|
||||
|
||||
if (typeof options === "undefined") {
|
||||
options = {};
|
||||
}
|
||||
|
||||
const child = new ChildProcess();
|
||||
const childCallbackName = getUniqueCallbackName("spawn");
|
||||
window[childCallbackName] = child;
|
||||
|
||||
function cleanup(name) {
|
||||
delete window[name];
|
||||
}
|
||||
|
||||
child.on("exit", code => {
|
||||
cleanup(childCallbackName);
|
||||
});
|
||||
|
||||
try {
|
||||
ksu.spawn(
|
||||
command,
|
||||
JSON.stringify(args),
|
||||
JSON.stringify(options),
|
||||
childCallbackName
|
||||
);
|
||||
} catch (error) {
|
||||
child.emit("error", error);
|
||||
cleanup(childCallbackName);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
export function fullScreen(isFullScreen) {
|
||||
ksu.fullScreen(isFullScreen);
|
||||
}
|
||||
|
||||
export function toast(message) {
|
||||
ksu.toast(message);
|
||||
}
|
||||
25
js/package.json
Normal file
25
js/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "kernelsu",
|
||||
"version": "1.0.6",
|
||||
"description": "Library for KernelSU's module WebUI",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "npm run test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tiann/KernelSU.git"
|
||||
},
|
||||
"keywords": [
|
||||
"su",
|
||||
"kernelsu",
|
||||
"module",
|
||||
"webui"
|
||||
],
|
||||
"author": "weishu",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/tiann/KernelSU/issues"
|
||||
},
|
||||
"homepage": "https://github.com/tiann/KernelSU#readme"
|
||||
}
|
||||
10
justfile
Normal file
10
justfile
Normal file
@@ -0,0 +1,10 @@
|
||||
alias bk := build_ksud
|
||||
alias bm := build_manager
|
||||
|
||||
build_ksud:
|
||||
cross build --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml
|
||||
|
||||
build_manager: build_ksud
|
||||
cp userspace/ksud/target/aarch64-linux-android/release/ksud manager/app/src/main/jniLibs/arm64-v8a/libksud.so
|
||||
cd manager && ./gradlew aDebug
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "uid_observer.h"
|
||||
#include "kernel_compat.h"
|
||||
|
||||
static bool ksu_module_mounted = false;
|
||||
|
||||
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
|
||||
|
||||
static inline bool is_allow_su()
|
||||
@@ -126,7 +128,8 @@ void escape_to_root(void)
|
||||
// setup capabilities
|
||||
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
|
||||
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
|
||||
u64 cap_for_ksud = profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
||||
u64 cap_for_ksud =
|
||||
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
||||
memcpy(&cred->cap_effective, &cap_for_ksud,
|
||||
sizeof(cred->cap_effective));
|
||||
memcpy(&cred->cap_inheritable, &profile->capabilities.effective,
|
||||
@@ -241,7 +244,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
pr_err("become_manager: copy param err\n");
|
||||
#endif
|
||||
return 0;
|
||||
goto block;
|
||||
}
|
||||
|
||||
// for user 0, it is /data/data
|
||||
@@ -259,7 +262,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
|
||||
if (startswith(param, (char *)prefix) != 0) {
|
||||
pr_info("become_manager: invalid param: %s\n", param);
|
||||
return 0;
|
||||
goto block;
|
||||
}
|
||||
|
||||
// stat the param, app must have permission to do this
|
||||
@@ -267,12 +270,13 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
struct path path;
|
||||
if (kern_path(param, LOOKUP_DIRECTORY, &path)) {
|
||||
pr_err("become_manager: kern_path err\n");
|
||||
return 0;
|
||||
goto block;
|
||||
}
|
||||
if (path.dentry->d_inode->i_uid.val != current_uid().val) {
|
||||
uid_t inode_uid = path.dentry->d_inode->i_uid.val;
|
||||
path_put(&path);
|
||||
if (inode_uid != current_uid().val) {
|
||||
pr_err("become_manager: path uid != current uid\n");
|
||||
path_put(&path);
|
||||
return 0;
|
||||
goto block;
|
||||
}
|
||||
char *pkg = param + strlen(prefix);
|
||||
pr_info("become_manager: param pkg: %s\n", pkg);
|
||||
@@ -282,8 +286,10 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||
pr_err("become_manager: prctl reply error\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
path_put(&path);
|
||||
block:
|
||||
last_failed_uid = current_uid().val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -331,6 +337,11 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_MODULE_MOUNTED: {
|
||||
ksu_module_mounted = true;
|
||||
pr_info("module mounted!\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -522,6 +533,11 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
|
||||
|
||||
int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
{
|
||||
// this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
|
||||
if (!ksu_module_mounted) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!new || !old) {
|
||||
return 0;
|
||||
}
|
||||
@@ -557,11 +573,13 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
// when we umount for such process, that is a disaster!
|
||||
bool is_zygote_child = is_zygote(old->security);
|
||||
if (!is_zygote_child) {
|
||||
pr_info("handle umount ignore non zygote child: %d\n", current->pid);
|
||||
pr_info("handle umount ignore non zygote child: %d\n",
|
||||
current->pid);
|
||||
return 0;
|
||||
}
|
||||
// umount the target mnt
|
||||
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, current->pid);
|
||||
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val,
|
||||
current->pid);
|
||||
|
||||
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
|
||||
// filter the mountpoint whose target is `/data/adb`
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#define EVENT_POST_FS_DATA 1
|
||||
#define EVENT_BOOT_COMPLETED 2
|
||||
#define EVENT_MODULE_MOUNTED 3
|
||||
|
||||
#define KSU_APP_PROFILE_VER 2
|
||||
#define KSU_MAX_PACKAGE_NAME 256
|
||||
|
||||
@@ -84,6 +84,7 @@ void apply_kernelsu_rules()
|
||||
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
|
||||
// our ksud triggered by init
|
||||
ksu_allow(db, "init", "adb_data_file", "file", ALL);
|
||||
ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289
|
||||
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);
|
||||
// we need to umount modules in zygote
|
||||
ksu_allow(db, "zygote", "adb_data_file", "dir", "search");
|
||||
@@ -130,6 +131,10 @@ void apply_kernelsu_rules()
|
||||
ksu_allow(db, "system_server", "untrusted_app_all_devpts", "chr_file",
|
||||
"write");
|
||||
|
||||
// Allow system server kill su process
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -103,11 +103,14 @@ bool is_ksu_domain()
|
||||
{
|
||||
char *domain;
|
||||
u32 seclen;
|
||||
bool result;
|
||||
int err = security_secid_to_secctx(current_sid(), &domain, &seclen);
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
return strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0;
|
||||
result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0;
|
||||
security_release_secctx(domain, seclen);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_zygote(void *sec)
|
||||
@@ -118,9 +121,12 @@ bool is_zygote(void *sec)
|
||||
}
|
||||
char *domain;
|
||||
u32 seclen;
|
||||
bool result;
|
||||
int err = security_secid_to_secctx(tsec->sid, &domain, &seclen);
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
return strncmp("u:r:zygote:s0", domain, seclen) == 0;
|
||||
result = strncmp("u:r:zygote:s0", domain, seclen) == 0;
|
||||
security_release_secctx(domain, seclen);
|
||||
return result;
|
||||
}
|
||||
@@ -44,7 +44,7 @@ echo '[+] Add kernel su driver to Makefile'
|
||||
|
||||
DRIVER_MAKEFILE=$DRIVER_DIR/Makefile
|
||||
DRIVER_KCONFIG=$DRIVER_DIR/Kconfig
|
||||
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "obj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
|
||||
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
|
||||
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
|
||||
|
||||
echo '[+] Done.'
|
||||
echo '[+] Done.'
|
||||
|
||||
@@ -93,12 +93,14 @@ dependencies {
|
||||
implementation(libs.com.google.accompanist.drawablepainter)
|
||||
implementation(libs.com.google.accompanist.navigation.animation)
|
||||
implementation(libs.com.google.accompanist.systemuicontroller)
|
||||
implementation(libs.com.google.accompanist.webview)
|
||||
|
||||
implementation(libs.compose.destinations.animations.core)
|
||||
ksp(libs.compose.destinations.ksp)
|
||||
|
||||
implementation(libs.com.github.topjohnwu.libsu.core)
|
||||
implementation(libs.com.github.topjohnwu.libsu.service)
|
||||
implementation(libs.com.github.topjohnwu.libsu.io)
|
||||
|
||||
implementation(libs.dev.rikka.rikkax.parcelablelist)
|
||||
|
||||
@@ -113,4 +115,5 @@ dependencies {
|
||||
implementation(libs.sheet.compose.dialogs.input)
|
||||
|
||||
implementation(libs.markdown)
|
||||
implementation(libs.androidx.webkit)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:theme="@style/Theme.KernelSU"
|
||||
tools:targetApi="33">
|
||||
<activity
|
||||
|
||||
@@ -5,6 +5,7 @@ import coil.Coil
|
||||
import coil.ImageLoader
|
||||
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
|
||||
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
|
||||
import java.io.File
|
||||
|
||||
lateinit var ksuApp: KernelSUApplication
|
||||
|
||||
@@ -24,6 +25,11 @@ class KernelSUApplication : Application() {
|
||||
}
|
||||
.build()
|
||||
)
|
||||
|
||||
val webroot = File(dataDir, "webroot")
|
||||
if (!webroot.exists()) {
|
||||
webroot.mkdir()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||
import com.ramcosta.composedestinations.navigation.popBackStack
|
||||
@@ -32,6 +33,7 @@ import me.weishu.kernelsu.ui.screen.NavGraphs
|
||||
import me.weishu.kernelsu.ui.theme.KernelSUTheme
|
||||
import me.weishu.kernelsu.ui.util.LocalDialogHost
|
||||
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
|
||||
import me.weishu.kernelsu.ui.util.rootAvailable
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
@@ -43,8 +45,11 @@ class MainActivity : ComponentActivity() {
|
||||
KernelSUTheme {
|
||||
val navController = rememberAnimatedNavController()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
val route = navBackStackEntry?.destination?.route
|
||||
val showBottomBar = route == null || !route.startsWith("web_screen")
|
||||
Scaffold(
|
||||
bottomBar = { BottomBar(navController) },
|
||||
bottomBar = { if (showBottomBar) BottomBar(navController) },
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) }
|
||||
) { innerPadding ->
|
||||
CompositionLocalProvider(
|
||||
@@ -66,7 +71,7 @@ class MainActivity : ComponentActivity() {
|
||||
@Composable
|
||||
private fun BottomBar(navController: NavHostController) {
|
||||
val isManager = Natives.becomeManager(ksuApp.packageName)
|
||||
val fullFeatured = isManager && !Natives.requireNewKernel()
|
||||
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
|
||||
NavigationBar(tonalElevation = 8.dp) {
|
||||
BottomBarDestination.values().forEach { destination ->
|
||||
if (!fullFeatured && destination.rootRequired) return@forEach
|
||||
|
||||
@@ -191,14 +191,19 @@ fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>)
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (showDialog) {
|
||||
val groups = Groups.values().sortedWith(compareBy<Groups> {
|
||||
when (it) {
|
||||
Groups.ROOT -> 0
|
||||
Groups.SYSTEM -> 1
|
||||
Groups.SHELL -> 2
|
||||
else -> Int.MAX_VALUE
|
||||
}
|
||||
}.then(compareBy { it.name }))
|
||||
val groups = Groups.values().sortedWith(
|
||||
compareBy<Groups> { if (selected.contains(it)) 0 else 1 }
|
||||
.then(compareBy {
|
||||
when (it) {
|
||||
Groups.ROOT -> 0
|
||||
Groups.SYSTEM -> 1
|
||||
Groups.SHELL -> 2
|
||||
else -> Int.MAX_VALUE
|
||||
}
|
||||
})
|
||||
.then(compareBy { it.name })
|
||||
|
||||
)
|
||||
val options = groups.map { value ->
|
||||
ListOption(
|
||||
titleText = value.display,
|
||||
@@ -264,7 +269,10 @@ fun CapsPanel(
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (showDialog) {
|
||||
val caps = Capabilities.values().sortedBy { it.name }
|
||||
val caps = Capabilities.values().sortedWith(
|
||||
compareBy<Capabilities> { if (selected.contains(it)) 0 else 1 }
|
||||
.then(compareBy { it.name })
|
||||
)
|
||||
val options = caps.map { value ->
|
||||
ListOption(
|
||||
titleText = value.display,
|
||||
|
||||
@@ -69,7 +69,17 @@ fun HomeScreen(navigator: DestinationsNavigator) {
|
||||
)
|
||||
)
|
||||
}
|
||||
UpdateCard()
|
||||
if (!rootAvailable()) {
|
||||
WarningCard(
|
||||
stringResource(id = R.string.grant_root_failed)
|
||||
)
|
||||
}
|
||||
val checkUpdate =
|
||||
LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE)
|
||||
.getBoolean("check_update", true)
|
||||
if (checkUpdate) {
|
||||
UpdateCard()
|
||||
}
|
||||
InfoCard()
|
||||
DonateCard()
|
||||
LearnMoreCard()
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -43,6 +44,7 @@ import me.weishu.kernelsu.ui.component.ConfirmDialog
|
||||
import me.weishu.kernelsu.ui.component.ConfirmResult
|
||||
import me.weishu.kernelsu.ui.component.LoadingDialog
|
||||
import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
|
||||
import me.weishu.kernelsu.ui.screen.destinations.WebScreenDestination
|
||||
import me.weishu.kernelsu.ui.util.*
|
||||
import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -122,10 +124,15 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
||||
ModuleList(
|
||||
viewModel = viewModel, modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
navigator.navigate(InstallScreenDestination(it))
|
||||
}
|
||||
.fillMaxSize(),
|
||||
onInstallModule =
|
||||
{
|
||||
navigator.navigate(InstallScreenDestination(it))
|
||||
}, onClickModule = { id, name, hasWebUi ->
|
||||
if (hasWebUi) {
|
||||
navigator.navigate(WebScreenDestination(id, name))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +141,10 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun ModuleList(
|
||||
viewModel: ModuleViewModel, modifier: Modifier = Modifier, onInstallModule: (Uri) -> Unit
|
||||
viewModel: ModuleViewModel,
|
||||
modifier: Modifier = Modifier,
|
||||
onInstallModule: (Uri) -> Unit,
|
||||
onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit
|
||||
) {
|
||||
val failedEnable = stringResource(R.string.module_failed_to_enable)
|
||||
val failedDisable = stringResource(R.string.module_failed_to_disable)
|
||||
@@ -172,7 +182,7 @@ private fun ModuleList(
|
||||
}
|
||||
}
|
||||
|
||||
val showToast: suspend (String) -> Unit = {msg->
|
||||
val showToast: suspend (String) -> Unit = { msg ->
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
@@ -346,6 +356,8 @@ private fun ModuleList(
|
||||
"${module.name}-${updatedModule.second}.zip"
|
||||
)
|
||||
}
|
||||
}, onClick = {
|
||||
onClickModule(it.id, it.name, it.hasWebUi)
|
||||
})
|
||||
|
||||
// fix last item shadow incomplete in LazyColumn
|
||||
@@ -379,9 +391,12 @@ private fun ModuleItem(
|
||||
onUninstall: (ModuleViewModel.ModuleInfo) -> Unit,
|
||||
onCheckChanged: (Boolean) -> Unit,
|
||||
onUpdate: (ModuleViewModel.ModuleInfo) -> Unit,
|
||||
onClick: (ModuleViewModel.ModuleInfo) -> Unit
|
||||
) {
|
||||
ElevatedCard(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick(module) },
|
||||
colors = CardDefaults.elevatedCardColors(containerColor = MaterialTheme.colorScheme.surface)
|
||||
) {
|
||||
|
||||
@@ -487,6 +502,18 @@ private fun ModuleItem(
|
||||
text = stringResource(R.string.uninstall),
|
||||
)
|
||||
}
|
||||
|
||||
if (module.hasWebUi) {
|
||||
TextButton(
|
||||
onClick = { onClick(module) },
|
||||
) {
|
||||
Text(
|
||||
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
|
||||
fontSize = MaterialTheme.typography.labelMedium.fontSize,
|
||||
text = stringResource(R.string.open),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -505,7 +532,8 @@ fun ModuleItemPreview() {
|
||||
enabled = true,
|
||||
update = true,
|
||||
remove = true,
|
||||
updateJson = ""
|
||||
updateJson = "",
|
||||
hasWebUi = false,
|
||||
)
|
||||
ModuleItem(module, true, "", {}, {}, {})
|
||||
ModuleItem(module, true, "", {}, {}, {}, {})
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.weishu.kernelsu.ui.screen
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -10,6 +11,8 @@ import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.material.icons.filled.ContactPage
|
||||
import androidx.compose.material.icons.filled.Fence
|
||||
import androidx.compose.material.icons.filled.RemoveModerator
|
||||
import androidx.compose.material.icons.filled.Update
|
||||
import androidx.compose.material.icons.filled.Upgrade
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
@@ -62,9 +65,9 @@ fun SettingScreen(navigator: DestinationsNavigator) {
|
||||
ListItem(
|
||||
leadingContent = { Icon(Icons.Filled.Fence, profileTemplate) },
|
||||
headlineContent = { Text(profileTemplate) },
|
||||
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary))},
|
||||
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary)) },
|
||||
modifier = Modifier.clickable {
|
||||
navigator.navigate(AppProfileTemplateScreenDestination)
|
||||
navigator.navigate(AppProfileTemplateScreenDestination)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -82,8 +85,30 @@ fun SettingScreen(navigator: DestinationsNavigator) {
|
||||
}
|
||||
}
|
||||
|
||||
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
|
||||
var checkUpdate by rememberSaveable {
|
||||
mutableStateOf(
|
||||
prefs.getBoolean("check_update", true)
|
||||
)
|
||||
}
|
||||
SwitchItem(
|
||||
icon = Icons.Filled.Update,
|
||||
title = stringResource(id = R.string.settings_check_update),
|
||||
summary = stringResource(id = R.string.settings_check_update_summary),
|
||||
checked = checkUpdate
|
||||
) {
|
||||
prefs.edit().putBoolean("check_update", it).apply()
|
||||
checkUpdate = it
|
||||
}
|
||||
|
||||
|
||||
ListItem(
|
||||
leadingContent = { Icon(Icons.Filled.BugReport, stringResource(id = R.string.send_log)) },
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Filled.BugReport,
|
||||
stringResource(id = R.string.send_log)
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(stringResource(id = R.string.send_log)) },
|
||||
modifier = Modifier.clickable {
|
||||
scope.launch {
|
||||
@@ -117,7 +142,12 @@ fun SettingScreen(navigator: DestinationsNavigator) {
|
||||
|
||||
val about = stringResource(id = R.string.about)
|
||||
ListItem(
|
||||
leadingContent = { Icon(Icons.Filled.ContactPage, stringResource(id = R.string.about)) },
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Filled.ContactPage,
|
||||
stringResource(id = R.string.about)
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(about) },
|
||||
modifier = Modifier.clickable {
|
||||
showAboutDialog.value = true
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package me.weishu.kernelsu.ui.screen
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebResourceResponse
|
||||
import android.webkit.WebView
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.webkit.WebViewAssetLoader
|
||||
import com.google.accompanist.web.AccompanistWebViewClient
|
||||
import com.google.accompanist.web.WebView
|
||||
import com.google.accompanist.web.rememberWebViewState
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import me.weishu.kernelsu.ui.webui.SuFilePathHandler
|
||||
import me.weishu.kernelsu.ui.webui.WebViewInterface
|
||||
import me.weishu.kernelsu.ui.webui.showSystemUI
|
||||
import java.io.File
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Destination
|
||||
@Composable
|
||||
fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: String) {
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
if (WebViewInterface.isHideSystemUI && context is Activity) {
|
||||
showSystemUI(context.window)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold { innerPadding ->
|
||||
val webRoot = File("/data/adb/modules/${moduleId}/webroot")
|
||||
val webViewAssetLoader = WebViewAssetLoader.Builder()
|
||||
.setDomain("mui.kernelsu.org")
|
||||
.addPathHandler("/",
|
||||
SuFilePathHandler(context, webRoot)
|
||||
)
|
||||
.build()
|
||||
|
||||
val webViewClient = object : AccompanistWebViewClient() {
|
||||
override fun shouldInterceptRequest(
|
||||
view: WebView,
|
||||
request: WebResourceRequest
|
||||
): WebResourceResponse? {
|
||||
return webViewAssetLoader.shouldInterceptRequest(request.url)
|
||||
}
|
||||
}
|
||||
WebView(
|
||||
state = rememberWebViewState(url = "https://mui.kernelsu.org/index.html"),
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding),
|
||||
client = webViewClient,
|
||||
factory = { context ->
|
||||
WebView(context).apply {
|
||||
settings.javaScriptEnabled = true
|
||||
settings.domStorageEnabled = true
|
||||
settings.allowFileAccess = false
|
||||
addJavascriptInterface(WebViewInterface(context, this), "ksu")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -25,17 +25,24 @@ private fun getKsuDaemonPath(): String {
|
||||
|
||||
object KsuCli {
|
||||
val SHELL: Shell = createRootShell()
|
||||
val GLOBAL_MNT_SHELL: Shell = createRootShell(true)
|
||||
}
|
||||
|
||||
fun getRootShell(): Shell {
|
||||
return KsuCli.SHELL
|
||||
fun getRootShell(globalMnt: Boolean = false): Shell {
|
||||
return if (globalMnt) KsuCli.GLOBAL_MNT_SHELL else {
|
||||
KsuCli.SHELL
|
||||
}
|
||||
}
|
||||
|
||||
fun createRootShell(): Shell {
|
||||
fun createRootShell(globalMnt: Boolean = false): Shell {
|
||||
Shell.enableVerboseLogging = BuildConfig.DEBUG
|
||||
val builder = Shell.Builder.create()
|
||||
return try {
|
||||
builder.build(getKsuDaemonPath(), "debug", "su")
|
||||
if (globalMnt) {
|
||||
builder.build(getKsuDaemonPath(), "debug", "su", "-g")
|
||||
} else {
|
||||
builder.build(getKsuDaemonPath(), "debug", "su")
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.e(TAG, "su failed: ", e)
|
||||
builder.build("sh")
|
||||
@@ -105,7 +112,7 @@ fun installModule(
|
||||
}
|
||||
val cmd = "module install ${file.absolutePath}"
|
||||
|
||||
val shell = getRootShell()
|
||||
val shell = createRootShell()
|
||||
|
||||
val stdoutCallback: CallbackList<String?> = object : CallbackList<String?>() {
|
||||
override fun onAddElement(s: String?) {
|
||||
@@ -140,6 +147,11 @@ fun reboot(reason: String = "") {
|
||||
ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason")
|
||||
}
|
||||
|
||||
fun rootAvailable(): Boolean {
|
||||
val shell = getRootShell()
|
||||
return shell.isRoot
|
||||
}
|
||||
|
||||
fun overlayFsAvailable(): Boolean {
|
||||
val shell = getRootShell()
|
||||
// check /proc/filesystems
|
||||
@@ -147,8 +159,8 @@ fun overlayFsAvailable(): Boolean {
|
||||
}
|
||||
|
||||
fun hasMagisk(): Boolean {
|
||||
val shell = getRootShell()
|
||||
val result = shell.newJob().add("nsenter --mount=/proc/1/ns/mnt which magisk").exec()
|
||||
val shell = getRootShell(true)
|
||||
val result = shell.newJob().add("which magisk").exec()
|
||||
Log.i(TAG, "has magisk: ${result.isSuccess}")
|
||||
return result.isSuccess
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ fun getBugreportFile(context: Context): File {
|
||||
val bootlogFile = File(bugreportDir, "bootlog.tar.gz")
|
||||
val mountsFile = File(bugreportDir, "mounts.txt")
|
||||
val fileSystemsFile = File(bugreportDir, "filesystems.txt")
|
||||
val ksuFileTree = File(bugreportDir, "ksu_tree.txt")
|
||||
val adbFileTree = File(bugreportDir, "adb_tree.txt")
|
||||
val adbFileDetails = File(bugreportDir, "adb_details.txt")
|
||||
val ksuFileSize = File(bugreportDir, "ksu_size.txt")
|
||||
val appListFile = File(bugreportDir, "packages.txt")
|
||||
val propFile = File(bugreportDir, "props.txt")
|
||||
val allowListFile = File(bugreportDir, "allowlist.bin")
|
||||
@@ -34,7 +36,7 @@ fun getBugreportFile(context: Context): File {
|
||||
val bootConfig = File(bugreportDir, "boot_config.txt")
|
||||
val kernelConfig = File(bugreportDir, "defconfig.gz")
|
||||
|
||||
val shell = getRootShell()
|
||||
val shell = getRootShell(true)
|
||||
|
||||
shell.newJob().add("dmesg > ${dmesgFile.absolutePath}").exec()
|
||||
shell.newJob().add("logcat -d > ${logcatFile.absolutePath}").exec()
|
||||
@@ -46,7 +48,9 @@ fun getBugreportFile(context: Context): File {
|
||||
|
||||
shell.newJob().add("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec()
|
||||
shell.newJob().add("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec()
|
||||
shell.newJob().add("ls -alRZ /data/adb > ${ksuFileTree.absolutePath}").exec()
|
||||
shell.newJob().add("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec()
|
||||
shell.newJob().add("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec()
|
||||
shell.newJob().add("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec()
|
||||
shell.newJob().add("cp /data/system/packages.list ${appListFile.absolutePath}").exec()
|
||||
shell.newJob().add("getprop > ${propFile.absolutePath}").exec()
|
||||
shell.newJob().add("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec()
|
||||
|
||||
@@ -36,6 +36,7 @@ class ModuleViewModel : ViewModel() {
|
||||
val update: Boolean,
|
||||
val remove: Boolean,
|
||||
val updateJson: String,
|
||||
val hasWebUi: Boolean,
|
||||
)
|
||||
|
||||
data class ModuleUpdateInfo(
|
||||
@@ -96,7 +97,8 @@ class ModuleViewModel : ViewModel() {
|
||||
obj.getBoolean("enabled"),
|
||||
obj.getBoolean("update"),
|
||||
obj.getBoolean("remove"),
|
||||
obj.optString("updateJson")
|
||||
obj.optString("updateJson"),
|
||||
obj.optBoolean("web")
|
||||
)
|
||||
}.toList()
|
||||
isNeedRefresh = false
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package me.weishu.kernelsu.ui.webui;
|
||||
|
||||
import java.net.URLConnection;
|
||||
|
||||
class MimeUtil {
|
||||
|
||||
public static String getMimeFromFileName(String fileName) {
|
||||
if (fileName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Copying the logic and mapping that Chromium follows.
|
||||
// First we check against the OS (this is a limited list by default)
|
||||
// but app developers can extend this.
|
||||
// We then check against a list of hardcoded mime types above if the
|
||||
// OS didn't provide a result.
|
||||
String mimeType = URLConnection.guessContentTypeFromName(fileName);
|
||||
|
||||
if (mimeType != null) {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
return guessHardcodedMime(fileName);
|
||||
}
|
||||
|
||||
// We should keep this map in sync with the lists under
|
||||
// //net/base/mime_util.cc in Chromium.
|
||||
// A bunch of the mime types don't really apply to Android land
|
||||
// like word docs so feel free to filter out where necessary.
|
||||
private static String guessHardcodedMime(String fileName) {
|
||||
int finalFullStop = fileName.lastIndexOf('.');
|
||||
if (finalFullStop == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String extension = fileName.substring(finalFullStop + 1).toLowerCase();
|
||||
|
||||
switch (extension) {
|
||||
case "webm":
|
||||
return "video/webm";
|
||||
case "mpeg":
|
||||
case "mpg":
|
||||
return "video/mpeg";
|
||||
case "mp3":
|
||||
return "audio/mpeg";
|
||||
case "wasm":
|
||||
return "application/wasm";
|
||||
case "xhtml":
|
||||
case "xht":
|
||||
case "xhtm":
|
||||
return "application/xhtml+xml";
|
||||
case "flac":
|
||||
return "audio/flac";
|
||||
case "ogg":
|
||||
case "oga":
|
||||
case "opus":
|
||||
return "audio/ogg";
|
||||
case "wav":
|
||||
return "audio/wav";
|
||||
case "m4a":
|
||||
return "audio/x-m4a";
|
||||
case "gif":
|
||||
return "image/gif";
|
||||
case "jpeg":
|
||||
case "jpg":
|
||||
case "jfif":
|
||||
case "pjpeg":
|
||||
case "pjp":
|
||||
return "image/jpeg";
|
||||
case "png":
|
||||
return "image/png";
|
||||
case "apng":
|
||||
return "image/apng";
|
||||
case "svg":
|
||||
case "svgz":
|
||||
return "image/svg+xml";
|
||||
case "webp":
|
||||
return "image/webp";
|
||||
case "mht":
|
||||
case "mhtml":
|
||||
return "multipart/related";
|
||||
case "css":
|
||||
return "text/css";
|
||||
case "html":
|
||||
case "htm":
|
||||
case "shtml":
|
||||
case "shtm":
|
||||
case "ehtml":
|
||||
return "text/html";
|
||||
case "js":
|
||||
case "mjs":
|
||||
return "application/javascript";
|
||||
case "xml":
|
||||
return "text/xml";
|
||||
case "mp4":
|
||||
case "m4v":
|
||||
return "video/mp4";
|
||||
case "ogv":
|
||||
case "ogm":
|
||||
return "video/ogg";
|
||||
case "ico":
|
||||
return "image/x-icon";
|
||||
case "woff":
|
||||
return "application/font-woff";
|
||||
case "gz":
|
||||
case "tgz":
|
||||
return "application/gzip";
|
||||
case "json":
|
||||
return "application/json";
|
||||
case "pdf":
|
||||
return "application/pdf";
|
||||
case "zip":
|
||||
return "application/zip";
|
||||
case "bmp":
|
||||
return "image/bmp";
|
||||
case "tiff":
|
||||
case "tif":
|
||||
return "image/tiff";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package me.weishu.kernelsu.ui.webui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebResourceResponse;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.webkit.WebViewAssetLoader;
|
||||
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import me.weishu.kernelsu.ui.util.KsuCliKt;
|
||||
|
||||
/**
|
||||
* Handler class to open files from file system by root access
|
||||
* For more information about android storage please refer to
|
||||
* <a href="https://developer.android.com/guide/topics/data/data-storage">Android Developers
|
||||
* Docs: Data and file storage overview</a>.
|
||||
* <p class="note">
|
||||
* To avoid leaking user or app data to the web, make sure to choose {@code directory}
|
||||
* carefully, and assume any file under this directory could be accessed by any web page subject
|
||||
* to same-origin rules.
|
||||
* <p>
|
||||
* A typical usage would be like:
|
||||
* <pre class="prettyprint">
|
||||
* File publicDir = new File(context.getFilesDir(), "public");
|
||||
* // Host "files/public/" in app's data directory under:
|
||||
* // http://appassets.androidplatform.net/public/...
|
||||
* WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
|
||||
* .addPathHandler("/public/", new InternalStoragePathHandler(context, publicDir))
|
||||
* .build();
|
||||
* </pre>
|
||||
*/
|
||||
public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
|
||||
private static final String TAG = "SuFilePathHandler";
|
||||
|
||||
/**
|
||||
* Default value to be used as MIME type if guessing MIME type failed.
|
||||
*/
|
||||
public static final String DEFAULT_MIME_TYPE = "text/plain";
|
||||
|
||||
/**
|
||||
* Forbidden subdirectories of {@link Context#getDataDir} that cannot be exposed by this
|
||||
* handler. They are forbidden as they often contain sensitive information.
|
||||
* <p class="note">
|
||||
* Note: Any future addition to this list will be considered breaking changes to the API.
|
||||
*/
|
||||
private static final String[] FORBIDDEN_DATA_DIRS =
|
||||
new String[] {"/data/data", "/data/system"};
|
||||
|
||||
@NonNull
|
||||
private final File mDirectory;
|
||||
|
||||
private final Shell mShell;
|
||||
|
||||
/**
|
||||
* Creates PathHandler for app's internal storage.
|
||||
* The directory to be exposed must be inside either the application's internal data
|
||||
* directory {@link Context#getDataDir} or cache directory {@link Context#getCacheDir}.
|
||||
* External storage is not supported for security reasons, as other apps with
|
||||
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} may be able to modify the
|
||||
* files.
|
||||
* <p>
|
||||
* Exposing the entire data or cache directory is not permitted, to avoid accidentally
|
||||
* exposing sensitive application files to the web. Certain existing subdirectories of
|
||||
* {@link Context#getDataDir} are also not permitted as they are often sensitive.
|
||||
* These files are ({@code "app_webview/"}, {@code "databases/"}, {@code "lib/"},
|
||||
* {@code "shared_prefs/"} and {@code "code_cache/"}).
|
||||
* <p>
|
||||
* The application should typically use a dedicated subdirectory for the files it intends to
|
||||
* expose and keep them separate from other files.
|
||||
*
|
||||
* @param context {@link Context} that is used to access app's internal storage.
|
||||
* @param directory the absolute path of the exposed app internal storage directory from
|
||||
* which files can be loaded.
|
||||
* @throws IllegalArgumentException if the directory is not allowed.
|
||||
*/
|
||||
public SuFilePathHandler(@NonNull Context context, @NonNull File directory) {
|
||||
try {
|
||||
mDirectory = new File(getCanonicalDirPath(directory));
|
||||
if (!isAllowedInternalStorageDir(context)) {
|
||||
throw new IllegalArgumentException("The given directory \"" + directory
|
||||
+ "\" doesn't exist under an allowed app internal storage directory");
|
||||
}
|
||||
mShell = KsuCliKt.createRootShell(true);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to resolve the canonical path for the given directory: "
|
||||
+ directory.getPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAllowedInternalStorageDir(@NonNull Context context) throws IOException {
|
||||
String dir = getCanonicalDirPath(mDirectory);
|
||||
|
||||
for (String forbiddenPath : FORBIDDEN_DATA_DIRS) {
|
||||
if (dir.startsWith(forbiddenPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the requested file from the exposed data directory.
|
||||
* <p>
|
||||
* The matched prefix path used shouldn't be a prefix of a real web path. Thus, if the
|
||||
* requested file cannot be found or is outside the mounted directory a
|
||||
* {@link WebResourceResponse} object with a {@code null} {@link InputStream} will be
|
||||
* returned instead of {@code null}. This saves the time of falling back to network and
|
||||
* trying to resolve a path that doesn't exist. A {@link WebResourceResponse} with
|
||||
* {@code null} {@link InputStream} will be received as an HTTP response with status code
|
||||
* {@code 404} and no body.
|
||||
* <p class="note">
|
||||
* The MIME type for the file will be determined from the file's extension using
|
||||
* {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that
|
||||
* files are named using standard file extensions. If the file does not have a
|
||||
* recognised extension, {@code "text/plain"} will be used by default.
|
||||
*
|
||||
* @param path the suffix path to be handled.
|
||||
* @return {@link WebResourceResponse} for the requested file.
|
||||
*/
|
||||
@Override
|
||||
@WorkerThread
|
||||
@NonNull
|
||||
public WebResourceResponse handle(@NonNull String path) {
|
||||
try {
|
||||
File file = getCanonicalFileIfChild(mDirectory, path);
|
||||
if (file != null) {
|
||||
InputStream is = openFile(file, mShell);
|
||||
String mimeType = guessMimeType(path);
|
||||
return new WebResourceResponse(mimeType, null, is);
|
||||
} else {
|
||||
Log.e(TAG, String.format(
|
||||
"The requested file: %s is outside the mounted directory: %s", path,
|
||||
mDirectory));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error opening the requested path: " + path, e);
|
||||
}
|
||||
return new WebResourceResponse(null, null, null);
|
||||
}
|
||||
|
||||
public static String getCanonicalDirPath(@NonNull File file) throws IOException {
|
||||
String canonicalPath = file.getCanonicalPath();
|
||||
if (!canonicalPath.endsWith("/")) canonicalPath += "/";
|
||||
return canonicalPath;
|
||||
}
|
||||
|
||||
public static File getCanonicalFileIfChild(@NonNull File parent, @NonNull String child)
|
||||
throws IOException {
|
||||
String parentCanonicalPath = getCanonicalDirPath(parent);
|
||||
String childCanonicalPath = new File(parent, child).getCanonicalPath();
|
||||
if (childCanonicalPath.startsWith(parentCanonicalPath)) {
|
||||
return new File(childCanonicalPath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static InputStream handleSvgzStream(@NonNull String path,
|
||||
@NonNull InputStream stream) throws IOException {
|
||||
return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream;
|
||||
}
|
||||
|
||||
public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws FileNotFoundException,
|
||||
IOException {
|
||||
SuFile suFile = new SuFile(file.getAbsolutePath());
|
||||
suFile.setShell(shell);
|
||||
InputStream fis = SuFileInputStream.open(suFile);
|
||||
return handleSvgzStream(file.getPath(), fis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link MimeUtil#getMimeFromFileName} to guess MIME type or return the
|
||||
* {@link #DEFAULT_MIME_TYPE} if it can't guess.
|
||||
*
|
||||
* @param filePath path of the file to guess its MIME type.
|
||||
* @return MIME type guessed from file extension or {@link #DEFAULT_MIME_TYPE}.
|
||||
*/
|
||||
@NonNull
|
||||
public static String guessMimeType(@NonNull String filePath) {
|
||||
String mimeType = MimeUtil.getMimeFromFileName(filePath);
|
||||
return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package me.weishu.kernelsu.ui.webui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.TextUtils
|
||||
import android.view.Window
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.WebView
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import com.topjohnwu.superuser.CallbackList
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
import me.weishu.kernelsu.ui.util.createRootShell
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class WebViewInterface(val context: Context, private val webView: WebView) {
|
||||
|
||||
companion object {
|
||||
var isHideSystemUI: Boolean = false
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun exec(cmd: String): String {
|
||||
val shell = createRootShell()
|
||||
return ShellUtils.fastCmd(shell, cmd)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun exec(cmd: String, callbackFunc: String) {
|
||||
exec(cmd, null, callbackFunc)
|
||||
}
|
||||
|
||||
private fun processOptions(sb: StringBuilder, options: String?) {
|
||||
val opts = if (options == null) JSONObject() else {
|
||||
JSONObject(options)
|
||||
}
|
||||
|
||||
val cwd = opts.optString("cwd")
|
||||
if (!TextUtils.isEmpty(cwd)) {
|
||||
sb.append("cd ${cwd};")
|
||||
}
|
||||
|
||||
opts.optJSONObject("env")?.let { env ->
|
||||
env.keys().forEach { key ->
|
||||
sb.append("export ${key}=${env.getString(key)};")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun exec(
|
||||
cmd: String,
|
||||
options: String?,
|
||||
callbackFunc: String
|
||||
) {
|
||||
val finalCommand = StringBuilder()
|
||||
processOptions(finalCommand, options)
|
||||
finalCommand.append(cmd)
|
||||
|
||||
val shell = createRootShell()
|
||||
val result = shell.newJob().add(finalCommand.toString()).to(ArrayList(), ArrayList()).exec()
|
||||
val stdout = result.out.joinToString(separator = "\n")
|
||||
val stderr = result.err.joinToString(separator = "\n")
|
||||
|
||||
val jsCode =
|
||||
"javascript: (function() { try { ${callbackFunc}(${result.code}, ${
|
||||
JSONObject.quote(
|
||||
stdout
|
||||
)
|
||||
}, ${JSONObject.quote(stderr)}); } catch(e) { console.error(e); } })();"
|
||||
webView.post {
|
||||
webView.loadUrl(jsCode)
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun spawn(command: String, args: String, options: String?, callbackFunc: String) {
|
||||
val finalCommand = StringBuilder()
|
||||
|
||||
processOptions(finalCommand, options)
|
||||
|
||||
if (!TextUtils.isEmpty(args)) {
|
||||
finalCommand.append(command).append(" ")
|
||||
JSONArray(args).let { argsArray ->
|
||||
for (i in 0 until argsArray.length()) {
|
||||
finalCommand.append(argsArray.getString(i))
|
||||
finalCommand.append(" ")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
finalCommand.append(command)
|
||||
}
|
||||
|
||||
val shell = createRootShell()
|
||||
|
||||
val emitData = fun(name: String, data: String) {
|
||||
val jsCode =
|
||||
"javascript: (function() { try { ${callbackFunc}.${name}.emit('data', ${
|
||||
JSONObject.quote(
|
||||
data
|
||||
)
|
||||
}); } catch(e) { console.error('emitData', e); } })();"
|
||||
webView.post {
|
||||
webView.loadUrl(jsCode)
|
||||
}
|
||||
}
|
||||
|
||||
val stdout = object : CallbackList<String>() {
|
||||
override fun onAddElement(s: String) {
|
||||
emitData("stdout", s)
|
||||
}
|
||||
}
|
||||
|
||||
val stderr = object : CallbackList<String>() {
|
||||
override fun onAddElement(s: String) {
|
||||
emitData("stderr", s)
|
||||
}
|
||||
}
|
||||
|
||||
val future = shell.newJob().add(finalCommand.toString()).to(stdout, stderr).enqueue()
|
||||
val completableFuture = CompletableFuture.supplyAsync {
|
||||
future.get()
|
||||
}
|
||||
|
||||
completableFuture.thenAccept { result ->
|
||||
val emitExitCode =
|
||||
"javascript: (function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();"
|
||||
webView.post {
|
||||
webView.loadUrl(emitExitCode)
|
||||
}
|
||||
|
||||
if (result.code != 0) {
|
||||
val emitErrCode =
|
||||
"javascript: (function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${
|
||||
JSONObject.quote(
|
||||
result.err.joinToString(
|
||||
"\n"
|
||||
)
|
||||
)
|
||||
};${callbackFunc}.emit('error', err); } catch(e) { console.error('emitErr', e); } })();"
|
||||
webView.post {
|
||||
webView.loadUrl(emitErrCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun toast(msg: String) {
|
||||
webView.post {
|
||||
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun fullScreen(enable: Boolean) {
|
||||
if (context is Activity) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
if (enable) {
|
||||
hideSystemUI(context.window)
|
||||
} else {
|
||||
showSystemUI(context.window)
|
||||
}
|
||||
isHideSystemUI = enable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun hideSystemUI(window: Window) {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
|
||||
controller.hide(WindowInsetsCompat.Type.systemBars())
|
||||
controller.systemBarsBehavior =
|
||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
}
|
||||
}
|
||||
|
||||
fun showSystemUI(window: Window) {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, true)
|
||||
WindowInsetsControllerCompat(
|
||||
window,
|
||||
window.decorView
|
||||
).show(WindowInsetsCompat.Type.systemBars())
|
||||
}
|
||||
@@ -102,4 +102,8 @@
|
||||
<string name="app_profile_template_delete">حذف</string>
|
||||
<string name="app_profile_template_import_empty">الحافظة فارغة!</string>
|
||||
<string name="app_profile_template_view">عرض القالب</string>
|
||||
<string name="grant_root_failed">فشل في منح صلاحية الجذر!</string>
|
||||
<string name="open">فتح</string>
|
||||
<string name="settings_check_update_summary">التحقق تلقائيًا من وجود تحديثات عند فتح التطبيق</string>
|
||||
<string name="settings_check_update">التحقق من التحديث</string>
|
||||
</resources>
|
||||
@@ -8,7 +8,7 @@
|
||||
<string name="home_unsupported_reason">Actuellement, KernelSU ne supporte que les noyaux GKI</string>
|
||||
<string name="home_kernel">Noyau</string>
|
||||
<string name="home_fingerprint">Empreinte digitale</string>
|
||||
<string name="home_selinux_status">Statut de SELinux</string>
|
||||
<string name="home_selinux_status">Mode SELinux</string>
|
||||
<string name="selinux_status_disabled">Désactivé</string>
|
||||
<string name="selinux_status_permissive">Permissive</string>
|
||||
<string name="selinux_status_unknown">Inconnu</string>
|
||||
@@ -29,17 +29,17 @@
|
||||
<string name="reboot">Redémarrer</string>
|
||||
<string name="install">Installer</string>
|
||||
<string name="settings">Paramètres</string>
|
||||
<string name="reboot_bootloader">Redémarrer vers le bootloader</string>
|
||||
<string name="reboot_userspace">Redémarrage logiciel</string>
|
||||
<string name="reboot_recovery">Redémarrer en mode récupération</string>
|
||||
<string name="reboot_bootloader">Redémarrer en mode bootloader</string>
|
||||
<string name="reboot_userspace">Redémarrage progressif</string>
|
||||
<string name="reboot_recovery">Redémarrer en mode de récupération</string>
|
||||
<string name="reboot_edl">Redémarrer en mode EDL</string>
|
||||
<string name="about">À propos</string>
|
||||
<string name="module_uninstall_success">%s est désinstallé</string>
|
||||
<string name="reboot_download">Redémarrer en mode téléchargement</string>
|
||||
<string name="module_uninstall_success">%s a été désinstallé</string>
|
||||
<string name="reboot_download">Redémarrer en mode de téléchargement</string>
|
||||
<string name="module_author">Auteur</string>
|
||||
<string name="module_uninstall_confirm">Êtes-vous sûr(e) de vouloir désinstaller le module %s \?</string>
|
||||
<string name="home_learn_kernelsu">Découvrir KernelSU</string>
|
||||
<string name="module_overlay_fs_not_available">OverlayFS n\'est pas disponible, impossible de faire fonctionner le module !</string>
|
||||
<string name="module_overlay_fs_not_available">OverlayFS est indisponible, impossible de faire fonctionner les modules !</string>
|
||||
<string name="refresh">Rafraîchir</string>
|
||||
<string name="show_system_apps">Afficher les applications système</string>
|
||||
<string name="hide_system_apps">Masquer les applications système</string>
|
||||
@@ -50,9 +50,8 @@
|
||||
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
|
||||
<string name="home_support_title">Soutenez-nous</string>
|
||||
<string name="home_click_to_learn_kernelsu">Découvrez comment installer KernelSU et utiliser les modules</string>
|
||||
<string name="home_support_content">KernelSU est et restera toujours gratuit et open source. Vous pouvez cependant nous témoigner de votre soutien en nous faisant un don.</string>
|
||||
<string name="about_source_code">Voir le code source sur %1$s<br/>
|
||||
\nRejoindre notre canal %2$s</string>
|
||||
<string name="home_support_content">KernelSU est, et restera toujours, gratuit et open source. Vous pouvez cependant nous témoigner de votre soutien en nous faisant un don.</string>
|
||||
<string name="about_source_code">Voir le code source sur %1$s<br/>Rejoindre notre canal %2$s</string>
|
||||
<string name="profile_template">Modèle</string>
|
||||
<string name="profile_default">Par défaut</string>
|
||||
<string name="profile_custom">Personnalisé</string>
|
||||
@@ -68,7 +67,7 @@
|
||||
<string name="failed_to_update_app_profile">Échec de la modification du profil d\'application de %s</string>
|
||||
<string name="profile_umount_modules_summary">L\'activation de cette option permettra à KernelSU de restaurer tous les fichiers modifiés par les modules de cette application.</string>
|
||||
<string name="settings_umount_modules_default">Démonter les modules par défaut</string>
|
||||
<string name="settings_umount_modules_default_summary">Valeur globale par défaut pour « Démonter les modules » dans les profils d\'application. Si l\'option est activée, les modifications apportées au système par les modules seront supprimées pour les applications qui n\'ont pas de profil défini.</string>
|
||||
<string name="settings_umount_modules_default_summary">Valeur globale par défaut pour l\'option « Démonter les modules » dans les profils d\'application. Lorsqu\'elle est activée, les modifications apportées au système par les modules seront supprimées pour les applications qui n\'ont pas de profil défini.</string>
|
||||
<string name="profile_selinux_domain">Domaine</string>
|
||||
<string name="profile_selinux_rules">Règles</string>
|
||||
<string name="module_update">Mettre à jour</string>
|
||||
@@ -78,8 +77,8 @@
|
||||
<string name="module_start_downloading">Début du téléchargement de : %s</string>
|
||||
<string name="force_stop_app">Forcer l\'arrêt</string>
|
||||
<string name="restart_app">Relancer l\'application</string>
|
||||
<string name="failed_to_update_sepolicy">Échec de la mise à jour des règles de SELinux pour : %s</string>
|
||||
<string name="require_kernel_version">La version actuelle (%d) de KernelSU est trop ancienne pour que le gestionnaire fonctionne correctement. Veuillez passer à la version %d ou à une version supérieure !</string>
|
||||
<string name="failed_to_update_sepolicy">Échec de la mise à jour des règles SELinux pour : %s</string>
|
||||
<string name="require_kernel_version">La version actuelle de KernelSU (%d) est trop ancienne pour que le gestionnaire fonctionne correctement. Veuillez passer à la version %d ou à une version supérieure !</string>
|
||||
<string name="app_profile_template_import_success">Importation réussie</string>
|
||||
<string name="app_profile_export_to_clipboard">Exporter vers le presse-papiers</string>
|
||||
<string name="app_profile_template_export_empty">Impossible de trouver un modèle local à exporter !</string>
|
||||
@@ -103,4 +102,6 @@
|
||||
<string name="app_profile_template_delete">Supprimer</string>
|
||||
<string name="app_profile_template_import_empty">Le presse-papiers est vide !</string>
|
||||
<string name="app_profile_template_view">Voir le modèle</string>
|
||||
<string name="settings_check_update_summary">Vérifier automatiquement les mises à jour à l\'ouverture de l\'application</string>
|
||||
<string name="settings_check_update">Vérifier les mises à jour</string>
|
||||
</resources>
|
||||
@@ -80,4 +80,30 @@
|
||||
<string name="settings_umount_modules_default_summary">Il valore predefinito per \"Scollega moduli\" in Profili App. Se attivato, rimuoverà tutte le modifiche al sistema da parte dei moduli per le applicazioni che non hanno un profilo impostato.</string>
|
||||
<string name="require_kernel_version">La versione attualmente installata di KernelSU (%d) è troppo vecchia ed il gestore non può funzionare correttamente. Si prega di aggiornare alla versione %d o successiva!</string>
|
||||
<string name="module_changelog">Registro aggiornamenti</string>
|
||||
<string name="app_profile_template_create">Crea modello</string>
|
||||
<string name="app_profile_template_edit">Modifica Modello</string>
|
||||
<string name="app_profile_template_id">identificativo</string>
|
||||
<string name="app_profile_template_id_invalid">Identificativo modello non valido</string>
|
||||
<string name="app_profile_template_name">Nome</string>
|
||||
<string name="app_profile_template_view">Visualizza modello</string>
|
||||
<string name="app_profile_template_readonly">Sola lettura</string>
|
||||
<string name="app_profile_template_id_exist">Esiste già l\'identificativo del modello!</string>
|
||||
<string name="app_profile_import_export">Importa/Esporta</string>
|
||||
<string name="app_profile_import_from_clipboard">Importa dagli appunti</string>
|
||||
<string name="app_profile_export_to_clipboard">Esporta negli appunti</string>
|
||||
<string name="app_profile_template_export_empty">Impossibile trovare profilo locale da esportare!</string>
|
||||
<string name="app_profile_template_import_success">Importato con successo</string>
|
||||
<string name="app_profile_template_sync">Sincronizza i modelli remoti</string>
|
||||
<string name="app_profile_template_import_empty">Gli appunti sono vuoti!</string>
|
||||
<string name="grant_root_failed">Impossibile ottenere l\'accesso root!</string>
|
||||
<string name="settings_profile_template">Modelli Profili App</string>
|
||||
<string name="settings_profile_template_summary">Gestisci i modelli locali e remoti dei Profili App</string>
|
||||
<string name="app_profile_template_delete">Elimina</string>
|
||||
<string name="app_profile_template_description">Descrizione</string>
|
||||
<string name="app_profile_template_save">Salva</string>
|
||||
<string name="app_profile_template_save_failed">Impossibile salvare profilo</string>
|
||||
<string name="open">Apri</string>
|
||||
<string name="module_changelog_failed">Impossibile reperire il changelog: %s</string>
|
||||
<string name="settings_check_update">Controlla aggiornamenti</string>
|
||||
<string name="settings_check_update_summary">Controlla automaticamente la disponibilità di aggiornamenti all\'apertura dell\'applicazione</string>
|
||||
</resources>
|
||||
@@ -10,7 +10,7 @@
|
||||
<string name="home_unsupported">非対応</string>
|
||||
<string name="home_unsupported_reason">現在、 KernelSU は GKI カーネルにのみ対応しています</string>
|
||||
<string name="home_kernel">カーネル</string>
|
||||
<string name="home_manager_version">バージョン</string>
|
||||
<string name="home_manager_version">アプリのバージョン</string>
|
||||
<string name="home_fingerprint">Fingerprint</string>
|
||||
<string name="home_selinux_status">SELinux の状態</string>
|
||||
<string name="selinux_status_disabled">Disabled</string>
|
||||
@@ -46,7 +46,7 @@
|
||||
<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/ja_JP/guide/what-is-kernelsu.html</string>
|
||||
<string name="home_click_to_learn_kernelsu">KernelSU のインストール方法やモジュールの使い方はこちら</string>
|
||||
<string name="home_support_title">支援する</string>
|
||||
@@ -103,4 +103,8 @@
|
||||
<string name="app_profile_template_delete">消去</string>
|
||||
<string name="app_profile_template_import_empty">クリップボードが空です!</string>
|
||||
<string name="app_profile_template_view">テンプレートを表示</string>
|
||||
<string name="settings_check_update">アップデートを確認</string>
|
||||
<string name="settings_check_update_summary">アプリを開いたときにアップデートを自動的に確認する</string>
|
||||
<string name="grant_root_failed">root の付与に失敗しました!</string>
|
||||
<string name="open">開ける</string>
|
||||
</resources>
|
||||
@@ -82,4 +82,24 @@
|
||||
<string name="require_kernel_version">De huidige KernelSU-versie %d is te laag om de manager correct te laten functioneren. Upgrade naar versie %d of hoger!</string>
|
||||
<string name="module_changelog">wijzigings logboek</string>
|
||||
<string name="settings_profile_template">App-profiel Sjabloon</string>
|
||||
<string name="app_profile_template_create">Maken Sjabloon</string>
|
||||
<string name="app_profile_template_edit">Bewerkin Sjabloon</string>
|
||||
<string name="app_profile_template_id">id</string>
|
||||
<string name="app_profile_template_id_invalid">Ongeldige sjabloon id</string>
|
||||
<string name="app_profile_template_name">Naam</string>
|
||||
<string name="app_profile_template_save">Redde</string>
|
||||
<string name="app_profile_template_view">Bekijken Sjabloon</string>
|
||||
<string name="app_profile_template_description">Beschrijving</string>
|
||||
<string name="settings_profile_template_summary">Beheer lokale en online sjabloon van app-profiel</string>
|
||||
<string name="app_profile_template_delete">Verwijderen</string>
|
||||
<string name="app_profile_template_readonly">alleen lezen</string>
|
||||
<string name="app_profile_template_id_exist">sjabloon id bestaat al!</string>
|
||||
<string name="app_profile_template_sync">Synchroniseer online-sjablonen</string>
|
||||
<string name="app_profile_template_save_failed">Mislukt naar opslaan sjabloon</string>
|
||||
<string name="app_profile_template_import_empty">Klembord is leeg!</string>
|
||||
<string name="app_profile_import_export">Importeren/Exporteren</string>
|
||||
<string name="app_profile_import_from_clipboard">Importeren vanaf klembord</string>
|
||||
<string name="module_changelog_failed">Ophalen van wijzigingslogboek mislukt: %s</string>
|
||||
<string name="app_profile_export_to_clipboard">Exporteren naar klembord</string>
|
||||
<string name="settings_check_update">Controleer update</string>
|
||||
</resources>
|
||||
@@ -5,7 +5,7 @@
|
||||
<string name="home_click_to_install">Clique para instalar</string>
|
||||
<string name="home_working">Em execução</string>
|
||||
<string name="home_working_version">Versão: %d</string>
|
||||
<string name="home_superuser_count">Superusuários: %d</string>
|
||||
<string name="home_superuser_count">SuperUsuários: %d</string>
|
||||
<string name="home_module_count">Módulos: %d</string>
|
||||
<string name="home_unsupported">Sem suporte</string>
|
||||
<string name="home_unsupported_reason">KernelSU suporta apenas kernels GKI agora</string>
|
||||
@@ -38,11 +38,11 @@
|
||||
<string name="module_uninstall_failed">Falha ao desinstalar: %s</string>
|
||||
<string name="module_version">Versão</string>
|
||||
<string name="module_author">Autor</string>
|
||||
<string name="module_overlay_fs_not_available">overlayfs não está disponível, o módulo não pode funcionar!</string>
|
||||
<string name="module_overlay_fs_not_available">OverlayFS não está disponível. O módulo não pode funcionar!</string>
|
||||
<string name="refresh">Atualizar</string>
|
||||
<string name="show_system_apps">Mostrar apps do sistema</string>
|
||||
<string name="hide_system_apps">Ocultar apps do sistema</string>
|
||||
<string name="send_log">Reportar registrto</string>
|
||||
<string name="send_log">Reportar registro</string>
|
||||
<string name="safe_mode">Modo de segurança</string>
|
||||
<string name="reboot_to_apply">Reinicie para entrar em vigor</string>
|
||||
<string name="module_magisk_conflict">Os módulos estão desativados porque estão em conflito com os do Magisk!</string>
|
||||
@@ -67,14 +67,14 @@
|
||||
<string name="profile_umount_modules">Desmontar módulos</string>
|
||||
<string name="failed_to_update_app_profile">Falha ao atualizar o Perfil do Aplicativo para %s</string>
|
||||
<string name="settings_umount_modules_default">Desmontar módulos por padrão</string>
|
||||
<string name="settings_umount_modules_default_summary">O valor padrão global para \"Desmontar módulos\" em Perfis de Aplicativos. Se ativado, ele removerá todas as modificações do módulo no sistema para apps que não possuem um Perfil definido.</string>
|
||||
<string name="settings_umount_modules_default_summary">O valor padrão global para \"Desmontar módulos\" em Perfil do Aplicativo. Se ativado, ele removerá todas as modificações do módulo no sistema para apps que não possuem um perfil definido.</string>
|
||||
<string name="profile_umount_modules_summary">Ativar esta opção permitirá que o KernelSU restaure quaisquer arquivos modificados pelos módulos para este app.</string>
|
||||
<string name="profile_selinux_domain">Domínio</string>
|
||||
<string name="profile_selinux_rules">Regras</string>
|
||||
<string name="module_update">Atualizar</string>
|
||||
<string name="module_downloading">Baixando módulo: %s</string>
|
||||
<string name="module_start_downloading">Iniciar download: %s</string>
|
||||
<string name="new_version_available">Nova versão: %s está disponível, clique para atualizar</string>
|
||||
<string name="new_version_available">Nova versão: %s está disponível, clique para atualizar.</string>
|
||||
<string name="launch_app">Iniciar</string>
|
||||
<string name="force_stop_app">Forçar parada</string>
|
||||
<string name="restart_app">Reiniciar</string>
|
||||
@@ -84,14 +84,14 @@
|
||||
<string name="app_profile_template_import_success">Importado com sucesso</string>
|
||||
<string name="app_profile_export_to_clipboard">Exportar para a área de transferência</string>
|
||||
<string name="app_profile_template_export_empty">Não foi possível encontrar o modelo local para exportar!</string>
|
||||
<string name="app_profile_template_id_exist">o ID do modelo já existe!</string>
|
||||
<string name="app_profile_template_id_exist">O ID do modelo já existe!</string>
|
||||
<string name="app_profile_import_from_clipboard">Importar da área de transferência</string>
|
||||
<string name="module_changelog_failed">Falha ao buscar o registro de alterações: %s</string>
|
||||
<string name="app_profile_template_name">Nome</string>
|
||||
<string name="app_profile_template_id_invalid">ID do modelo inválido</string>
|
||||
<string name="app_profile_template_sync">Sincronizar modelos online</string>
|
||||
<string name="app_profile_template_create">Criar modelo</string>
|
||||
<string name="app_profile_template_readonly">somente leitura</string>
|
||||
<string name="app_profile_template_readonly">Somente leitura</string>
|
||||
<string name="app_profile_import_export">Importar/Exportar</string>
|
||||
<string name="app_profile_template_save_failed">Falha ao salvar o modelo</string>
|
||||
<string name="app_profile_template_edit">Editar modelo</string>
|
||||
@@ -99,8 +99,12 @@
|
||||
<string name="settings_profile_template">Modelo do Perfil do Aplicativo</string>
|
||||
<string name="app_profile_template_description">Descrição</string>
|
||||
<string name="app_profile_template_save">Salvar</string>
|
||||
<string name="settings_profile_template_summary">Gerenciar modelo local e online do Perfil do Aplicativo</string>
|
||||
<string name="settings_profile_template_summary">Gerencie o modelo local e online do Perfil do Aplicativo</string>
|
||||
<string name="app_profile_template_delete">Excluir</string>
|
||||
<string name="app_profile_template_import_empty">A área de transferência está vazia!</string>
|
||||
<string name="app_profile_template_view">Ver modelo</string>
|
||||
<string name="settings_check_update">Verificar atualização</string>
|
||||
<string name="settings_check_update_summary">Verifique automaticamente se há atualizações ao abrir o app</string>
|
||||
<string name="grant_root_failed">Falha ao conceder acesso root!</string>
|
||||
<string name="open">Abrir</string>
|
||||
</resources>
|
||||
@@ -102,4 +102,6 @@
|
||||
<string name="app_profile_template_delete">Șterge</string>
|
||||
<string name="app_profile_template_import_empty">Clipboard-ul este gol!</string>
|
||||
<string name="app_profile_template_view">Vizualizare șablon</string>
|
||||
<string name="settings_check_update">Verifică actualizarea</string>
|
||||
<string name="settings_check_update_summary">Se verifică automat actualizările când deschizi aplicația</string>
|
||||
</resources>
|
||||
@@ -18,7 +18,7 @@
|
||||
<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">Superuser</string>
|
||||
<!--Don't translate this string!-->
|
||||
<string name="module_failed_to_enable">Не удалось включить модуль: %s</string>
|
||||
<string name="module_failed_to_disable">Не удалось отключить модуль: %s</string>
|
||||
@@ -106,4 +106,8 @@
|
||||
<string name="app_profile_template_delete">Удалить</string>
|
||||
<string name="app_profile_template_import_empty">Буфер обмена пуст!</string>
|
||||
<string name="app_profile_template_view">Просмотр шаблона</string>
|
||||
<string name="settings_check_update">Проверка обновления</string>
|
||||
<string name="settings_check_update_summary">Автоматическая проверка обновлений при открытии приложения</string>
|
||||
<string name="grant_root_failed">Не удалось выдать root!</string>
|
||||
<string name="open">Открыть</string>
|
||||
</resources>
|
||||
105
manager/app/src/main/res/values-sl/strings.xml
Normal file
105
manager/app/src/main/res/values-sl/strings.xml
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="home_click_to_install">Klikni za namestitev</string>
|
||||
<string name="home_working">V obdelavi</string>
|
||||
<string name="home_working_version">Verzija: %d</string>
|
||||
<string name="home_superuser_count">Superuporabniki: %d</string>
|
||||
<string name="home_unsupported_reason">KernelSU podpira samo GKI kernele</string>
|
||||
<string name="home_kernel">Kernel</string>
|
||||
<string name="home_manager_version">Verzija upravitelja</string>
|
||||
<string name="home_fingerprint">Prstni odtis</string>
|
||||
<string name="home_selinux_status">SELinux status</string>
|
||||
<string name="selinux_status_disabled">Onemogočeno</string>
|
||||
<string name="selinux_status_unknown">Neznano</string>
|
||||
<string name="module_failed_to_disable">Napaka pri onemogočanju modula: %s</string>
|
||||
<string name="module_empty">Ni nameščenih modulov</string>
|
||||
<string name="module">Modul</string>
|
||||
<string name="uninstall">Odmesti</string>
|
||||
<string name="module_install">Namesti</string>
|
||||
<string name="install">Namesti</string>
|
||||
<string name="reboot_userspace">Mehki ponovni zagon</string>
|
||||
<string name="reboot_recovery">Ponovni zagon v Recovery</string>
|
||||
<string name="reboot_bootloader">Ponovni zagon v Bootloader</string>
|
||||
<string name="reboot_edl">Ponovni zagon v EDL</string>
|
||||
<string name="module_uninstall_confirm">Ste prepričani, da želite odstraniti modul %s?</string>
|
||||
<string name="module_uninstall_success">%s je odmeščen</string>
|
||||
<string name="module_author">Avtor</string>
|
||||
<string name="module_overlay_fs_not_available">overlayfs ni na voljo, modul ne more delovati!</string>
|
||||
<string name="hide_system_apps">Skrij prikaz sistemskih aplikacij</string>
|
||||
<string name="send_log">Prijavite dnevnik</string>
|
||||
<string name="home_learn_kernelsu">Naučite se KernelSU</string>
|
||||
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
|
||||
<string name="home_click_to_learn_kernelsu">Naučite se, kako namestiti KernelSU in uporabiti module</string>
|
||||
<string name="about_source_code">Glej odprto kodo na %1$s<br/>Pridružite se našem %2$s kanalu</string>
|
||||
<string name="profile_default">Privzeto</string>
|
||||
<string name="profile_template">Predloga</string>
|
||||
<string name="profile_namespace">Imenski prostor vmestitve</string>
|
||||
<string name="profile_namespace_inherited">Podedovano</string>
|
||||
<string name="profile_namespace_global">Globalno</string>
|
||||
<string name="profile_namespace_individual">Pozameznik</string>
|
||||
<string name="profile_capabilities">Zmožnosti</string>
|
||||
<string name="profile_umount_modules">Izvrzi module</string>
|
||||
<string name="settings_umount_modules_default">Po privzetem izvrzi module</string>
|
||||
<string name="profile_selinux_domain">Domena</string>
|
||||
<string name="module_update">Posodobitev</string>
|
||||
<string name="module_downloading">Nalaganje modula: %s</string>
|
||||
<string name="launch_app">Zaženi</string>
|
||||
<string name="restart_app">Ponovni zagon</string>
|
||||
<string name="module_changelog">Dnevnik sprememb</string>
|
||||
<string name="settings_profile_template">Predloga za aplikacijski profil</string>
|
||||
<string name="home">Domov</string>
|
||||
<string name="home_module_count">Moduli: %d</string>
|
||||
<string name="home_unsupported">Ne podpira</string>
|
||||
<string name="superuser">SuperUporabnik</string>
|
||||
<string name="module_failed_to_enable">Napaka pri omogočanju modula: %s</string>
|
||||
<string name="reboot">Znova zaženi</string>
|
||||
<string name="settings">Nastavitve</string>
|
||||
<string name="reboot_download">Ponovni zagon v Download</string>
|
||||
<string name="about">O nas</string>
|
||||
<string name="module_version">Verzija</string>
|
||||
<string name="module_uninstall_failed">Napaka pri odmeščanju: %s</string>
|
||||
<string name="refresh">Osveži</string>
|
||||
<string name="safe_mode">Varni način</string>
|
||||
<string name="reboot_to_apply">Za uveljavitev je potreben ponovni zagon</string>
|
||||
<string name="show_system_apps">Prikaz sistemskih aplikacij</string>
|
||||
<string name="module_magisk_conflict">Moduli so onemogočeni, ker so v konfliktu z Magiskovimi!</string>
|
||||
<string name="home_support_title">Podprite nas</string>
|
||||
<string name="profile_custom">Po meri</string>
|
||||
<string name="profile_name">Ime profila</string>
|
||||
<string name="profile_groups">Skupine</string>
|
||||
<string name="profile_selinux_context">SELinux kontekst</string>
|
||||
<string name="home_support_content">KernelSU je, in bo vedno brezplačen in odprtokoden. Kljub temu, nam lahko z donacijo pokažete, da vam je mar.</string>
|
||||
<string name="failed_to_update_app_profile">Napaka pri posodobitvi aplikacijskega profila za %s</string>
|
||||
<string name="require_kernel_version">Za pravilno funkionalnost upravitelja je trenutna KernelSU verzija %d prenizka. Potrebna je nadgradnja na verzijo %d ali več!</string>
|
||||
<string name="settings_umount_modules_default_summary">Globalno privzeta vrednost za \"Izvrzi module\" v aplikacijskih profilih. Če je omogočena, bo to odstranilo vse sistemske modifikacije modulov za aplikacije, ki nimajo nastavljenega profila.</string>
|
||||
<string name="profile_umount_modules_summary">Omogočanje te opcije bo dovolilo KernelSU, da obnovi vse zaradi modulov spremenjene datoteke za to aplikacijo.</string>
|
||||
<string name="force_stop_app">Prisilna ustavitev</string>
|
||||
<string name="profile_selinux_rules">Pravila</string>
|
||||
<string name="module_start_downloading">Začni z nalaganjem: %s</string>
|
||||
<string name="new_version_available">Na voljo je nova verzija: %s, kliknite za nadgradnjo</string>
|
||||
<string name="failed_to_update_sepolicy">Napaka pri posodobitvi SELinux pravil za: %s</string>
|
||||
<string name="home_not_installed">Ni nameščeno</string>
|
||||
<string name="selinux_status_enforcing">Enforcing</string>
|
||||
<string name="selinux_status_permissive">Permissive</string>
|
||||
<string name="app_profile_template_create">Ustvari predlogo</string>
|
||||
<string name="app_profile_template_edit">Uredi predlogo</string>
|
||||
<string name="app_profile_template_id_invalid">Neveljaven id predloge</string>
|
||||
<string name="app_profile_template_description">Opis</string>
|
||||
<string name="app_profile_template_save">Shrani</string>
|
||||
<string name="app_profile_template_delete">Odstrani</string>
|
||||
<string name="app_profile_template_readonly">le za branje</string>
|
||||
<string name="app_profile_template_id_exist">id predloge že obstaja!</string>
|
||||
<string name="app_profile_import_from_clipboard">Uvoz iz odložišča</string>
|
||||
<string name="app_profile_export_to_clipboard">Izvoz v odložišče</string>
|
||||
<string name="app_profile_template_export_empty">Lokalna predloga za izvoz ni bila najdena!</string>
|
||||
<string name="app_profile_template_save_failed">Napaka pri shranjevanju predloge</string>
|
||||
<string name="app_profile_template_import_empty">Odložišče je prazno!</string>
|
||||
<string name="settings_profile_template_summary">Upravljaj z lokalnimi in spletnimi predlogami za aplikacijski profil</string>
|
||||
<string name="app_profile_template_id">id</string>
|
||||
<string name="app_profile_template_name">Ime</string>
|
||||
<string name="app_profile_template_view">Ogled predloge</string>
|
||||
<string name="app_profile_template_import_success">Uvoz uspešen</string>
|
||||
<string name="app_profile_template_sync">Sinhroniziraj predloge iz spleta</string>
|
||||
<string name="app_profile_import_export">Uvoz/Izvoz</string>
|
||||
<string name="module_changelog_failed">Napaka pri pridobivanju dnevnika sprememb: %s</string>
|
||||
</resources>
|
||||
@@ -12,4 +12,9 @@
|
||||
<string name="module_failed_to_disable">మాడ్యూల్ని నిలిపివేయడంలో విఫలమైంది: %s</string>
|
||||
<string name="module_empty">మాడ్యూల్ ఏదీ ఇన్స్టాల్ చేయబడలేదు</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>
|
||||
</resources>
|
||||
@@ -102,4 +102,8 @@
|
||||
<string name="app_profile_template_import_empty">คลิปบอร์ดว่างเปล่า!</string>
|
||||
<string name="app_profile_template_view">ดูเทมเพลต</string>
|
||||
<string name="module_changelog_failed">ดึงข้อมูลบันทึกการเปลี่ยนแปลงล้มเหลว: %s</string>
|
||||
<string name="open">เปิด</string>
|
||||
<string name="grant_root_failed">ไม่สามารถให้สิทธิ์รูทได้!</string>
|
||||
<string name="settings_check_update">ตรวจสอบการอัปเดต</string>
|
||||
<string name="settings_check_update_summary">ตรวจสอบการอัปเดตโดยอัตโนมัติเมื่อเปิดแอป</string>
|
||||
</resources>
|
||||
@@ -52,7 +52,7 @@
|
||||
<string name="home_click_to_learn_kernelsu">KernelSU\'nun nasıl kurulacağını ve modüllerin nasıl kullanılacağını öğrenin</string>
|
||||
<string name="home_support_title">Bizi destekleyin</string>
|
||||
<string name="home_support_content">KernelSU ücretsiz ve açık kaynaklı bir yazılımdır ve her zaman öyle kalacaktır. Ancak bağış yaparak bize destek olduğunuzu gösterebilirsiniz.</string>
|
||||
<string name="about_source_code">Kaynak kodunu görüntüleyin: %1$s<br/>%2$s kanalımıza katılın</string>
|
||||
<string name="about_source_code">Kaynak kodunu %1$s\'tan görüntüleyin<br/>%2$s kanalımıza katılın</string>
|
||||
<string name="profile" translatable="false">Uygulama profili</string>
|
||||
<string name="profile_default">Varsayılan</string>
|
||||
<string name="profile_template">Şablon</string>
|
||||
@@ -104,4 +104,8 @@
|
||||
<string name="app_profile_template_save_failed">Şablon kaydedilemedi</string>
|
||||
<string name="app_profile_template_import_empty">Pano boş!</string>
|
||||
<string name="module_changelog_failed">Değişiklik geçmişi alınamadı: %s</string>
|
||||
<string name="settings_check_update">Güncellemeleri denetle</string>
|
||||
<string name="settings_check_update_summary">Uygulamayı açarken güncellemeleri otomatik denetle</string>
|
||||
<string name="grant_root_failed">Root izni verilemedi!</string>
|
||||
<string name="open">Aç</string>
|
||||
</resources>
|
||||
@@ -50,7 +50,7 @@
|
||||
<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>
|
||||
<string name="home_support_content">KernelSU 将保持免费开源,向开发者捐赠以表示支持。</string>
|
||||
<string name="about_source_code"><![CDATA[在 %1$s 查看源码<br/>加入我们的 %2$s 频道<br/>加入我们的 <b><a href="https://pd.qq.com/s/8lipl1brp">QQ 频道</a></b>]]></string>
|
||||
<string name="profile_default">默认</string>
|
||||
<string name="profile_template">模版</string>
|
||||
@@ -102,4 +102,8 @@
|
||||
<string name="app_profile_template_save_failed">模版保存失败!</string>
|
||||
<string name="app_profile_template_import_empty">剪切板为空!</string>
|
||||
<string name="module_changelog_failed">获取更新日志失败:%s</string>
|
||||
<string name="settings_check_update">检查更新</string>
|
||||
<string name="settings_check_update_summary">在应用启动后自动检查是否有最新版</string>
|
||||
<string name="grant_root_failed">获取 root 失败!</string>
|
||||
<string name="open">打开</string>
|
||||
</resources>
|
||||
@@ -3,14 +3,14 @@
|
||||
<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_working">運作中</string>
|
||||
<string name="home_working_version">KernelSU 版本:%d</string>
|
||||
<string name="home_superuser_count">超級使用者:%d 個</string>
|
||||
<string name="home_module_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_kernel">核心</string>
|
||||
<string name="home_manager_version">管理員版本</string>
|
||||
<string name="home_manager_version">管理器版本</string>
|
||||
<string name="home_fingerprint">指紋</string>
|
||||
<string name="home_selinux_status">SELinux 狀態</string>
|
||||
<string name="selinux_status_disabled">已停用</string>
|
||||
@@ -48,9 +48,9 @@
|
||||
<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="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>
|
||||
<string name="profile_default">預設</string>
|
||||
<string name="profile_name">設定檔名稱</string>
|
||||
@@ -61,8 +61,8 @@
|
||||
<string name="profile_umount_modules">卸載模組</string>
|
||||
<string name="failed_to_update_app_profile">無法更新 %s 應用程式設定檔</string>
|
||||
<string name="profile_selinux_rules">規則</string>
|
||||
<string name="require_kernel_version">目前 KernelSU 版本 %d 過低,管理員無法正常運作。請升級至 %d 或更高版本!</string>
|
||||
<string name="settings_umount_modules_default_summary">應用程式設定檔中「卸載模組」的全域預設值。如果啟用,將會為沒有設定檔的應用程式移除所有模組對系統的修改。</string>
|
||||
<string name="require_kernel_version">目前 KernelSU 版本 %d 過低,管理器無法正常運作。請升級至 %d 或更高版本!</string>
|
||||
<string name="settings_umount_modules_default_summary">應用程式設定檔中「解除安裝模組」的全域預設值,如果啟用,將會為沒有設定檔的應用程式移除所有模組針對系統的修改。</string>
|
||||
<string name="profile_umount_modules_summary">啟用此選項將允許 KernelSU 為這個應用程式還原任何被模組修改過的檔案。</string>
|
||||
<string name="profile_selinux_domain">網域</string>
|
||||
<string name="module_update">更新</string>
|
||||
@@ -70,8 +70,8 @@
|
||||
<string name="profile_namespace">掛載命名空間</string>
|
||||
<string name="profile_namespace_individual">個人</string>
|
||||
<string name="profile_groups">群組</string>
|
||||
<string name="profile_selinux_context">SELinux 內容</string>
|
||||
<string name="settings_umount_modules_default">預設卸載模組</string>
|
||||
<string name="profile_selinux_context">SELinux 環境</string>
|
||||
<string name="settings_umount_modules_default">預設解除安裝模組</string>
|
||||
<string name="module_downloading">正在下載模組:%s</string>
|
||||
<string name="module_start_downloading">開始下載:%s</string>
|
||||
<string name="new_version_available">新版本:%s 已可供使用,按一下以升級</string>
|
||||
@@ -79,27 +79,27 @@
|
||||
<string name="force_stop_app">強制停止</string>
|
||||
<string name="restart_app">重新啟動</string>
|
||||
<string name="failed_to_update_sepolicy">無法為 %s 更新 SELinux 規則</string>
|
||||
<string name="module_changelog">日志</string>
|
||||
<string name="app_profile_template_import_success">導出成功</string>
|
||||
<string name="module_changelog">變更記錄</string>
|
||||
<string name="app_profile_template_import_success">成功匯出</string>
|
||||
<string name="app_profile_export_to_clipboard">導出到剪貼板</string>
|
||||
<string name="app_profile_template_export_empty">沒有本地模板可以導出!</string>
|
||||
<string name="app_profile_template_id_exist">模板id已存在!</string>
|
||||
<string name="app_profile_import_from_clipboard">從剪貼板導入</string>
|
||||
<string name="app_profile_template_export_empty">本地沒有模板可匯出!</string>
|
||||
<string name="app_profile_template_id_exist">模板 ID 已存在!</string>
|
||||
<string name="app_profile_import_from_clipboard">從剪貼簿匯入</string>
|
||||
<string name="module_changelog_failed">獲取更新日誌失敗:%s</string>
|
||||
<string name="app_profile_template_name">名字</string>
|
||||
<string name="app_profile_template_id_invalid">模板id不合法</string>
|
||||
<string name="app_profile_template_id_invalid">模板 ID 無效</string>
|
||||
<string name="app_profile_template_sync">同步在線規則</string>
|
||||
<string name="app_profile_template_create">創建模板</string>
|
||||
<string name="app_profile_template_readonly">只讀</string>
|
||||
<string name="app_profile_import_export">導入/導出</string>
|
||||
<string name="app_profile_template_save_failed">模板保存失敗</string>
|
||||
<string name="app_profile_import_export">匯出 / 匯入</string>
|
||||
<string name="app_profile_template_save_failed">模板儲存失敗</string>
|
||||
<string name="app_profile_template_edit">編輯模板</string>
|
||||
<string name="app_profile_template_id">模板id</string>
|
||||
<string name="settings_profile_template">App Profile模板</string>
|
||||
<string name="app_profile_template_id">模板 ID</string>
|
||||
<string name="settings_profile_template">App Profile 模板</string>
|
||||
<string name="app_profile_template_description">描述</string>
|
||||
<string name="app_profile_template_save">保存</string>
|
||||
<string name="settings_profile_template_summary">管理本地和在線的App Profile模板</string>
|
||||
<string name="app_profile_template_save">儲存</string>
|
||||
<string name="settings_profile_template_summary">管理本地和線上的 App Profile 模板</string>
|
||||
<string name="app_profile_template_delete">刪除</string>
|
||||
<string name="app_profile_template_import_empty">剪貼板爲空!</string>
|
||||
<string name="app_profile_template_import_empty">剪貼簿沒有內容!</string>
|
||||
<string name="app_profile_template_view">查看模板</string>
|
||||
</resources>
|
||||
@@ -3,7 +3,7 @@
|
||||
<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">運作中</string>
|
||||
<string name="home_working_version">KernelSU 版本:%d</string>
|
||||
<string name="home_superuser_count">已授權 Root:%d 個</string>
|
||||
<string name="home_unsupported">不支援</string>
|
||||
@@ -49,8 +49,8 @@
|
||||
<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="home_support_title">支援開發</string>
|
||||
<string name="home_support_content">KernelSU 將保持免費和開源,您可以考慮向開發人員贊助以表示支持。</string>
|
||||
<string name="about_source_code"><![CDATA[在 %1$s 中檢視原始碼<br/>加入我們的 %2$s 頻道]]></string>
|
||||
<string name="profile_umount_modules">解除安裝模組</string>
|
||||
<string name="failed_to_update_app_profile">無法更新 %s 應用程式設定檔</string>
|
||||
@@ -80,12 +80,12 @@
|
||||
<string name="force_stop_app">強制停止</string>
|
||||
<string name="failed_to_update_sepolicy">無法為 %s 更新 SELinux</string>
|
||||
<string name="module_changelog">變更記錄</string>
|
||||
<string name="app_profile_template_id_invalid">模板 id 不合法</string>
|
||||
<string name="app_profile_template_id_invalid">模板 ID 無效</string>
|
||||
<string name="app_profile_template_create">創建模板</string>
|
||||
<string name="app_profile_template_edit">編輯模板</string>
|
||||
<string name="app_profile_template_id">模板 id</string>
|
||||
<string name="app_profile_template_id">模板 ID</string>
|
||||
<string name="settings_profile_template">App Profile 模板</string>
|
||||
<string name="settings_profile_template_summary">管理本地和在線的App Profile模板</string>
|
||||
<string name="settings_profile_template_summary">管理本地和線上的 App Profile 模板</string>
|
||||
<string name="app_profile_template_import_success">成功匯出</string>
|
||||
<string name="app_profile_export_to_clipboard">匯出至剪貼簿</string>
|
||||
<string name="app_profile_template_export_empty">本地沒有模板可匯出!</string>
|
||||
|
||||
@@ -104,4 +104,8 @@
|
||||
<string name="app_profile_template_save_failed">Failed to save template</string>
|
||||
<string name="app_profile_template_import_empty">Clipboard is empty!</string>
|
||||
<string name="module_changelog_failed">Fetch changelog failed: %s</string>
|
||||
<string name="settings_check_update">Check update</string>
|
||||
<string name="settings_check_update_summary">Automatically check for updates when opening the app</string>
|
||||
<string name="grant_root_failed">Failed to grant root!</string>
|
||||
<string name="open">Open</string>
|
||||
</resources>
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
<resources>
|
||||
|
||||
<style name="Theme.KernelSU" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
</resources>
|
||||
8
manager/app/src/main/res/xml/network_security_config.xml
Normal file
8
manager/app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">127.0.0.1</domain>
|
||||
<domain includeSubdomains="true">0.0.0.0</domain>
|
||||
<domain includeSubdomains="true">::1</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||
@@ -34,8 +34,8 @@ cmaker {
|
||||
|
||||
val androidMinSdkVersion = 26
|
||||
val androidTargetSdkVersion = 33
|
||||
val androidCompileSdkVersion = 33
|
||||
val androidBuildToolsVersion = "33.0.2"
|
||||
val androidCompileSdkVersion = 34
|
||||
val androidBuildToolsVersion = "34.0.0"
|
||||
val androidCompileNdkVersion = "25.2.9519653"
|
||||
val androidSourceCompatibility = JavaVersion.VERSION_17
|
||||
val androidTargetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
agp = "8.1.0"
|
||||
agp = "8.2.2"
|
||||
kotlin = "1.8.10"
|
||||
ksp = "1.8.10-1.0.9"
|
||||
compose-bom = "2023.06.01"
|
||||
@@ -10,6 +10,7 @@ compose-destination = "1.9.42-beta"
|
||||
libsu = "5.2.1"
|
||||
sheets-compose-dialogs = "1.2.0"
|
||||
markdown = "4.6.2"
|
||||
webkit = "1.10.0"
|
||||
|
||||
[plugins]
|
||||
agp-app = { id = "com.android.application", version.ref = "agp" }
|
||||
@@ -36,12 +37,15 @@ androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecyc
|
||||
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" }
|
||||
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" }
|
||||
|
||||
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
|
||||
com-google-accompanist-drawablepainter = { group = "com.google.accompanist", name = "accompanist-drawablepainter", version.ref = "accompanist" }
|
||||
com-google-accompanist-navigation-animation = { group = "com.google.accompanist", name = "accompanist-navigation-animation", version.ref = "accompanist" }
|
||||
com-google-accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanist" }
|
||||
com-google-accompanist-webview = { group = "com.google.accompanist", name = "accompanist-webview", version.ref = "accompanist" }
|
||||
|
||||
com-github-topjohnwu-libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref = "libsu" }
|
||||
com-github-topjohnwu-libsu-service = { group = "com.github.topjohnwu.libsu", name = "service", version.ref = "libsu" }
|
||||
com-github-topjohnwu-libsu-io= { group = "com.github.topjohnwu.libsu", name = "io", version.ref = "libsu" }
|
||||
|
||||
dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:parcelablelist", version = "2.0.1" }
|
||||
|
||||
@@ -58,4 +62,4 @@ sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs",
|
||||
sheet-compose-dialogs-list = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "list", version.ref = "sheets-compose-dialogs"}
|
||||
sheet-compose-dialogs-input = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "input", version.ref = "sheets-compose-dialogs"}
|
||||
|
||||
markdown = { group = "io.noties.markwon", name = "core", version.ref = "markdown" }
|
||||
markdown = { group = "io.noties.markwon", name = "core", version.ref = "markdown" }
|
||||
|
||||
BIN
manager/gradle/wrapper/gradle-wrapper.jar
vendored
BIN
manager/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
14
manager/gradlew
vendored
14
manager/gradlew
vendored
@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -202,11 +202,11 @@ fi
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
||||
@@ -2,14 +2,12 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
|
||||
473
userspace/ksud/Cargo.lock
generated
473
userspace/ksud/Cargo.lock
generated
@@ -29,7 +29,7 @@ version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
@@ -79,9 +79,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.68"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
@@ -91,7 +91,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -108,7 +108,7 @@ checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
@@ -121,25 +121,6 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.60.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -210,13 +191,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -231,8 +209,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time 0.1.45",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -245,17 +226,6 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.4"
|
||||
@@ -350,7 +320,7 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -359,7 +329,7 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-epoch",
|
||||
@@ -369,36 +339,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.6"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
|
||||
checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.2"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.13"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -407,18 +371,15 @@ version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.14"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
@@ -508,7 +469,7 @@ version = "0.8.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -537,12 +498,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.5"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -576,6 +537,18 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.6"
|
||||
@@ -601,7 +574,7 @@ version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
@@ -612,12 +585,6 @@ version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
@@ -633,6 +600,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
@@ -648,6 +621,19 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hole-punch"
|
||||
version = "0.0.4-alpha.0"
|
||||
source = "git+https://github.com/tiann/hole-punch#11ab7a61bfb98682b72fd7f58a47d8e5d997328e"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"errno 0.2.8",
|
||||
"libc",
|
||||
"memmap",
|
||||
"thiserror",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.5"
|
||||
@@ -746,7 +732,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.2.6",
|
||||
"io-lifetimes",
|
||||
"rustix 0.36.7",
|
||||
"windows-sys 0.42.0",
|
||||
@@ -813,28 +799,33 @@ dependencies = [
|
||||
"android-properties",
|
||||
"android_logger",
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap",
|
||||
"const_format",
|
||||
"derive-new",
|
||||
"encoding_rs",
|
||||
"env_logger",
|
||||
"extattr",
|
||||
"fs_extra",
|
||||
"getopts",
|
||||
"hole-punch",
|
||||
"humansize",
|
||||
"is_executable",
|
||||
"java-properties",
|
||||
"jwalk",
|
||||
"libc",
|
||||
"log",
|
||||
"loopdev",
|
||||
"nom",
|
||||
"procfs",
|
||||
"regex",
|
||||
"retry",
|
||||
"rust-embed",
|
||||
"rustix 0.38.30 (git+https://github.com/Kernel-SU/rustix.git?branch=main)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha256",
|
||||
"sys-mount",
|
||||
"tempdir",
|
||||
"which",
|
||||
"zip 0.6.4",
|
||||
"zip-extensions",
|
||||
@@ -846,17 +837,11 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
@@ -878,16 +863,6 @@ dependencies = [
|
||||
"rle-decode-fast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.6"
|
||||
@@ -911,42 +886,39 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.10"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "loopdev"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/tiann/loopdev?branch=loopfix#b6ca5e3ea163f66239f6a835874fe231b2a9286f"
|
||||
source = "git+https://github.com/Kernel-SU/loopdev#7a921f8d966477a645b1188732fac486c71a68ef"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"errno 0.2.8",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
name = "memmap"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -995,11 +967,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.3.4",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -1037,7 +1009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
@@ -1053,12 +1025,6 @@ dependencies = [
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
@@ -1109,9 +1075,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1128,7 +1094,7 @@ dependencies = [
|
||||
"hex",
|
||||
"lazy_static",
|
||||
"procfs-core",
|
||||
"rustix 0.38.21",
|
||||
"rustix 0.38.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1144,13 +1110,26 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||
dependencies = [
|
||||
"fuchsia-cprng",
|
||||
"libc",
|
||||
"rand_core 0.3.1",
|
||||
"rdrand",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@@ -1159,7 +1138,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1169,9 +1148,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
dependencies = [
|
||||
"rand_core 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
@@ -1203,6 +1197,15 @@ dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.1"
|
||||
@@ -1220,13 +1223,22 @@ version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "retry"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1276,12 +1288,6 @@ version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.7"
|
||||
@@ -1298,15 +1304,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.21"
|
||||
version = "0.38.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno 0.3.5",
|
||||
"errno 0.3.8",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.10",
|
||||
"windows-sys 0.48.0",
|
||||
"linux-raw-sys 0.4.13",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.30"
|
||||
source = "git+https://github.com/Kernel-SU/rustix.git?branch=main#0e270bce2d97466be6b987bb5f7ea5b1e8d84969"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno 0.3.8",
|
||||
"itoa",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.13",
|
||||
"once_cell",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1324,12 +1344,6 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.3"
|
||||
@@ -1338,9 +1352,23 @@ checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
@@ -1359,7 +1387,7 @@ version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
@@ -1370,7 +1398,7 @@ version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
@@ -1388,23 +1416,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "smart-default"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@@ -1430,9 +1441,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.38"
|
||||
version = "2.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1440,16 +1451,13 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sys-mount"
|
||||
version = "2.0.2"
|
||||
source = "git+https://github.com/tiann/sys-mount?branch=loopfix#c7c4048e4a4ffdf8b108a85956363a75f2c554f0"
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"loopdev",
|
||||
"smart-default",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"rand 0.4.6",
|
||||
"remove_dir_all",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1463,22 +1471,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.38"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.107",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1520,38 +1528,6 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
@@ -1584,12 +1560,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
@@ -1611,7 +1586,7 @@ version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
@@ -1668,7 +1643,7 @@ dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix 0.38.21",
|
||||
"rustix 0.38.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@@ -1736,6 +1711,15 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.1"
|
||||
@@ -1766,6 +1750,21 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
@@ -1778,6 +1777,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.1"
|
||||
@@ -1790,6 +1795,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.1"
|
||||
@@ -1802,6 +1813,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.1"
|
||||
@@ -1814,6 +1831,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.1"
|
||||
@@ -1826,6 +1849,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
@@ -1838,6 +1867,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.1"
|
||||
@@ -1850,6 +1885,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.5.13"
|
||||
|
||||
@@ -34,12 +34,17 @@ rust-embed = { version = "6", features = [
|
||||
which = "5"
|
||||
getopts = "0.2"
|
||||
sha256 = "1"
|
||||
tempdir = "0.3"
|
||||
chrono = "0.4"
|
||||
hole-punch = { git = "https://github.com/tiann/hole-punch" }
|
||||
fs_extra = "1.3"
|
||||
|
||||
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies]
|
||||
sys-mount = { git = "https://github.com/tiann/sys-mount", branch = "loopfix" }
|
||||
rustix = { git = "https://github.com/Kernel-SU/rustix.git", branch = "main", features = ["all-apis"] }
|
||||
# some android specific dependencies which compiles under unix are also listed here for convenience of coding
|
||||
android-properties = { version = "0.2.2", features = ["bionic-deprecated"] }
|
||||
procfs = "0.16"
|
||||
loopdev = { git = "https://github.com/Kernel-SU/loopdev" }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.13"
|
||||
|
||||
212
userspace/ksud/src/boot_patch.rs
Normal file
212
userspace/ksud/src/boot_patch.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
use anyhow::bail;
|
||||
use anyhow::ensure;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use is_executable::IsExecutable;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::process::Stdio;
|
||||
|
||||
use crate::utils;
|
||||
|
||||
#[cfg(unix)]
|
||||
fn ensure_gki_kernel() -> Result<()> {
|
||||
let version =
|
||||
procfs::sys::kernel::Version::current().with_context(|| "get kernel version failed")?;
|
||||
let is_gki = version.major == 5 && version.minor >= 10 || version.major > 5;
|
||||
ensure!(is_gki, "only support GKI kernel");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_cpio_cmd(magiskboot: &Path, workding_dir: &Path, cmd: &str) -> Result<()> {
|
||||
let status = Command::new(magiskboot)
|
||||
.current_dir(workding_dir)
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.arg("cpio")
|
||||
.arg("ramdisk.cpio")
|
||||
.arg(cmd)
|
||||
.status()?;
|
||||
|
||||
ensure!(status.success(), "magiskboot cpio {} failed", cmd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dd<P: AsRef<Path>, Q: AsRef<Path>>(ifile: P, ofile: Q) -> Result<()> {
|
||||
let status = Command::new("dd")
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.arg(format!("if={}", ifile.as_ref().display()))
|
||||
.arg(format!("of={}", ofile.as_ref().display()))
|
||||
.status()?;
|
||||
ensure!(
|
||||
status.success(),
|
||||
"dd if={:?} of={:?} failed",
|
||||
ifile.as_ref(),
|
||||
ofile.as_ref()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn patch(
|
||||
image: Option<PathBuf>,
|
||||
kernel: Option<PathBuf>,
|
||||
kmod: Option<PathBuf>,
|
||||
init: Option<PathBuf>,
|
||||
ota: bool,
|
||||
flash: bool,
|
||||
out: Option<PathBuf>,
|
||||
magiskboot_path: Option<PathBuf>,
|
||||
) -> Result<()> {
|
||||
if image.is_none() {
|
||||
#[cfg(unix)]
|
||||
ensure_gki_kernel()?;
|
||||
}
|
||||
|
||||
let is_replace_kernel = kernel.is_some();
|
||||
|
||||
if is_replace_kernel {
|
||||
ensure!(
|
||||
init.is_none() && kmod.is_none(),
|
||||
"init and module must not be specified."
|
||||
);
|
||||
} else {
|
||||
ensure!(
|
||||
init.is_some() && kmod.is_some(),
|
||||
"init and module must be specified"
|
||||
);
|
||||
}
|
||||
|
||||
let workding_dir = tempdir::TempDir::new("KernelSU")?;
|
||||
|
||||
let bootimage;
|
||||
|
||||
let mut bootdevice = None;
|
||||
|
||||
if let Some(image) = image {
|
||||
ensure!(image.exists(), "boot image not found");
|
||||
bootimage = std::fs::canonicalize(image)?;
|
||||
} else {
|
||||
let mut slot_suffix =
|
||||
utils::getprop("ro.boot.slot_suffix").unwrap_or_else(|| String::from(""));
|
||||
|
||||
if !slot_suffix.is_empty() && ota {
|
||||
if slot_suffix == "_a" {
|
||||
slot_suffix = "_b".to_string()
|
||||
} else {
|
||||
slot_suffix = "_a".to_string()
|
||||
}
|
||||
};
|
||||
|
||||
let init_boot_exist =
|
||||
Path::new(&format!("/dev/block/by-name/init_boot{slot_suffix}")).exists();
|
||||
let boot_partition = if !is_replace_kernel && init_boot_exist {
|
||||
format!("/dev/block/by-name/init_boot{slot_suffix}")
|
||||
} else {
|
||||
format!("/dev/block/by-name/boot{slot_suffix}")
|
||||
};
|
||||
|
||||
println!("bootdevice: {boot_partition}");
|
||||
let tmp_boot_path = workding_dir.path().join("boot.img");
|
||||
|
||||
dd(&boot_partition, &tmp_boot_path)?;
|
||||
|
||||
ensure!(tmp_boot_path.exists(), "boot image not found");
|
||||
|
||||
bootimage = tmp_boot_path;
|
||||
bootdevice = Some(boot_partition);
|
||||
};
|
||||
|
||||
println!("boot image: {bootimage:?}");
|
||||
|
||||
let magiskboot = magiskboot_path
|
||||
.map(std::fs::canonicalize)
|
||||
.transpose()?
|
||||
.unwrap_or_else(|| "magiskboot".into());
|
||||
|
||||
if !magiskboot.is_executable() {
|
||||
#[cfg(unix)]
|
||||
std::fs::set_permissions(&magiskboot, std::fs::Permissions::from_mode(0o755))
|
||||
.with_context(|| "set magiskboot executable failed".to_string())?;
|
||||
}
|
||||
|
||||
ensure!(magiskboot.exists(), "magiskboot not found");
|
||||
|
||||
if let Some(kernel) = kernel {
|
||||
std::fs::copy(kernel, workding_dir.path().join("kernel"))
|
||||
.with_context(|| "copy kernel from failed".to_string())?;
|
||||
}
|
||||
|
||||
if let (Some(kmod), Some(init)) = (kmod, init) {
|
||||
std::fs::copy(kmod, workding_dir.path().join("kernelsu.ko"))
|
||||
.with_context(|| "copy kernel module failed".to_string())?;
|
||||
std::fs::copy(init, workding_dir.path().join("init"))
|
||||
.with_context(|| "copy init failed".to_string())?;
|
||||
|
||||
// magiskboot unpack boot.img
|
||||
// magiskboot cpio ramdisk.cpio 'cp init init.real'
|
||||
// magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init'
|
||||
// magiskboot cpio ramdisk.cpio 'add 0755 <kmod> kernelsu.ko'
|
||||
|
||||
let status = Command::new(&magiskboot)
|
||||
.current_dir(workding_dir.path())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.arg("unpack")
|
||||
.arg(bootimage.display().to_string())
|
||||
.status()?;
|
||||
ensure!(status.success(), "magiskboot unpack failed");
|
||||
|
||||
let status = do_cpio_cmd(&magiskboot, workding_dir.path(), "exists init");
|
||||
if status.is_ok() {
|
||||
// init exist, backup it.
|
||||
do_cpio_cmd(&magiskboot, workding_dir.path(), "mv init init.real")?;
|
||||
}
|
||||
|
||||
do_cpio_cmd(&magiskboot, workding_dir.path(), "add 0755 init init")?;
|
||||
do_cpio_cmd(
|
||||
&magiskboot,
|
||||
workding_dir.path(),
|
||||
"add 0755 kernelsu.ko kernelsu.ko",
|
||||
)?;
|
||||
}
|
||||
|
||||
// magiskboot repack boot.img
|
||||
let status = Command::new(&magiskboot)
|
||||
.current_dir(workding_dir.path())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.arg("repack")
|
||||
.arg(bootimage.display().to_string())
|
||||
.status()?;
|
||||
ensure!(status.success(), "magiskboot repack failed");
|
||||
|
||||
let out = out.unwrap_or(std::env::current_dir()?);
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
let output_image = out.join(format!(
|
||||
"kernelsu_patched_boot_{}.img",
|
||||
now.format("%Y%m%d_%H%M%S")
|
||||
));
|
||||
std::fs::copy(workding_dir.path().join("new-boot.img"), &output_image)
|
||||
.with_context(|| "copy out new boot failed".to_string())?;
|
||||
|
||||
if flash {
|
||||
let Some(bootdevice) = bootdevice else {
|
||||
bail!("boot device not found")
|
||||
};
|
||||
let status = Command::new("blockdev")
|
||||
.arg("--setrw")
|
||||
.arg(&bootdevice)
|
||||
.status()?;
|
||||
ensure!(status.success(), "set boot device rw failed");
|
||||
|
||||
dd(&output_image, &bootdevice).with_context(|| "flash boot failed")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::{Ok, Result};
|
||||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
use android_logger::Config;
|
||||
@@ -48,6 +49,40 @@ enum Commands {
|
||||
command: Profile,
|
||||
},
|
||||
|
||||
/// Patch boot or init_boot images to apply KernelSU
|
||||
BootPatch {
|
||||
/// boot image path, if not specified, will try to find the boot image automatically
|
||||
#[arg(short, long)]
|
||||
boot: Option<PathBuf>,
|
||||
|
||||
/// kernel image path to replace
|
||||
#[arg(short, long)]
|
||||
kernel: Option<PathBuf>,
|
||||
|
||||
/// LKM module path to replace
|
||||
#[arg(short, long, requires("init"))]
|
||||
module: Option<PathBuf>,
|
||||
|
||||
/// init to be replaced, if use LKM, this must be specified
|
||||
#[arg(short, long, requires("module"))]
|
||||
init: Option<PathBuf>,
|
||||
|
||||
/// will use another slot when boot image is not specified
|
||||
#[arg(short = 'u', long, default_value = "false")]
|
||||
ota: bool,
|
||||
|
||||
/// Flash it to boot partition after patch
|
||||
#[arg(short, long, default_value = "false")]
|
||||
flash: bool,
|
||||
|
||||
/// output path, if not specified, will use current directory
|
||||
#[arg(short, long, default_value = None)]
|
||||
out: Option<PathBuf>,
|
||||
|
||||
/// magiskboot path, if not specified, will use builtin one
|
||||
#[arg(long, default_value = None)]
|
||||
magiskboot: Option<PathBuf>,
|
||||
},
|
||||
/// For developers
|
||||
Debug {
|
||||
#[command(subcommand)]
|
||||
@@ -70,13 +105,28 @@ enum Debug {
|
||||
},
|
||||
|
||||
/// Root Shell
|
||||
Su,
|
||||
Su {
|
||||
/// switch to gloabl mount namespace
|
||||
#[arg(short, long, default_value = "false")]
|
||||
global_mnt: bool,
|
||||
},
|
||||
|
||||
/// Get kernel version
|
||||
Version,
|
||||
|
||||
Mount,
|
||||
|
||||
/// Copy sparse file
|
||||
Xcp {
|
||||
/// source file
|
||||
src: String,
|
||||
/// destination file
|
||||
dst: String,
|
||||
/// punch hole
|
||||
#[arg(short, long, default_value = "false")]
|
||||
punch_hole: bool,
|
||||
},
|
||||
|
||||
/// For testing
|
||||
Test,
|
||||
}
|
||||
@@ -130,6 +180,9 @@ enum Module {
|
||||
|
||||
/// list all modules
|
||||
List,
|
||||
|
||||
/// Shrink module image size
|
||||
Shrink,
|
||||
}
|
||||
|
||||
#[derive(clap::Subcommand, Debug)]
|
||||
@@ -209,6 +262,7 @@ pub fn run() -> Result<()> {
|
||||
Module::Enable { id } => module::enable_module(&id),
|
||||
Module::Disable { id } => module::disable_module(&id),
|
||||
Module::List => module::list_modules(),
|
||||
Module::Shrink => module::shrink_ksu_images(),
|
||||
}
|
||||
}
|
||||
Commands::Install => event::install(),
|
||||
@@ -240,10 +294,29 @@ pub fn run() -> Result<()> {
|
||||
println!("Kernel Version: {}", crate::ksu::get_version());
|
||||
Ok(())
|
||||
}
|
||||
Debug::Su => crate::ksu::grant_root(),
|
||||
Debug::Su { global_mnt } => crate::ksu::grant_root(global_mnt),
|
||||
Debug::Mount => event::mount_systemlessly(defs::MODULE_DIR),
|
||||
Debug::Xcp {
|
||||
src,
|
||||
dst,
|
||||
punch_hole,
|
||||
} => {
|
||||
utils::copy_sparse_file(src, dst, punch_hole)?;
|
||||
Ok(())
|
||||
}
|
||||
Debug::Test => todo!(),
|
||||
},
|
||||
|
||||
Commands::BootPatch {
|
||||
boot,
|
||||
init,
|
||||
kernel,
|
||||
module,
|
||||
ota,
|
||||
flash,
|
||||
out,
|
||||
magiskboot,
|
||||
} => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot),
|
||||
};
|
||||
|
||||
if let Err(e) = &result {
|
||||
|
||||
@@ -21,7 +21,7 @@ fn set_kernel_param(size: u32, hash: String) -> Result<()> {
|
||||
let expeced_size_path = kernel_param_path.join("ksu_expected_size");
|
||||
let expeced_hash_path = kernel_param_path.join("ksu_expected_hash");
|
||||
|
||||
println!(
|
||||
print!(
|
||||
"before size: {:#x} hash: {}",
|
||||
read_u32(&expeced_size_path)?,
|
||||
std::fs::read_to_string(&expeced_hash_path)?
|
||||
@@ -30,7 +30,7 @@ fn set_kernel_param(size: u32, hash: String) -> Result<()> {
|
||||
std::fs::write(&expeced_size_path, size.to_string())?;
|
||||
std::fs::write(&expeced_hash_path, hash)?;
|
||||
|
||||
println!(
|
||||
print!(
|
||||
"after size: {:#x} hash: {}",
|
||||
read_u32(&expeced_size_path)?,
|
||||
std::fs::read_to_string(&expeced_hash_path)?
|
||||
@@ -58,5 +58,8 @@ pub fn set_manager(pkg: &str) -> Result<()> {
|
||||
let path = get_apk_path(pkg).with_context(|| format!("{pkg} does not exist!"))?;
|
||||
let sign = get_apk_signature(&path)?;
|
||||
set_kernel_param(sign.0, sign.1)?;
|
||||
|
||||
// force-stop it
|
||||
let _ = Command::new("am").args(["force-stop", pkg]).status();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -25,9 +25,12 @@ pub const MODULE_UPDATE_TMP_IMG: &str = concatcp!(WORKING_DIR, "update_tmp.img")
|
||||
// warning: this directory should not change, or you need to change the code in module_installer.sh!!!
|
||||
pub const MODULE_UPDATE_TMP_DIR: &str = concatcp!(ADB_DIR, "modules_update/");
|
||||
|
||||
pub const SYSTEM_RW_DIR: &str = concatcp!(MODULE_DIR, ".rw/");
|
||||
|
||||
pub const TEMP_DIR: &str = "/debug_ramdisk";
|
||||
pub const TEMP_DIR_LEGACY: &str = "/sbin";
|
||||
|
||||
pub const MODULE_WEB_DIR: &str = "webroot";
|
||||
pub const DISABLE_FILE_NAME: &str = "disable";
|
||||
pub const UPDATE_FILE_NAME: &str = "update";
|
||||
pub const REMOVE_FILE_NAME: &str = "remove";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use log::{info, warn};
|
||||
#[cfg(target_os = "android")]
|
||||
use std::path::PathBuf;
|
||||
use std::{collections::HashMap, path::Path};
|
||||
|
||||
@@ -9,13 +10,13 @@ use crate::{
|
||||
utils::{self, ensure_clean_dir, ensure_dir_exists},
|
||||
};
|
||||
|
||||
fn mount_partition(partition: &str, lowerdir: &Vec<String>) -> Result<()> {
|
||||
fn mount_partition(partition_name: &str, lowerdir: &Vec<String>) -> Result<()> {
|
||||
if lowerdir.is_empty() {
|
||||
warn!("partition: {partition} lowerdir is empty");
|
||||
warn!("partition: {partition_name} lowerdir is empty");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let partition = format!("/{partition}");
|
||||
let partition = format!("/{partition_name}");
|
||||
|
||||
// if /partition is a symlink and linked to /system/partition, then we don't need to overlay it separately
|
||||
if Path::new(&partition).read_link().is_ok() {
|
||||
@@ -23,7 +24,15 @@ fn mount_partition(partition: &str, lowerdir: &Vec<String>) -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
mount::mount_overlay(&partition, lowerdir)
|
||||
let mut workdir = None;
|
||||
let mut upperdir = None;
|
||||
let system_rw_dir = Path::new(defs::SYSTEM_RW_DIR);
|
||||
if system_rw_dir.exists() {
|
||||
workdir = Some(system_rw_dir.join(partition_name).join("workdir"));
|
||||
upperdir = Some(system_rw_dir.join(partition_name).join("upperdir"));
|
||||
}
|
||||
|
||||
mount::mount_overlay(&partition, lowerdir, workdir, upperdir)
|
||||
}
|
||||
|
||||
pub fn mount_systemlessly(module_dir: &str) -> Result<()> {
|
||||
@@ -152,6 +161,9 @@ pub fn on_post_data_fs() -> Result<()> {
|
||||
mount::AutoMountExt4::try_new(target_update_img, module_dir, false)
|
||||
.with_context(|| "mount module image failed".to_string())?;
|
||||
|
||||
// tell kernel that we've mount the module, so that it can do some optimization
|
||||
crate::ksu::report_module_mounted();
|
||||
|
||||
// if we are in safe mode, we should disable all modules
|
||||
if safe_mode {
|
||||
warn!("safe mode, skip post-fs-data scripts and disable all modules!");
|
||||
@@ -243,7 +255,7 @@ pub fn on_boot_completed() -> Result<()> {
|
||||
// this is a update and we successfully booted
|
||||
if std::fs::rename(module_update_img, module_img).is_err() {
|
||||
warn!("Failed to rename images, copy it now.",);
|
||||
std::fs::copy(module_update_img, module_img)
|
||||
utils::copy_sparse_file(module_update_img, module_img, false)
|
||||
.with_context(|| "Failed to copy images")?;
|
||||
std::fs::remove_file(module_update_img).with_context(|| "Failed to remove image!")?;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use anyhow::{Ok, Result};
|
||||
|
||||
#[cfg(unix)]
|
||||
use anyhow::ensure;
|
||||
use getopts::Options;
|
||||
use std::env;
|
||||
#[cfg(unix)]
|
||||
@@ -14,24 +11,21 @@ use crate::{
|
||||
utils::{self, umask},
|
||||
};
|
||||
|
||||
pub const KERNEL_SU_OPTION: u32 = 0xDEAD_BEEF;
|
||||
|
||||
const CMD_GRANT_ROOT: u64 = 0;
|
||||
// const CMD_BECOME_MANAGER: u64 = 1;
|
||||
const CMD_GET_VERSION: u64 = 2;
|
||||
// const CMD_ALLOW_SU: u64 = 3;
|
||||
// const CMD_DENY_SU: u64 = 4;
|
||||
// const CMD_GET_ALLOW_LIST: u64 = 5;
|
||||
// const CMD_GET_DENY_LIST: u64 = 6;
|
||||
const CMD_REPORT_EVENT: u64 = 7;
|
||||
pub const CMD_SET_SEPOLICY: u64 = 8;
|
||||
pub const CMD_CHECK_SAFEMODE: u64 = 9;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use rustix::{
|
||||
process::getuid,
|
||||
thread::{set_thread_res_gid, set_thread_res_uid, Gid, Uid},
|
||||
};
|
||||
|
||||
const EVENT_POST_FS_DATA: u64 = 1;
|
||||
const EVENT_BOOT_COMPLETED: u64 = 2;
|
||||
const EVENT_MODULE_MOUNTED: u64 = 3;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn grant_root() -> Result<()> {
|
||||
pub fn grant_root(global_mnt: bool) -> Result<()> {
|
||||
const KERNEL_SU_OPTION: u32 = 0xDEAD_BEEF;
|
||||
const CMD_GRANT_ROOT: u64 = 0;
|
||||
|
||||
let mut result: u32 = 0;
|
||||
unsafe {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
@@ -44,12 +38,22 @@ pub fn grant_root() -> Result<()> {
|
||||
);
|
||||
}
|
||||
|
||||
ensure!(result == KERNEL_SU_OPTION, "grant root failed");
|
||||
Err(std::process::Command::new("sh").exec().into())
|
||||
anyhow::ensure!(result == KERNEL_SU_OPTION, "grant root failed");
|
||||
let mut command = std::process::Command::new("sh");
|
||||
let command = unsafe {
|
||||
command.pre_exec(move || {
|
||||
if global_mnt {
|
||||
let _ = utils::switch_mnt_ns(1);
|
||||
let _ = utils::unshare_mnt_ns();
|
||||
}
|
||||
std::result::Result::Ok(())
|
||||
})
|
||||
};
|
||||
Err(command.exec().into())
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub fn grant_root() -> Result<()> {
|
||||
pub fn grant_root(_global_mnt: bool) -> Result<()> {
|
||||
unimplemented!("grant_root is only available on android");
|
||||
}
|
||||
|
||||
@@ -60,12 +64,19 @@ fn print_usage(program: &str, opts: Options) {
|
||||
|
||||
fn set_identity(uid: u32, gid: u32, groups: &[u32]) {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
unsafe {
|
||||
if !groups.is_empty() {
|
||||
libc::setgroups(groups.len(), groups.as_ptr());
|
||||
}
|
||||
libc::setresgid(gid, gid, gid);
|
||||
libc::setresuid(uid, uid, uid);
|
||||
{
|
||||
rustix::process::set_groups(
|
||||
groups
|
||||
.iter()
|
||||
.map(|g| unsafe { Gid::from_raw(*g) })
|
||||
.collect::<Vec<_>>()
|
||||
.as_ref(),
|
||||
)
|
||||
.ok();
|
||||
let gid = unsafe { Gid::from_raw(gid) };
|
||||
let uid = unsafe { Uid::from_raw(uid) };
|
||||
set_thread_res_gid(gid, gid, gid).ok();
|
||||
set_thread_res_uid(uid, uid, uid).ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +213,7 @@ pub fn root_shell() -> Result<()> {
|
||||
}
|
||||
|
||||
// use current uid if no user specified, these has been done in kernel!
|
||||
let mut uid = unsafe { libc::getuid() };
|
||||
let mut uid = getuid().as_raw();
|
||||
if free_idx < matches.free.len() {
|
||||
let name = &matches.free[free_idx];
|
||||
uid = unsafe {
|
||||
@@ -290,46 +301,32 @@ fn add_path_to_env(path: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn get_version() -> i32 {
|
||||
let mut result: i32 = 0;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
unsafe {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
libc::prctl(
|
||||
KERNEL_SU_OPTION as i32, // supposed to overflow
|
||||
CMD_GET_VERSION,
|
||||
std::ptr::addr_of_mut!(result).cast::<libc::c_void>(),
|
||||
);
|
||||
}
|
||||
result
|
||||
rustix::process::ksu_get_version()
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub fn get_version() -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn report_event(event: u64) {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
unsafe {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
libc::prctl(
|
||||
KERNEL_SU_OPTION as i32, // supposed to overflow
|
||||
CMD_REPORT_EVENT,
|
||||
event,
|
||||
);
|
||||
}
|
||||
rustix::process::ksu_report_event(event)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
fn report_event(_event: u64) {}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn check_kernel_safemode() -> bool {
|
||||
let mut result: i32 = 0;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
unsafe {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
libc::prctl(
|
||||
KERNEL_SU_OPTION as i32, // supposed to overflow
|
||||
CMD_CHECK_SAFEMODE,
|
||||
0,
|
||||
0,
|
||||
std::ptr::addr_of_mut!(result).cast::<libc::c_void>(),
|
||||
);
|
||||
}
|
||||
result == KERNEL_SU_OPTION as i32
|
||||
rustix::process::ksu_check_kernel_safemode()
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub fn check_kernel_safemode() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn report_post_fs_data() {
|
||||
@@ -339,3 +336,7 @@ pub fn report_post_fs_data() {
|
||||
pub fn report_boot_complete() {
|
||||
report_event(EVENT_BOOT_COMPLETED);
|
||||
}
|
||||
|
||||
pub fn report_module_mounted() {
|
||||
report_event(EVENT_MODULE_MOUNTED);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod apk_sign;
|
||||
mod assets;
|
||||
mod boot_patch;
|
||||
mod cli;
|
||||
mod debug;
|
||||
mod defs;
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::utils::*;
|
||||
use crate::{
|
||||
assets, defs, mount,
|
||||
restorecon::{restore_syscon, setsyscon},
|
||||
sepolicy,
|
||||
sepolicy, utils,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, bail, ensure, Context, Result};
|
||||
@@ -11,6 +11,7 @@ use const_format::concatcp;
|
||||
use is_executable::is_executable;
|
||||
use java_properties::PropertiesIter;
|
||||
use log::{info, warn};
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env::var as env_var,
|
||||
@@ -23,7 +24,7 @@ use std::{
|
||||
use zip_extensions::zip_extract_file_to_memory;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::{prelude::PermissionsExt, process::CommandExt};
|
||||
use std::os::unix::{fs::MetadataExt, prelude::PermissionsExt, process::CommandExt};
|
||||
|
||||
const INSTALLER_CONTENT: &str = include_str!("./installer.sh");
|
||||
const INSTALL_MODULE_SCRIPT: &str = concatcp!(
|
||||
@@ -118,25 +119,6 @@ fn foreach_active_module(f: impl FnMut(&Path) -> Result<()>) -> Result<()> {
|
||||
foreach_module(true, f)
|
||||
}
|
||||
|
||||
fn get_minimal_image_size(img: &str) -> Result<u64> {
|
||||
check_image(img)?;
|
||||
|
||||
let output = Command::new("resize2fs")
|
||||
.args(["-P", img])
|
||||
.stdout(Stdio::piped())
|
||||
.output()?;
|
||||
|
||||
let output = String::from_utf8_lossy(&output.stdout);
|
||||
println!("- {}", output.trim());
|
||||
let regex = regex::Regex::new(r"filesystem: (\d+)")?;
|
||||
let result = regex
|
||||
.captures(&output)
|
||||
.ok_or(anyhow::anyhow!("regex not match"))?;
|
||||
let result = &result[1];
|
||||
let result = u64::from_str(result)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn check_image(img: &str) -> Result<()> {
|
||||
let result = Command::new("e2fsck")
|
||||
.args(["-yf", img])
|
||||
@@ -157,31 +139,6 @@ fn check_image(img: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn grow_image_size(img: &str, extra_size: u64) -> Result<()> {
|
||||
let minimal_size = get_minimal_image_size(img)?; // the minimal size is in KB
|
||||
let target_size = minimal_size * 1024 + extra_size;
|
||||
|
||||
// check image
|
||||
check_image(img)?;
|
||||
|
||||
println!(
|
||||
"- Target image size: {}",
|
||||
humansize::format_size(target_size, humansize::DECIMAL)
|
||||
);
|
||||
let target_size = target_size / 1024 + 1024;
|
||||
info!("resize image to {target_size}K, minimal size is {minimal_size}K");
|
||||
let result = Command::new("resize2fs")
|
||||
.args([img, &format!("{target_size}K")])
|
||||
.stdout(Stdio::piped())
|
||||
.status()
|
||||
.with_context(|| format!("Failed to exec resize2fs {img}"))?;
|
||||
ensure!(result.success(), "Failed to resize2fs: {}", result);
|
||||
|
||||
check_image(img)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_sepolicy_rule() -> Result<()> {
|
||||
foreach_active_module(|path| {
|
||||
let rule_file = path.join("sepolicy.rule");
|
||||
@@ -324,6 +281,27 @@ pub fn prune_modules() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_module_image(image: &str, image_size: u64, journal_size: u64) -> Result<()> {
|
||||
File::create(image)
|
||||
.context("Failed to create ext4 image file")?
|
||||
.set_len(image_size)
|
||||
.context("Failed to truncate ext4 image")?;
|
||||
|
||||
// format the img to ext4 filesystem
|
||||
let result = Command::new("mkfs.ext4")
|
||||
.arg("-J")
|
||||
.arg(format!("size={journal_size}"))
|
||||
.arg(image)
|
||||
.stdout(Stdio::piped())
|
||||
.output()?;
|
||||
ensure!(
|
||||
result.status.success(),
|
||||
"Failed to format ext4 image: {}",
|
||||
String::from_utf8(result.stderr).unwrap()
|
||||
);
|
||||
check_image(image)?;
|
||||
Ok(())
|
||||
}
|
||||
fn _install_module(zip: &str) -> Result<()> {
|
||||
ensure_boot_completed()?;
|
||||
|
||||
@@ -370,18 +348,12 @@ fn _install_module(zip: &str) -> Result<()> {
|
||||
std::fs::remove_file(tmp_module_path)?;
|
||||
}
|
||||
|
||||
let default_reserve_size = 256 * 1024 * 1024;
|
||||
let zip_uncompressed_size = get_zip_uncompressed_size(zip)?;
|
||||
let grow_size = default_reserve_size + zip_uncompressed_size;
|
||||
|
||||
info!(
|
||||
"zip uncompressed size: {}",
|
||||
humansize::format_size(zip_uncompressed_size, humansize::DECIMAL)
|
||||
);
|
||||
info!(
|
||||
"grow size: {}",
|
||||
humansize::format_size(grow_size, humansize::DECIMAL)
|
||||
);
|
||||
|
||||
println!("- Preparing image");
|
||||
println!(
|
||||
@@ -389,53 +361,53 @@ fn _install_module(zip: &str) -> Result<()> {
|
||||
humansize::format_size(zip_uncompressed_size, humansize::DECIMAL)
|
||||
);
|
||||
|
||||
let sparse_image_size = 1 << 40; // 1T
|
||||
let journal_size = 8; // 8M
|
||||
if !modules_img_exist && !modules_update_img_exist {
|
||||
// if no modules and modules_update, it is brand new installation, we should create a new img
|
||||
// create a tmp module img and mount it to modules_update
|
||||
info!("Creating brand new module image");
|
||||
File::create(tmp_module_img)
|
||||
.context("Failed to create ext4 image file")?
|
||||
.set_len(grow_size)
|
||||
.context("Failed to extend ext4 image")?;
|
||||
|
||||
// format the img to ext4 filesystem
|
||||
let result = Command::new("mkfs.ext4")
|
||||
.arg("-b")
|
||||
.arg("1024")
|
||||
.arg(tmp_module_img)
|
||||
.stdout(Stdio::piped())
|
||||
.output()?;
|
||||
ensure!(
|
||||
result.status.success(),
|
||||
"Failed to format ext4 image: {}",
|
||||
String::from_utf8(result.stderr).unwrap()
|
||||
);
|
||||
|
||||
check_image(tmp_module_img)?;
|
||||
create_module_image(tmp_module_img, sparse_image_size, journal_size)?;
|
||||
} else if modules_update_img_exist {
|
||||
// modules_update.img exists, we should use it as tmp img
|
||||
info!("Using existing modules_update.img as tmp image");
|
||||
std::fs::copy(modules_update_img, tmp_module_img).with_context(|| {
|
||||
utils::copy_sparse_file(modules_update_img, tmp_module_img, true).with_context(|| {
|
||||
format!(
|
||||
"Failed to copy {} to {}",
|
||||
modules_update_img.display(),
|
||||
tmp_module_img
|
||||
)
|
||||
})?;
|
||||
// grow size of the tmp image
|
||||
grow_image_size(tmp_module_img, grow_size)?;
|
||||
} else {
|
||||
// modules.img exists, we should use it as tmp img
|
||||
info!("Using existing modules.img as tmp image");
|
||||
std::fs::copy(modules_img, tmp_module_img).with_context(|| {
|
||||
format!(
|
||||
"Failed to copy {} to {}",
|
||||
modules_img.display(),
|
||||
tmp_module_img
|
||||
)
|
||||
})?;
|
||||
// grow size of the tmp image
|
||||
grow_image_size(tmp_module_img, grow_size)?;
|
||||
|
||||
#[cfg(unix)]
|
||||
let blksize = std::fs::metadata(defs::MODULE_DIR)?.blksize();
|
||||
#[cfg(not(unix))]
|
||||
let blksize = 0;
|
||||
// legacy image, it's block size is 1024 with unlimited journal size
|
||||
if blksize == 1024 {
|
||||
println!("- Legacy image, migrating to new format, please be patient...");
|
||||
create_module_image(tmp_module_img, sparse_image_size, journal_size)?;
|
||||
let _dontdrop =
|
||||
mount::AutoMountExt4::try_new(tmp_module_img, module_update_tmp_dir, true)?;
|
||||
fs_extra::dir::copy(
|
||||
defs::MODULE_DIR,
|
||||
module_update_tmp_dir,
|
||||
&fs_extra::dir::CopyOptions::new()
|
||||
.overwrite(true)
|
||||
.content_only(true),
|
||||
)?;
|
||||
} else {
|
||||
utils::copy_sparse_file(modules_img, tmp_module_img, true).with_context(|| {
|
||||
format!(
|
||||
"Failed to copy {} to {}",
|
||||
modules_img.display(),
|
||||
tmp_module_img
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure modules_update exists
|
||||
@@ -473,7 +445,7 @@ fn _install_module(zip: &str) -> Result<()> {
|
||||
// all done, rename the tmp image to modules_update.img
|
||||
if std::fs::rename(tmp_module_img, defs::MODULE_UPDATE_IMG).is_err() {
|
||||
warn!("Rename image failed, try copy it.");
|
||||
std::fs::copy(tmp_module_img, defs::MODULE_UPDATE_IMG)
|
||||
utils::copy_sparse_file(tmp_module_img, defs::MODULE_UPDATE_IMG, true)
|
||||
.with_context(|| "Failed to copy image.".to_string())?;
|
||||
let _ = std::fs::remove_file(tmp_module_img);
|
||||
}
|
||||
@@ -513,14 +485,14 @@ where
|
||||
modules_update_img.display(),
|
||||
modules_update_tmp_img.display()
|
||||
);
|
||||
std::fs::copy(modules_update_img, modules_update_tmp_img)?;
|
||||
utils::copy_sparse_file(modules_update_img, modules_update_tmp_img, true)?;
|
||||
} else {
|
||||
info!(
|
||||
"copy {} to {}",
|
||||
modules_img.display(),
|
||||
modules_update_tmp_img.display()
|
||||
);
|
||||
std::fs::copy(modules_img, modules_update_tmp_img)?;
|
||||
utils::copy_sparse_file(modules_img, modules_update_tmp_img, true)?;
|
||||
}
|
||||
|
||||
// ensure modules_update dir exist
|
||||
@@ -534,7 +506,7 @@ where
|
||||
|
||||
if let Err(e) = std::fs::rename(modules_update_tmp_img, defs::MODULE_UPDATE_IMG) {
|
||||
warn!("Rename image failed: {e}, try copy it.");
|
||||
std::fs::copy(modules_update_tmp_img, defs::MODULE_UPDATE_IMG)
|
||||
utils::copy_sparse_file(modules_update_tmp_img, defs::MODULE_UPDATE_IMG, true)
|
||||
.with_context(|| "Failed to copy image.".to_string())?;
|
||||
let _ = std::fs::remove_file(modules_update_tmp_img);
|
||||
}
|
||||
@@ -678,10 +650,12 @@ fn _list_modules(path: &str) -> Vec<HashMap<String, String>> {
|
||||
let enabled = !path.join(defs::DISABLE_FILE_NAME).exists();
|
||||
let update = path.join(defs::UPDATE_FILE_NAME).exists();
|
||||
let remove = path.join(defs::REMOVE_FILE_NAME).exists();
|
||||
let web = path.join(defs::MODULE_WEB_DIR).exists();
|
||||
|
||||
module_prop_map.insert("enabled".to_owned(), enabled.to_string());
|
||||
module_prop_map.insert("update".to_owned(), update.to_string());
|
||||
module_prop_map.insert("remove".to_owned(), remove.to_string());
|
||||
module_prop_map.insert("web".to_owned(), web.to_string());
|
||||
|
||||
if result.is_err() {
|
||||
warn!("Failed to parse module.prop: {}", module_prop.display());
|
||||
@@ -698,3 +672,21 @@ pub fn list_modules() -> Result<()> {
|
||||
println!("{}", serde_json::to_string_pretty(&modules)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn shrink_image(img: &str) -> Result<()> {
|
||||
check_image(img)?;
|
||||
Command::new("resize2fs")
|
||||
.arg("-M")
|
||||
.arg(img)
|
||||
.stdout(Stdio::piped())
|
||||
.status()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn shrink_ksu_images() -> Result<()> {
|
||||
shrink_image(defs::MODULE_IMG)?;
|
||||
if Path::new(defs::MODULE_UPDATE_IMG).exists() {
|
||||
shrink_image(defs::MODULE_UPDATE_IMG)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,62 +1,30 @@
|
||||
use anyhow::{bail, Ok, Result};
|
||||
use anyhow::{anyhow, bail, Ok, Result};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use anyhow::Context;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use retry::delay::NoDelay;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use sys_mount::{unmount, FilesystemType, Mount, MountFlags, Unmount, UnmountFlags};
|
||||
use rustix::{fd::AsFd, fs::CWD, mount::*};
|
||||
|
||||
use crate::defs::KSU_OVERLAY_SOURCE;
|
||||
use log::{info, warn};
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use procfs::process::Process;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct AutoMountExt4 {
|
||||
mnt: String,
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mount: Option<Mount>,
|
||||
target: String,
|
||||
auto_umount: bool,
|
||||
}
|
||||
|
||||
impl AutoMountExt4 {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn try_new(src: &str, mnt: &str, auto_umount: bool) -> Result<Self> {
|
||||
let result = Mount::builder()
|
||||
.fstype(FilesystemType::from("ext4"))
|
||||
.flags(MountFlags::empty())
|
||||
.create_loop(true)
|
||||
.mount(src, mnt)
|
||||
.map(|mount| {
|
||||
Ok(Self {
|
||||
mnt: mnt.to_string(),
|
||||
mount: Some(mount),
|
||||
auto_umount,
|
||||
})
|
||||
});
|
||||
if let Err(e) = result {
|
||||
println!("- Mount failed: {e}, retry with system mount");
|
||||
let result = std::process::Command::new("mount")
|
||||
.arg("-t")
|
||||
.arg("ext4")
|
||||
.arg(src)
|
||||
.arg(mnt)
|
||||
.status();
|
||||
if let Err(e) = result {
|
||||
Err(anyhow::anyhow!(
|
||||
"mount partition: {src} -> {mnt} failed: {e}"
|
||||
))
|
||||
} else {
|
||||
Ok(Self {
|
||||
mnt: mnt.to_string(),
|
||||
mount: None,
|
||||
auto_umount,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
result.unwrap()
|
||||
}
|
||||
pub fn try_new(source: &str, target: &str, auto_umount: bool) -> Result<Self> {
|
||||
mount_ext4(source, target)?;
|
||||
Ok(Self {
|
||||
target: target.to_string(),
|
||||
auto_umount,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
@@ -66,18 +34,8 @@ impl AutoMountExt4 {
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn umount(&self) -> Result<()> {
|
||||
if let Some(ref mount) = self.mount {
|
||||
mount
|
||||
.unmount(UnmountFlags::empty())
|
||||
.map_err(|e| anyhow::anyhow!(e))
|
||||
} else {
|
||||
let result = std::process::Command::new("umount").arg(&self.mnt).status();
|
||||
if let Err(e) = result {
|
||||
Err(anyhow::anyhow!("umount: {} failed: {e}", self.mnt))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
unmount(self.target.as_str(), UnmountFlags::DETACH)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +44,7 @@ impl Drop for AutoMountExt4 {
|
||||
fn drop(&mut self) {
|
||||
log::info!(
|
||||
"AutoMountExt4 drop: {}, auto_umount: {}",
|
||||
self.mnt,
|
||||
self.target,
|
||||
self.auto_umount
|
||||
);
|
||||
if self.auto_umount {
|
||||
@@ -95,99 +53,155 @@ impl Drop for AutoMountExt4 {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn mount_image(src: &str, target: &str, autodrop: bool) -> Result<()> {
|
||||
if autodrop {
|
||||
Mount::builder()
|
||||
.fstype(FilesystemType::from("ext4"))
|
||||
.create_loop(true)
|
||||
.mount_autodrop(src, target, UnmountFlags::empty())
|
||||
.with_context(|| format!("Failed to do mount: {src} -> {target}"))?;
|
||||
pub fn mount_ext4(source: impl AsRef<Path>, target: impl AsRef<Path>) -> Result<()> {
|
||||
let new_loopback = loopdev::LoopControl::open()?.next_free()?;
|
||||
new_loopback.with().attach(source)?;
|
||||
let lo = new_loopback.path().ok_or(anyhow!("no loop"))?;
|
||||
if let Result::Ok(fs) = fsopen("ext4", FsOpenFlags::FSOPEN_CLOEXEC) {
|
||||
let fs = fs.as_fd();
|
||||
fsconfig_set_string(fs, "source", lo)?;
|
||||
fsconfig_create(fs)?;
|
||||
let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?;
|
||||
move_mount(
|
||||
mount.as_fd(),
|
||||
"",
|
||||
CWD,
|
||||
target.as_ref(),
|
||||
MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
|
||||
)?;
|
||||
} else {
|
||||
Mount::builder()
|
||||
.fstype(FilesystemType::from("ext4"))
|
||||
.mount(src, target)
|
||||
.with_context(|| format!("Failed to do mount: {src} -> {target}"))?;
|
||||
mount(lo, target.as_ref(), "ext4", MountFlags::empty(), "")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn mount_ext4(src: &str, target: &str, autodrop: bool) -> Result<()> {
|
||||
// umount target first.
|
||||
let _ = umount_dir(target);
|
||||
let result = retry::retry(NoDelay.take(3), || mount_image(src, target, autodrop));
|
||||
result
|
||||
.map_err(|e| anyhow::anyhow!("mount partition: {src} -> {target} failed: {e}"))
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn umount_dir(src: &str) -> Result<()> {
|
||||
unmount(src, UnmountFlags::empty()).with_context(|| format!("Failed to umount {src}"))?;
|
||||
pub fn umount_dir(src: impl AsRef<Path>) -> Result<()> {
|
||||
unmount(src.as_ref(), UnmountFlags::empty())
|
||||
.with_context(|| format!("Failed to umount {}", src.as_ref().display()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn mount_overlayfs(
|
||||
pub fn mount_overlayfs(
|
||||
lower_dirs: &[String],
|
||||
lowest: impl AsRef<Path>,
|
||||
lowest: &str,
|
||||
upperdir: Option<PathBuf>,
|
||||
workdir: Option<PathBuf>,
|
||||
dest: impl AsRef<Path>,
|
||||
) -> Result<()> {
|
||||
let options = format!(
|
||||
"lowerdir={}:{}",
|
||||
lower_dirs.join(":"),
|
||||
lowest.as_ref().display()
|
||||
);
|
||||
let lowerdir_config = lower_dirs
|
||||
.iter()
|
||||
.map(|s| s.as_ref())
|
||||
.chain(std::iter::once(lowest))
|
||||
.collect::<Vec<_>>()
|
||||
.join(":");
|
||||
info!(
|
||||
"mount overlayfs on {}, options={}",
|
||||
dest.as_ref().display(),
|
||||
options
|
||||
"mount overlayfs on {:?}, lowerdir={}, upperdir={:?}, workdir={:?}",
|
||||
dest.as_ref(),
|
||||
lowerdir_config,
|
||||
upperdir,
|
||||
workdir
|
||||
);
|
||||
Mount::builder()
|
||||
.fstype(FilesystemType::from("overlay"))
|
||||
.data(&options)
|
||||
.flags(MountFlags::RDONLY)
|
||||
.mount(KSU_OVERLAY_SOURCE, dest.as_ref())
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"mount overlayfs on {} options {} failed",
|
||||
dest.as_ref().display(),
|
||||
options
|
||||
)
|
||||
})?;
|
||||
if let Result::Ok(fs) = fsopen("overlay", FsOpenFlags::FSOPEN_CLOEXEC) {
|
||||
let fs = fs.as_fd();
|
||||
fsconfig_set_string(fs, "lowerdir", lowerdir_config)?;
|
||||
if let (Some(upperdir), Some(workdir)) = (upperdir, workdir) {
|
||||
if upperdir.exists() && workdir.exists() {
|
||||
fsconfig_set_string(fs, "upperdir", upperdir.display().to_string())?;
|
||||
fsconfig_set_string(fs, "workdir", workdir.display().to_string())?;
|
||||
}
|
||||
}
|
||||
fsconfig_set_string(fs, "source", KSU_OVERLAY_SOURCE)?;
|
||||
fsconfig_create(fs)?;
|
||||
let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?;
|
||||
move_mount(
|
||||
mount.as_fd(),
|
||||
"",
|
||||
CWD,
|
||||
dest.as_ref(),
|
||||
MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
|
||||
)?;
|
||||
} else {
|
||||
let mut data = format!("lowerdir={lowerdir_config}");
|
||||
if let (Some(upperdir), Some(workdir)) = (upperdir, workdir) {
|
||||
if upperdir.exists() && workdir.exists() {
|
||||
data = format!(
|
||||
"{data},upperdir={},workdir={}",
|
||||
upperdir.display(),
|
||||
workdir.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
mount(
|
||||
KSU_OVERLAY_SOURCE,
|
||||
dest.as_ref(),
|
||||
"overlay",
|
||||
MountFlags::empty(),
|
||||
data,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn mount_tmpfs(dest: impl AsRef<Path>) -> Result<()> {
|
||||
info!("mount tmpfs on {}", dest.as_ref().display());
|
||||
Mount::builder()
|
||||
.fstype(FilesystemType::from("tmpfs"))
|
||||
.mount(KSU_OVERLAY_SOURCE, dest.as_ref())
|
||||
.with_context(|| format!("mount tmpfs on {} failed", dest.as_ref().display()))?;
|
||||
if let Result::Ok(fs) = fsopen("tmpfs", FsOpenFlags::FSOPEN_CLOEXEC) {
|
||||
let fs = fs.as_fd();
|
||||
fsconfig_set_string(fs, "source", KSU_OVERLAY_SOURCE)?;
|
||||
fsconfig_create(fs)?;
|
||||
let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?;
|
||||
move_mount(
|
||||
mount.as_fd(),
|
||||
"",
|
||||
CWD,
|
||||
dest.as_ref(),
|
||||
MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
|
||||
)?;
|
||||
} else {
|
||||
mount(
|
||||
KSU_OVERLAY_SOURCE,
|
||||
dest.as_ref(),
|
||||
"tmpfs",
|
||||
MountFlags::empty(),
|
||||
"",
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn bind_mount(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<()> {
|
||||
pub fn bind_mount(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<()> {
|
||||
info!(
|
||||
"bind mount {} -> {}",
|
||||
from.as_ref().display(),
|
||||
to.as_ref().display()
|
||||
);
|
||||
Mount::builder()
|
||||
.flags(MountFlags::BIND)
|
||||
.mount(from.as_ref(), to.as_ref())
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"bind mount failed: {} -> {}",
|
||||
from.as_ref().display(),
|
||||
to.as_ref().display()
|
||||
)
|
||||
})?;
|
||||
if let Result::Ok(tree) = open_tree(
|
||||
CWD,
|
||||
from.as_ref(),
|
||||
OpenTreeFlags::OPEN_TREE_CLOEXEC
|
||||
| OpenTreeFlags::OPEN_TREE_CLONE
|
||||
| OpenTreeFlags::AT_RECURSIVE,
|
||||
) {
|
||||
move_mount(
|
||||
tree.as_fd(),
|
||||
"",
|
||||
CWD,
|
||||
to.as_ref(),
|
||||
MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
|
||||
)?;
|
||||
} else {
|
||||
mount(
|
||||
from.as_ref(),
|
||||
to.as_ref(),
|
||||
"",
|
||||
MountFlags::BIND | MountFlags::REC,
|
||||
"",
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -222,7 +236,7 @@ fn mount_overlay_child(
|
||||
return Ok(());
|
||||
}
|
||||
// merge modules and stock
|
||||
if let Err(e) = mount_overlayfs(&lower_dirs, stock_root, mount_point) {
|
||||
if let Err(e) = mount_overlayfs(&lower_dirs, stock_root, None, None, mount_point) {
|
||||
warn!("failed: {:#}, fallback to bind mount", e);
|
||||
bind_mount(stock_root, mount_point)?;
|
||||
}
|
||||
@@ -230,7 +244,12 @@ fn mount_overlay_child(
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn mount_overlay(root: &String, module_roots: &Vec<String>) -> Result<()> {
|
||||
pub fn mount_overlay(
|
||||
root: &String,
|
||||
module_roots: &Vec<String>,
|
||||
workdir: Option<PathBuf>,
|
||||
upperdir: Option<PathBuf>,
|
||||
) -> Result<()> {
|
||||
info!("mount overlay for {}", root);
|
||||
std::env::set_current_dir(root).with_context(|| format!("failed to chdir to {root}"))?;
|
||||
let stock_root = ".";
|
||||
@@ -250,7 +269,8 @@ pub fn mount_overlay(root: &String, module_roots: &Vec<String>) -> Result<()> {
|
||||
mount_seq.sort();
|
||||
mount_seq.dedup();
|
||||
|
||||
mount_overlayfs(module_roots, root, root).with_context(|| "mount overlayfs for root failed")?;
|
||||
mount_overlayfs(module_roots, root, upperdir, workdir, root)
|
||||
.with_context(|| "mount overlayfs for root failed")?;
|
||||
for mount_point in mount_seq.iter() {
|
||||
let Some(mount_point) = mount_point else {
|
||||
continue;
|
||||
@@ -283,7 +303,12 @@ pub fn umount_dir(_src: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub fn mount_overlay(_dest: &String, _lower_dirs: &Vec<String>) -> Result<()> {
|
||||
pub fn mount_overlay(
|
||||
_root: &String,
|
||||
_module_roots: &Vec<String>,
|
||||
_workdir: Option<PathBuf>,
|
||||
_upperdir: Option<PathBuf>,
|
||||
) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
@@ -696,20 +696,7 @@ fn apply_one_rule<'a>(statement: &'a PolicyStatement<'a>, strict: bool) -> Resul
|
||||
let policies: Vec<AtomicStatement> = statement.try_into()?;
|
||||
|
||||
for policy in policies {
|
||||
let mut result: u32 = 0;
|
||||
let cpolicy = FfiPolicy::from(policy);
|
||||
unsafe {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
libc::prctl(
|
||||
crate::ksu::KERNEL_SU_OPTION as i32, // supposed to overflow
|
||||
crate::ksu::CMD_SET_SEPOLICY,
|
||||
0,
|
||||
std::ptr::addr_of!(cpolicy).cast::<libc::c_void>(),
|
||||
std::ptr::addr_of_mut!(result).cast::<libc::c_void>(),
|
||||
);
|
||||
}
|
||||
|
||||
if result != crate::ksu::KERNEL_SU_OPTION {
|
||||
if !rustix::process::ksu_set_policy(&FfiPolicy::from(policy)) {
|
||||
log::warn!("apply rule: {:?} failed.", statement);
|
||||
if strict {
|
||||
return Err(anyhow::anyhow!("apply rule {:?} failed.", statement));
|
||||
|
||||
@@ -12,6 +12,15 @@ use std::fs::{set_permissions, Permissions};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::prelude::PermissionsExt;
|
||||
|
||||
use hole_punch::*;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use rustix::{
|
||||
process,
|
||||
thread::{move_into_link_name_space, unshare, LinkNameSpaceType, UnshareFlags},
|
||||
};
|
||||
|
||||
pub fn ensure_clean_dir(dir: &str) -> Result<()> {
|
||||
let path = Path::new(dir);
|
||||
log::debug!("ensure_clean_dir: {}", path.display());
|
||||
@@ -112,24 +121,23 @@ pub fn get_zip_uncompressed_size(zip_path: &str) -> Result<u64> {
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn switch_mnt_ns(pid: i32) -> Result<()> {
|
||||
use anyhow::ensure;
|
||||
use std::os::fd::AsRawFd;
|
||||
use rustix::{
|
||||
fd::AsFd,
|
||||
fs::{open, Mode, OFlags},
|
||||
};
|
||||
let path = format!("/proc/{pid}/ns/mnt");
|
||||
let fd = std::fs::File::open(path)?;
|
||||
let fd = open(path, OFlags::RDONLY, Mode::from_raw_mode(0))?;
|
||||
let current_dir = std::env::current_dir();
|
||||
let ret = unsafe { libc::setns(fd.as_raw_fd(), libc::CLONE_NEWNS) };
|
||||
move_into_link_name_space(fd.as_fd(), Some(LinkNameSpaceType::Mount))?;
|
||||
if let std::result::Result::Ok(current_dir) = current_dir {
|
||||
let _ = std::env::set_current_dir(current_dir);
|
||||
}
|
||||
ensure!(ret == 0, "switch mnt ns failed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn unshare_mnt_ns() -> Result<()> {
|
||||
use anyhow::ensure;
|
||||
let ret = unsafe { libc::unshare(libc::CLONE_NEWNS) };
|
||||
ensure!(ret == 0, "unshare mnt ns failed");
|
||||
unshare(UnshareFlags::NEWNS)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -161,7 +169,7 @@ pub fn switch_cgroups() {
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn umask(mask: u32) {
|
||||
unsafe { libc::umask(mask) };
|
||||
process::umask(rustix::fs::Mode::from_raw_mode(mask));
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
@@ -182,3 +190,54 @@ pub fn get_tmp_path() -> &'static str {
|
||||
}
|
||||
""
|
||||
}
|
||||
|
||||
// TODO: use libxcp to improve the speed if cross's MSRV is 1.70
|
||||
pub fn copy_sparse_file<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||
src: P,
|
||||
dst: Q,
|
||||
punch_hole: bool,
|
||||
) -> Result<()> {
|
||||
let mut src_file = File::open(src.as_ref())?;
|
||||
let mut dst_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(dst.as_ref())?;
|
||||
|
||||
dst_file.set_len(src_file.metadata()?.len())?;
|
||||
|
||||
let segments = src_file.scan_chunks()?;
|
||||
for segment in segments {
|
||||
if let SegmentType::Data = segment.segment_type {
|
||||
let start = segment.start;
|
||||
let end = segment.end;
|
||||
|
||||
src_file.seek(SeekFrom::Start(start))?;
|
||||
dst_file.seek(SeekFrom::Start(start))?;
|
||||
|
||||
let mut buffer = [0; 4096];
|
||||
let mut total_bytes_copied = 0;
|
||||
|
||||
while total_bytes_copied < end - start {
|
||||
let bytes_to_read =
|
||||
std::cmp::min(buffer.len() as u64, end - start - total_bytes_copied);
|
||||
let bytes_read = src_file.read(&mut buffer[..bytes_to_read as usize])?;
|
||||
|
||||
if bytes_read == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if punch_hole && buffer[..bytes_read].iter().all(|&x| x == 0) {
|
||||
// all zero, don't copy it at all!
|
||||
dst_file.seek(SeekFrom::Current(bytes_read as i64))?;
|
||||
total_bytes_copied += bytes_read as u64;
|
||||
continue;
|
||||
}
|
||||
dst_file.write_all(&buffer[..bytes_read])?;
|
||||
total_bytes_copied += bytes_read as u64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ function sidebarGuide() {
|
||||
{ text: 'Intergrate for non-GKI devices', link: '/guide/how-to-integrate-for-non-gki'},
|
||||
{ text: 'Unofficially supported devices', link: '/guide/unofficially-support-devices.md' },
|
||||
{ text: 'Module Guide', link: '/guide/module.md' },
|
||||
{ text: 'Module WebUI', link: '/guide/module-webui.md' },
|
||||
{ text: 'App Profile', link: '/guide/app-profile.md' },
|
||||
{ text: 'Rescue from bootloop', link: '/guide/rescue-from-bootloop.md' },
|
||||
{ text: 'FAQ', link: '/guide/faq' },
|
||||
|
||||
@@ -23,7 +23,7 @@ export default defineConfig({
|
||||
|
||||
footer: {
|
||||
message: 'Lançado sob a Licença GPL3.',
|
||||
copyright: 'Copyright © Desenvolvedores KernelSU atuais de 2022'
|
||||
copyright: 'Copyright © Desenvolvedores do KernelSU atuais de 2022'
|
||||
},
|
||||
|
||||
editLink: {
|
||||
@@ -51,9 +51,10 @@ function sidebarGuide() {
|
||||
{ text: 'Integração para dispositivos não GKI', link: '/pt_BR/guide/how-to-integrate-for-non-gki'},
|
||||
{ text: 'Dispositivos com suporte não oficial', link: '/pt_BR/guide/unofficially-support-devices.md' },
|
||||
{ text: 'Guias de módulo', link: '/pt_BR/guide/module.md' },
|
||||
{ text: 'Módulo WebUI', link: '/pt_BR/guide/module-webui.md' },
|
||||
{ text: 'Perfil do Aplicativo', link: '/pt_BR/guide/app-profile.md' },
|
||||
{ text: 'Resgate do bootloop', link: '/pt_BR/guide/rescue-from-bootloop.md' },
|
||||
{ text: 'FAQ', link: '/pt_BR/guide/faq' },
|
||||
{ text: 'Perguntas frequentes', link: '/pt_BR/guide/faq' },
|
||||
{ text: 'Recursos ocultos', link: '/pt_BR/guide/hidden-features' },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -45,11 +45,13 @@ function sidebarGuide() {
|
||||
text: 'Guide',
|
||||
items: [
|
||||
{ text: '什么是 KernelSU?', link: '/zh_CN/guide/what-is-kernelsu' },
|
||||
{ text: 'KernelSU 模块与 Magisk 的差异', link: '/zh_CN/guide/difference-with-magisk' },
|
||||
{ text: '安装', link: '/zh_CN/guide/installation' },
|
||||
{ text: '如何构建?', link: '/zh_CN/guide/how-to-build' },
|
||||
{ text: '如何为非GKI设备集成 KernelSU', link: '/zh_CN/guide/how-to-integrate-for-non-gki'},
|
||||
{ text: '非官方支持设备', link: '/zh_CN/guide/unofficially-support-devices.md' },
|
||||
{ text: '模块开发指南', link: '/zh_CN/guide/module.md' },
|
||||
{ text: '模块 Web 界面', link: '/guide/module-webui.md' },
|
||||
{ text: 'App Profile', link: '/zh_CN/guide/app-profile.md' },
|
||||
{ text: '救砖', link: '/zh_CN/guide/rescue-from-bootloop.md' },
|
||||
{ text: '常见问题', link: '/zh_CN/guide/faq' },
|
||||
|
||||
@@ -66,3 +66,9 @@ We do not recommend you to modify the system partition directly. You should use
|
||||
## Can KernelSU modify hosts? How can i use AdAway?
|
||||
|
||||
Of course. But KernelSU doesn't have builtin hosts support, you can install [systemless-hosts](https://github.com/symbuzzer/systemless-hosts-KernelSU-module) to do it.
|
||||
|
||||
## Why is there a huge 1T file?
|
||||
|
||||
The 1T size `modules.img` is a disk image file, **don't worry about its size**, it's a special type of file known as a [sparse file](https://en.wikipedia.org/wiki/Sparse_file), its actual size is only the size of the module you use, and it will dynamically shrink after you delete the module; it does not actually occupy 1T of disk space (actually your mobile phone may not have that much space).
|
||||
|
||||
If you're really unhappy with the size of this file, you can use the `resize2fs -M` command to make it the actual size; but the module may not work properly at this time, and we won't provide any support for this.
|
||||
|
||||
@@ -62,7 +62,14 @@ curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh
|
||||
|
||||
:::
|
||||
|
||||
Then, add KernelSU calls to the kernel source, here is a patch to refer:
|
||||
Keep in mind that on some devices, your defconfig may be in `arch/arm64/configs` or in other cases `arch/arm64/configs/vendor/your_defconfig`. For example in your defconfig, Enable `CONFIG_KSU` with y to enable, or n to disable. Your path will be something like:
|
||||
`arch/arm64/configs/...`
|
||||
```
|
||||
# KernelSU
|
||||
CONFIG_KSU=y
|
||||
```
|
||||
|
||||
Then, add KernelSU calls to the kernel source, here are some patches to refer:
|
||||
|
||||
::: code-group
|
||||
|
||||
@@ -74,21 +81,25 @@ index ac59664eaecf..bdd585e1d2cc 100644
|
||||
@@ -1890,11 +1890,14 @@ static int __do_execve_file(int fd, struct filename *filename,
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern bool ksu_execveat_hook __read_mostly;
|
||||
+extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||
+ void *envp, int *flags);
|
||||
+extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
+ void *argv, void *envp, int *flags);
|
||||
+#endif
|
||||
static int do_execveat_common(int fd, struct filename *filename,
|
||||
struct user_arg_ptr argv,
|
||||
struct user_arg_ptr envp,
|
||||
int flags)
|
||||
{
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ if (unlikely(ksu_execveat_hook))
|
||||
+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags);
|
||||
+ else
|
||||
+ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags);
|
||||
+ #endif
|
||||
return __do_execve_file(fd, filename, argv, envp, flags, NULL);
|
||||
}
|
||||
```
|
||||
@@ -100,9 +111,11 @@ index 05036d819197..965b84d486b8 100644
|
||||
@@ -348,6 +348,8 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
|
||||
return ksys_fallocate(fd, mode, offset, len);
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
+ int *flags);
|
||||
+#endif
|
||||
/*
|
||||
* access() needs to use the real uid/gid, not the effective uid/gid.
|
||||
* We do this by temporarily clearing all FS-related capabilities and
|
||||
@@ -117,8 +130,9 @@ index 05036d819197..965b84d486b8 100644
|
||||
struct vfsmount *mnt;
|
||||
int res;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
|
||||
+ #endif
|
||||
|
||||
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
||||
return -EINVAL;
|
||||
@@ -131,16 +145,19 @@ index 650fc7e0f3a6..55be193913b6 100644
|
||||
@@ -434,10 +434,14 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_read);
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern bool ksu_vfs_read_hook __read_mostly;
|
||||
+extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||
+ size_t *count_ptr, loff_t **pos);
|
||||
+#endif
|
||||
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ if (unlikely(ksu_vfs_read_hook))
|
||||
+ ksu_handle_vfs_read(&file, &buf, &count, &pos);
|
||||
+ #endif
|
||||
+
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
return -EBADF;
|
||||
@@ -154,8 +171,10 @@ index 376543199b5a..82adcef03ecc 100644
|
||||
@@ -148,6 +148,8 @@ int vfs_statx_fd(unsigned int fd, struct kstat *stat,
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_statx_fd);
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
||||
+#endif
|
||||
+
|
||||
/**
|
||||
* vfs_statx - Get basic and extra attributes by filename
|
||||
@@ -163,8 +182,10 @@ index 376543199b5a..82adcef03ecc 100644
|
||||
@@ -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;
|
||||
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_stat(&dfd, &filename, &flags);
|
||||
+ #endif
|
||||
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
|
||||
AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
|
||||
return -EINVAL;
|
||||
@@ -189,17 +210,19 @@ index 068fdbcc9e26..5348b7bb9db2 100644
|
||||
@@ -87,6 +87,8 @@ int vfs_fstat(unsigned int fd, struct kstat *stat)
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_fstat);
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
||||
+
|
||||
+#endif
|
||||
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;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_stat(&dfd, &filename, &flag);
|
||||
+ #endif
|
||||
+
|
||||
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
|
||||
AT_EMPTY_PATH)) != 0)
|
||||
@@ -216,9 +239,11 @@ index 2ff887661237..e758d7db7663 100644
|
||||
@@ -355,6 +355,9 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
+ int *flags);
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* access() needs to use the real uid/gid, not the effective uid/gid.
|
||||
@@ -226,8 +251,9 @@ index 2ff887661237..e758d7db7663 100644
|
||||
@@ -370,6 +373,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
||||
int res;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
|
||||
+ #endif
|
||||
+
|
||||
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
||||
return -EINVAL;
|
||||
@@ -247,17 +273,20 @@ index 45306f9ef247..815091ebfca4 100755
|
||||
@@ -367,10 +367,13 @@ static int input_get_disposition(struct input_dev *dev,
|
||||
return disposition;
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern bool ksu_input_hook __read_mostly;
|
||||
+extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value);
|
||||
+#endif
|
||||
+
|
||||
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);
|
||||
+
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ if (unlikely(ksu_input_hook))
|
||||
+ ksu_handle_input_handle_event(&type, &code, &value);
|
||||
+ #endif
|
||||
|
||||
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
|
||||
add_input_randomness(type, code, value);
|
||||
|
||||
@@ -144,8 +144,8 @@ Android-Image-Kitchen is not recommended now, because it doesn't handle the boot
|
||||
### Using magiskboot on Android devices {#using-magiskboot-on-Android-devices}
|
||||
|
||||
1. Download latest Magisk from [Release Page](https://github.com/topjohnwu/Magisk/releases)
|
||||
2. Rename Magisk-*.apk to Magisk-vesion.zip and unzip it.
|
||||
3. Push `Magisk-v25.2/lib/arm64-v8a/libmagiskboot.so` to your device by adb: `adb push Magisk-v25.2/lib/arm64-v8a/libmagiskboot.so /data/local/tmp/magiskboot`
|
||||
2. Rename `Magisk-*(version).apk` to `Magisk-*.zip` and unzip it.
|
||||
3. Push `Magisk-*/lib/arm64-v8a/libmagiskboot.so` to your device by adb: `adb push Magisk-*/lib/arm64-v8a/libmagiskboot.so /data/local/tmp/magiskboot`
|
||||
4. Push stock boot.img and Image in AnyKernel3 to your device.
|
||||
5. Enter adb shell and cd `/data/local/tmp/` directory, then `chmod +x magiskboot`
|
||||
6. Enter adb shell and cd `/data/local/tmp/` directory, execute `./magiskboot unpack boot.img` to unpack `boot.img`, you will get a `kernel` file, this is your stock kernel.
|
||||
@@ -184,4 +184,4 @@ In fact, all these installation methods have only one main idea, which is to **r
|
||||
1. First install Magisk, get root privileges through Magisk and then use the kernel flasher to flash in the AnyKernel zip from KernelSU.
|
||||
2. Use some flashing toolkit on PCs to flash in the kernel provided KernelSU.
|
||||
|
||||
But if it doesn't work, please try `magiskboot` way.
|
||||
But if it doesn't work, please try `magiskboot` way.
|
||||
|
||||
48
website/docs/guide/module-webui.md
Normal file
48
website/docs/guide/module-webui.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Module WebUI
|
||||
|
||||
In addition to executing boot scripts and modifying system files, KernelSU's modules also support displaying UI interfaces and interacting with users.
|
||||
|
||||
The module can write HTML + CSS + JavaScript pages through any web technology. KernelSU's manager will display these pages through WebView. It also provides some APIs for interacting with the system, such as executing shell commands.
|
||||
|
||||
## webroot directory
|
||||
|
||||
Web resource files should be placed in the `webroot` subdirectory of the module root directory, and there **MUST** be a file named `index.html`, which is the module page entry. The simplest module structure containing a web interface is as follows:
|
||||
|
||||
```txt
|
||||
❯ tree .
|
||||
.
|
||||
|-- module.prop
|
||||
`-- webroot
|
||||
`-- index.html
|
||||
```
|
||||
|
||||
:::warning
|
||||
When installing the module, KernelSU will automatically set the permissions and SELinux context of this directory. If you don’t know what you are doing, please do not set the permissions of this directory yourself!
|
||||
:::
|
||||
|
||||
If your page contains CSS and JavaScript, you need to place it in this directory as well.
|
||||
|
||||
## JavaScript API
|
||||
|
||||
If it is just a display page, it is no different from a normal web page. More importantly, KernelSU provides a series of system API that allow you to implement the unique functions of the module.
|
||||
|
||||
KernelSU provides a JavaScript library and [publishes it on npm](https://www.npmjs.com/package/kernelsu), which you can use in the JavaScript code of your web pages.
|
||||
|
||||
For example, you can execute a shell command to obtain a specific configuration or modify a property:
|
||||
|
||||
```javascript
|
||||
import { exec } from 'kernelsu';
|
||||
|
||||
const { errno, stdout } = exec("getprop ro.product.model");
|
||||
```
|
||||
|
||||
For another example, you can make the web page display full screen, or display a toast.
|
||||
|
||||
[API documentation](https://www.npmjs.com/package/kernelsu)
|
||||
|
||||
If you find that the existing API does not meet your needs or is inconvenient to use, you are welcome to give us suggestions [here](https://github.com/tiann/KernelSU/issues)!
|
||||
|
||||
## Some tips
|
||||
|
||||
1. You can use `localStorage` normally to store some data, but it will be lost after the Manager App is uninstalled. If you need to save persistently, you can write data to some directory yourself.
|
||||
2. For simple pages, I recommend you use [parceljs](https://parceljs.org/) for packaging. It requires zero configuration and is very convenient to use. However, if you are a front-end master or have your own preferences, then just choose one you like!
|
||||
@@ -4,6 +4,10 @@ KernelSU provides a module mechanism that achieves the effect of modifying the s
|
||||
|
||||
The module mechanism of KernelSU is almost the same as that of Magisk. If you are familiar with Magisk module development, developing KernelSU modules is very similar. You can skip the introduction of modules below and only need to read [difference-with-magisk](difference-with-magisk.md).
|
||||
|
||||
## WebUI
|
||||
|
||||
KernelSU's modules support displaying interfaces and interacting with users, please refer to the [WebUI documentation](module-webui.md).
|
||||
|
||||
## Busybox
|
||||
|
||||
KernelSU ships with a feature complete BusyBox binary (including full SELinux support). The executable is located at `/data/adb/ksu/bin/busybox`. KernelSU's BusyBox supports runtime toggle-able "ASH Standalone Shell Mode". What this standalone mode means is that when running in the `ash` shell of BusyBox, every single command will directly use the applet within BusyBox, regardless of what is set as `PATH`. For example, commands like `ls`, `rm`, `chmod` will **NOT** use what is in `PATH` (in the case of Android by default it will be `/system/bin/ls`, `/system/bin/rm`, and `/system/bin/chmod` respectively), but will instead directly call internal BusyBox applets. This makes sure that scripts always run in a predictable environment and always have the full suite of commands no matter which Android version it is running on. To force a command _not_ to use BusyBox, you have to call the executable with full paths.
|
||||
|
||||
@@ -26,4 +26,3 @@ features:
|
||||
details: KernelSU allows customization of `su`'s uid, gid, groups, capabilities, and SELinux rules, locking up root privileges.
|
||||
- title: Modules
|
||||
details: Modules may modify /system systemlessly using overlayfs enabling great power.
|
||||
|
||||
|
||||
58
website/docs/ja_JP/guide/how-to-build.md
Normal file
58
website/docs/ja_JP/guide/how-to-build.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 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)
|
||||
|
||||
::: 警告
|
||||
このページは 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>` は、ビルドを一意に決定するマニフェストファイルです。マニフェストを使用して再現可能なビルドを行えます。マニフェストファイルは [Google 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 をビルドするのは簡単です。カーネルソースのルートディレクトリで任意のものを選択して実行します:
|
||||
|
||||
::: code-group
|
||||
```sh[最新タグ(安定版)]
|
||||
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
|
||||
```
|
||||
```sh[ main ブランチ (開発用)]
|
||||
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s main
|
||||
```
|
||||
```sh[タグを選択 (例:v0.5.2)]
|
||||
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -s v0.5.2
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
その後でカーネルを再ビルドすると、KernelSU が組み込まれたカーネルイメージが得られます!
|
||||
@@ -153,8 +153,8 @@ fastboot reboot
|
||||
### magiskboot を使う
|
||||
|
||||
1. 最新の Magisk を[リリースページ](https://github.com/topjohnwu/Magisk/releases)からダウンロードしてください。
|
||||
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`
|
||||
2. `Magisk-*(version).apk` を `Magisk-*.zip` に名前を変更して展開してください。
|
||||
3. `Magisk-*/lib/arm64-v8a/libmagiskboot.so`を adb でデバイスに転送します:`adb push Magisk-*/lib/arm64-v8a/libmagiskboot.so /data/local/tmp/magiskboot`
|
||||
4. 純正 boot.img と AnyKernel3 の中の Image をデバイスに転送します。
|
||||
5. adb shell に入り、`cd /data/local/tmp/` し、`chmod +x magiskboot` を実行します。
|
||||
6. adb shell に入り、`cd /data/local/tmp/` し、`./magiskboot unpack boot.img` を実行して `boot.img` を抽出します。`kernel` ファイルが純正カーネルです。
|
||||
@@ -166,4 +166,4 @@ fastboot reboot
|
||||
実はこれらのインストール方法はすべて、**元のカーネルを KernelSU が提供するカーネルに置き換える**という主旨でしかなく、これが実現できれば他の方法でもインストール可能です:
|
||||
|
||||
1. まず Magisk をインストールし、Magisk を通じて root 権限を取得し、カーネル管理アプリで KernelSU の AnyKernel ZIPをインストールする
|
||||
2. PC 上で何らかの書き込みツールを使用し、KernelSU が提供するカーネルを書き込む
|
||||
2. PC 上で何らかの書き込みツールを使用し、KernelSU が提供するカーネルを書き込む
|
||||
|
||||
48
website/docs/ja_JP/guide/module-webui.md
Normal file
48
website/docs/ja_JP/guide/module-webui.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Module WebUI
|
||||
|
||||
KernelSU のモジュールは、ブートスクリプトの実行やシステムファイルの修正に加えて、UI インターフェースの表示やユーザーとの対話もサポートしています。
|
||||
|
||||
モジュールは、任意の Web 技術を通じて HTML + CSS + JavaScript のページを作成することができます。KernelSU のマネージャーは WebView を通じてこれらのページを表示します。また、シェルコマンドの実行など、システムと対話するためのいくつかのAPIを提供しています。
|
||||
|
||||
## webroot ディレクトリ
|
||||
|
||||
Web リソースファイルは、モジュールのルートディレクトリの webroot サブディレクトリに置かれるべきであり、index.html という名前のファイルが必ず存在しなければなりません。これがモジュールページのエントリです。Web インターフェイスを含む最もシンプルなモジュール構造は以下の通りです:
|
||||
|
||||
```txt
|
||||
❯ tree .
|
||||
.
|
||||
|-- module.prop
|
||||
`-- webroot
|
||||
`-- index.html
|
||||
```
|
||||
|
||||
:::警告
|
||||
モジュールをインストールするとき、KernelSU はこのディレクトリのパーミッションと SELinux コンテキストを自動的に設定します。何をしているかわからないのであれば、自分でこのディレクトリのパーミッションを設定しないでください!
|
||||
:::
|
||||
|
||||
ページに css や JavaScript が含まれている場合は、このディレクトリに配置する必要があります。
|
||||
|
||||
## Javascript API
|
||||
|
||||
単なる表示ページであれば、通常の Web ページとの違いはありません。より重要なのは、KernelSU がモジュールの固有機能を実装させるための一連のシステム API を提供することです。
|
||||
|
||||
KernelSU は Javascript ライブラリを提供し、[npm で公開しています](https://www.npmjs.com/package/kernelsu)。これを Web ページの JavaScript コードで使用することができます。
|
||||
|
||||
たとえば、特定の設定を取得したり、プロパティを変更するために、シェルコマンドを実行することができます:
|
||||
|
||||
```javascript
|
||||
import { exec } from 'kernelsu';
|
||||
|
||||
const { errno, stdout } = exec("getprop ro.product.model");
|
||||
```
|
||||
|
||||
別の例として、Webページをフルスクリーンで表示したり、トーストを表示することができます。
|
||||
|
||||
[API ドキュメント](https://www.npmjs.com/package/kernelsu)
|
||||
|
||||
既存のAPIがご自身のニーズを満たしていない、または使い勝手が不便である場合、[こちら](https://github.com/tiann/KernelSU/issues)でご提案いただければ幸いです!
|
||||
|
||||
## いくつかのヒント
|
||||
|
||||
1. localStorage を通常通りに使用してデータを保存することができますが、Manager アプリをアンインストールした後には失われます。永続的に保存する必要がある場合は、自分でいくつかのディレクトリにデータを書き込むことができます。
|
||||
2. シンプルなページには、[parceljs](https://parceljs.org/)を使用することをお勧めします。設定が不要で非常に便利です。しかし、フロントエンドの達人である場合や、自分の好みがある場合は、気に入ったものを選んでください!
|
||||
@@ -106,7 +106,7 @@ Se você realmente precisa conceder permissões de root ao ADB (por exemplo, com
|
||||
|
||||
### Desmontar módulos
|
||||
|
||||
O KernelSU fornece um mecanismo sem sistema para modificar partições do sistema, obtido através da montagem de overlayfs. No entanto, alguns apps podem ser sensíveis a esse comportamento. Assim, podemos descarregar módulos montados nesses apps configurando a opção “desmontar módulos”.
|
||||
O KernelSU fornece um mecanismo sem sistema para modificar partições do sistema, obtido através da montagem de OverlayFS. No entanto, alguns apps podem ser sensíveis a esse comportamento. Assim, podemos descarregar módulos montados nesses apps configurando a opção “desmontar módulos”.
|
||||
|
||||
Além disso, a interface de configurações do gerenciador KernelSU fornece uma opção para "desmontar módulos por padrão". Por padrão, essa opção está **ativada**, o que significa que o KernelSU ou alguns módulos descarregarão módulos para este app, a menos que configurações adicionais sejam aplicadas. Se você não preferir esta configuração ou se ela afetar determinados apps, você terá as seguintes opções:
|
||||
|
||||
|
||||
@@ -25,4 +25,4 @@ Aqui estão algumas diferenças:
|
||||
- Os diretórios do BusyBox são diferentes. O BusyBox integrado no KernelSU está localizado em `/data/adb/ksu/bin/busybox`, enquanto no Magisk está em `/data/adb/magisk/busybox`. **Observe que este é um comportamento interno do KernelSU e pode mudar no futuro!**
|
||||
- O KernelSU não suporta arquivos `.replace`, entretanto, o KernelSU suporta as variáveis `REMOVE` e `REPLACE` para remover ou substituir arquivos e pastas.
|
||||
- O KernelSU adiciona o estágio `boot-completed` para executar alguns scripts na inicialização concluída.
|
||||
- O KernelSU adiciona o estágio `post-mount` para executar alguns scripts após montar overlayfs.
|
||||
- O KernelSU adiciona o estágio `post-mount` para executar alguns scripts após montar OverlayFS.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# FAQ
|
||||
# Perguntas frequentes
|
||||
|
||||
## KernelSU oferece suporte ao meu dispositivo?
|
||||
|
||||
@@ -66,3 +66,9 @@ Não recomendamos que você modifique a partição do sistema diretamente. Você
|
||||
## O KernelSU pode modificar hosts? Como posso usar AdAway?
|
||||
|
||||
Claro. Mas o KernelSU não tem suporte a hosts integrados, você pode instalar [systemless-hosts](https://github.com/symbuzzer/systemless-hosts-KernelSU-module) para fazer isso.
|
||||
|
||||
## Por que existe um enorme arquivo de 1T?
|
||||
|
||||
O arquivo `modules.img` de 1T é um arquivo de imagem de disco, **não se preocupe com seu tamanho**, é um tipo especial de arquivo conhecido como [arquivo esparso](https://en.wikipedia.org/wiki/Sparse_file), seu tamanho real é apenas o tamanho do módulo que você usa e diminuirá dinamicamente após você excluir o módulo. Na verdade, ele não ocupa 1T de espaço em disco (na verdade, seu celular pode não ter tanto espaço).
|
||||
|
||||
Se você estiver realmente insatisfeito com o tamanho deste arquivo, você pode usar o comando `resize2fs -M` para torná-lo seu tamanho real, mas o módulo pode não funcionar corretamente neste momento e não forneceremos nenhum suporte para isso.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
O KernelSU pode ser integrado em kernels não GKI e foi portado para 4.14 e versões anteriores.
|
||||
|
||||
Devido à fragmentação de kernels não GKI, não temos uma maneira uniforme de construí-lo, portanto não podemos fornecer imagens boot não GKI. Mas você mesmo pode construir o kernel com o KernelSU integrado.
|
||||
Devido à fragmentação de kernels não GKI, não temos uma maneira uniforme de construí-lo, portanto não podemos fornecer boot.img não GKI. Mas você mesmo pode construir o kernel com o KernelSU integrado.
|
||||
|
||||
Primeiro, você deve ser capaz de construir um kernel inicializável a partir do código-fonte do kernel. Se o kernel não for de código aberto, será difícil executar o KernelSU no seu dispositivo.
|
||||
|
||||
@@ -33,7 +33,7 @@ E construa seu kernel novamente, KernelSU deve funcionar bem.
|
||||
|
||||
Se você descobrir que o KPROBES ainda não está ativado, você pode tentar ativar `CONFIG_MODULES`. (Se ainda assim não surtir efeito, use `make menuconfig` para procurar outras dependências do KPROBES)
|
||||
|
||||
Mas se você entrar em um bootloop quando o KernelSU for integrado, talvez o **kprobe esteja quebrado em seu kernel**, você deve corrigir o bug do kprobe ou usar o segundo caminho.
|
||||
Mas se você entrar em um bootloop quando o KernelSU for integrado, talvez o **kprobe esteja quebrado em seu kernel**. Você deve corrigir o bug do kprobe ou usar o segundo caminho.
|
||||
|
||||
:::tip COMO VERIFICAR SE O KPROBE ESTÁ QUEBRADO?
|
||||
|
||||
@@ -62,7 +62,14 @@ curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh
|
||||
|
||||
:::
|
||||
|
||||
Em seguida, adicione chamadas KernelSU à fonte do kernel. Aqui está um patch para referência:
|
||||
Tenha em mente que em alguns dispositivos, seu defconfig pode estar em `arch/arm64/configs` ou em outros casos `arch/arm64/configs/vendor/your_defconfig`. Por exemplo, em seu defconfig, habilite `CONFIG_KSU` com y para habilitar ou n para desabilitar. Seu caminho será algo como:
|
||||
`arch/arm64/configs/...`
|
||||
```
|
||||
# KernelSU
|
||||
CONFIG_KSU=y
|
||||
```
|
||||
|
||||
Em seguida, adicione chamadas KernelSU à fonte do kernel. Aqui estão alguns patches para referência:
|
||||
|
||||
::: code-group
|
||||
|
||||
@@ -74,21 +81,25 @@ index ac59664eaecf..bdd585e1d2cc 100644
|
||||
@@ -1890,11 +1890,14 @@ static int __do_execve_file(int fd, struct filename *filename,
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern bool ksu_execveat_hook __read_mostly;
|
||||
+extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||
+ void *envp, int *flags);
|
||||
+extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
+ void *argv, void *envp, int *flags);
|
||||
+#endif
|
||||
static int do_execveat_common(int fd, struct filename *filename,
|
||||
struct user_arg_ptr argv,
|
||||
struct user_arg_ptr envp,
|
||||
int flags)
|
||||
{
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ if (unlikely(ksu_execveat_hook))
|
||||
+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags);
|
||||
+ else
|
||||
+ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags);
|
||||
+ #endif
|
||||
return __do_execve_file(fd, filename, argv, envp, flags, NULL);
|
||||
}
|
||||
```
|
||||
@@ -100,9 +111,11 @@ index 05036d819197..965b84d486b8 100644
|
||||
@@ -348,6 +348,8 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
|
||||
return ksys_fallocate(fd, mode, offset, len);
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
+ int *flags);
|
||||
+#endif
|
||||
/*
|
||||
* access() precisa usar o uid/gid real, não o uid/gid efetivo.
|
||||
* Fazemos isso limpando temporariamente todos os recursos relacionados ao FS e
|
||||
@@ -117,8 +130,9 @@ index 05036d819197..965b84d486b8 100644
|
||||
struct vfsmount *mnt;
|
||||
int res;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
|
||||
+ #endif
|
||||
|
||||
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
||||
return -EINVAL;
|
||||
@@ -131,16 +145,19 @@ index 650fc7e0f3a6..55be193913b6 100644
|
||||
@@ -434,10 +434,14 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_read);
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern bool ksu_vfs_read_hook __read_mostly;
|
||||
+extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||
+ size_t *count_ptr, loff_t **pos);
|
||||
+#endif
|
||||
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ if (unlikely(ksu_vfs_read_hook))
|
||||
+ ksu_handle_vfs_read(&file, &buf, &count, &pos);
|
||||
+ #endif
|
||||
+
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
return -EBADF;
|
||||
@@ -154,8 +171,10 @@ index 376543199b5a..82adcef03ecc 100644
|
||||
@@ -148,6 +148,8 @@ int vfs_statx_fd(unsigned int fd, struct kstat *stat,
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_statx_fd);
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
||||
+#endif
|
||||
+
|
||||
/**
|
||||
* vfs_statx - Obtenha atributos básicos e extras por filename
|
||||
@@ -163,8 +182,10 @@ index 376543199b5a..82adcef03ecc 100644
|
||||
@@ -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;
|
||||
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_stat(&dfd, &filename, &flags);
|
||||
+ #endif
|
||||
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
|
||||
AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
|
||||
return -EINVAL;
|
||||
@@ -189,17 +210,19 @@ index 068fdbcc9e26..5348b7bb9db2 100644
|
||||
@@ -87,6 +87,8 @@ int vfs_fstat(unsigned int fd, struct kstat *stat)
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_fstat);
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
||||
+
|
||||
+#endif
|
||||
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;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_stat(&dfd, &filename, &flag);
|
||||
+ #endif
|
||||
+
|
||||
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
|
||||
AT_EMPTY_PATH)) != 0)
|
||||
@@ -216,9 +239,11 @@ index 2ff887661237..e758d7db7663 100644
|
||||
@@ -355,6 +355,9 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
+ int *flags);
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* access() precisa usar o uid/gid real, não o uid/gid efetivo.
|
||||
@@ -226,8 +251,9 @@ index 2ff887661237..e758d7db7663 100644
|
||||
@@ -370,6 +373,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
||||
int res;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW;
|
||||
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
|
||||
+ #endif
|
||||
+
|
||||
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
||||
return -EINVAL;
|
||||
@@ -247,17 +273,20 @@ index 45306f9ef247..815091ebfca4 100755
|
||||
@@ -367,10 +367,13 @@ static int input_get_disposition(struct input_dev *dev,
|
||||
return disposition;
|
||||
}
|
||||
|
||||
|
||||
+#ifdef CONFIG_KSU
|
||||
+extern bool ksu_input_hook __read_mostly;
|
||||
+extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value);
|
||||
+#endif
|
||||
+
|
||||
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);
|
||||
+
|
||||
+ #ifdef CONFIG_KSU
|
||||
+ if (unlikely(ksu_input_hook))
|
||||
+ ksu_handle_input_handle_event(&type, &code, &value);
|
||||
+ #endif
|
||||
|
||||
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
|
||||
add_input_randomness(type, code, value);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user