Compare commits

..

115 Commits

Author SHA1 Message Date
weishu
3ad27c5999 kernel: use macro for default domain 2023-06-06 21:07:25 +08:00
weishu
5b27f6c010 kernel: Fix shell permission under KSU_DEBUG 2023-06-06 21:05:37 +08:00
weishu
be44fad288 ci: android13-5.15-2022-11 is deprecated: https://android.googlesource.com/kernel/common/+refs 2023-06-06 20:59:15 +08:00
weishu
2a5fb76f95 manager: sync kernel struct and bump profile version 2023-06-06 20:56:27 +08:00
weishu
5db7075432 kernel: bump format version to force clear allowlist, prepare to release a new version 2023-06-06 20:49:39 +08:00
weishu
1408175a35 kernel: fix set groups for kernel 4.9- 2023-06-06 20:45:42 +08:00
weishu
ab1dc894e1 manager: disable template ui temporarily 2023-06-06 19:06:03 +08:00
weishu
c5bc1c8b15 manager: make template ui work 2023-06-06 17:54:57 +08:00
Soo-Hwan Na
6d1ee60d67 kernel/selinux: Need to force include errno.h sometimes (#572)
- Seen with Linux 4.14 kernel with error message:

In file included from ../drivers/android/kernelsu/selinux/sepolicy.c:1:
In file included from ../drivers/android/kernelsu/selinux/sepolicy.h:6:
In file included from ../security/selinux/ss/policydb.h:30: In file
included from ../security/selinux/ss/avtab.h:26:
../security/selinux/include/security.h:240:10: error: use of undeclared
identifier 'EIDRM'
        return -EIDRM;
                ^
  CC      drivers/base/transport_class.o
  CC      kernel/rcu/update.o
../security/selinux/include/security.h:246:10: error: use of undeclared
identifier 'ENOENT'
        return -ENOENT;
                ^
2023-06-06 16:42:45 +08:00
weishu
a58e929205 manager: Default selinux context should be "u:r:su:s0" 2023-06-06 16:37:14 +08:00
weishu
53be8612c8 kernel: support setting selinux context for profile 2023-06-06 16:35:25 +08:00
weishu
c7f6a7d11b kernel: support settings supplementary groups for profile 2023-06-06 13:19:11 +08:00
weishu
e9011041c5 manager: Fix groups overflow, close #598 2023-06-06 12:40:07 +08:00
weishu
9803371fdb ci: respect the CONFIG_KSU options (#599)
close #596, #597
2023-06-06 12:12:27 +08:00
weishu
710edb72fa kernel: prevent root process to exec su, which makes app can escape root profile by exec it twice 2023-06-06 11:08:57 +08:00
Igor Sorocean
a4ddf59562 Update ro translation (#595) 2023-06-05 22:40:44 +08:00
weishu
37dc9a27a7 kernel: fix incorrect prune uid for work profile app, close #587 2023-06-05 17:41:41 +08:00
weishu
27ccfa6395 manager: change minimal CAP to DAC_READ_SEARCH 2023-06-05 10:17:10 +08:00
weishu
116bc56cfe manager: Fix set profile failed. 2023-06-05 10:10:16 +08:00
weishu
9ae0126be5 manager: Add default minimal caps for default root profile 2023-06-05 09:08:41 +08:00
weishu
e8755f8ae0 manager: Fix groups and caps selection, close #592 2023-06-05 08:31:15 +08:00
Gustavo Mendes
6ba2bd3af9 Add Portuguese brazilian translation (#593)
Signed-off-by: Gustavo Mendes <gusttavo.me@outlook.com>
2023-06-05 08:24:41 +08:00
raystef66
4c5e485e76 Update Flemish/Dutch translation (#590) 2023-06-05 05:48:10 +08:00
Womsxd
05c6892f43 ksubot.py: Increase timeout (#589)
Increase the timeout duration and try to resolve the
'telegram.error.TimedOut: Timed out' issue when sending messages in a
Telegram group.
2023-06-04 23:31:37 +08:00
weishu
670a20c37f manager: Fix selection 2023-06-04 23:24:19 +08:00
weishu
75509aba72 ksud: fix gid is override by uid 2023-06-04 23:14:44 +08:00
weishu
887f02e742 manager: optimize uid/gid panel 2023-06-04 23:14:44 +08:00
Hikari-no-Tenshi
ef8da39d34 manager: Update Ukrainian translation (#584) 2023-06-04 21:41:46 +08:00
Jia-Bin
b7c759ece1 Update Traditional Chinese (#586)
Update Traditional Chinese
Modify the translation to meet localization and usage habits
2023-06-04 21:36:32 +08:00
weishu
019da4a634 ksud: respect the kernel default uid 2023-06-04 18:09:58 +08:00
weishu
33aa6de50b manager: Add desc for umount modules. 2023-06-04 17:42:58 +08:00
weishu
0b3688c3b1 manager: unify kernel and user structs 2023-06-04 17:29:31 +08:00
weishu
076e5d3655 kernel: make the profile uid, gid, capabilities really work 2023-06-04 17:29:12 +08:00
weishu
c9608af0c8 manager: fix capabilities and namespace save/load 2023-06-04 16:12:03 +08:00
weishu
908fbadaf5 manager: remove unused resources 2023-06-04 16:12:02 +08:00
weishu
ee97fdfc56 kernel: add more capailities 2023-06-04 16:09:27 +08:00
weishu
4ac137313f manager: rename "umount modules" -> "Hide modules" 2023-06-04 14:25:50 +08:00
weishu
11d0029a4b manager: Add default groups when empty 2023-06-04 14:25:50 +08:00
weishu
8af5a9038b kernel: fix set app profile may override other user's 2023-06-04 13:59:22 +08:00
weishu
5d449988fb manager: Fix app profile umount default 2023-06-04 09:58:02 +08:00
weishu
e969563df0 manager: Add UMOUNT badge 2023-06-04 09:52:51 +08:00
weishu
990626cf7d kernel: Fixing the issue of a delay in updating the default profile. 2023-06-04 09:47:31 +08:00
weishu
fc77ca989f kernel: use uid instead of package to compare allowlist, fix #580 2023-06-04 09:18:39 +08:00
diphons
2ce3976023 Fixup: build under linux 4.14 (#581)
Split compiler_types.h from compiler.h only available for linux 4.14
2023-06-04 09:15:03 +08:00
weishu
63ec531814 kernel: dont prune uid used for app profile 2023-06-04 01:01:39 +08:00
weishu
a4b55b30ca manager: Add log for fallbacked app profile 2023-06-04 00:59:59 +08:00
weishu
807556f361 manager: show default value for app profile. 2023-06-04 00:22:36 +08:00
weishu
2d854f2f37 manager: the default value of umountModules is actually "true" in kernel 2023-06-04 00:05:19 +08:00
weishu
5980c113fe kernel: respect the app profile's umount modules field for kernel umounting 2023-06-04 00:03:56 +08:00
weishu
1491465b55 manager: require kernel 10931 2023-06-03 23:58:23 +08:00
weishu
728380222a kernel: Add version field for struct app_profile 2023-06-03 23:57:05 +08:00
weishu
005404f552 kernel: support load/restore default profiles 2023-06-03 23:57:05 +08:00
weishu
b55c229038 manager: add support for setting default non root profile. 2023-06-03 23:54:15 +08:00
weishu
32538c9833 manager: remove unused 2023-06-03 23:54:15 +08:00
weishu
b31fc47197 kernel: support CMD_IS_UID_GRANTED_ROOT and CMD_IS_UID_SHOULD_UMOUNT 2023-06-03 22:44:01 +08:00
s1204IT
5003824fa8 Update WSA Kernel (#575)
Remove: 5.10.117.2
Change: 5.15.98.1 -> 5.15.98.**4**
2023-06-03 19:29:04 +08:00
Hikari-no-Tenshi
eea75b72a4 manager: Update Ukrainian translation (#579) 2023-06-03 19:28:38 +08:00
weishu
82d5ec3cc1 kernel: fix CMD_GET_ALLOW_LIST error 2023-06-03 19:23:51 +08:00
weishu
75721be8c0 manager: use default profile when kernel return null. 2023-06-03 17:26:38 +08:00
weishu
de72eedb46 kernel: don't copy profile when not found 2023-06-03 17:26:00 +08:00
weishu
66827ab7de manager: show profile info in superuser list 2023-06-03 17:17:19 +08:00
weishu
2a33433272 manager: don't obfuscate Profile 2023-06-03 16:20:13 +08:00
weishu
581dff8a5f manager: only show warning when installed. 2023-06-03 15:30:51 +08:00
weishu
fc425cbba2 manager: remove semicolon for require new version 2023-06-03 15:25:54 +08:00
weishu
87f55c1acb manager: Add require new kernel version. 2023-06-03 15:23:35 +08:00
weishu
68d639e325 manager: Add groups and caps for profile 2023-06-03 15:01:57 +08:00
weishu
89f6cd044e kernel: minor fixes for profiles 2023-06-03 10:18:11 +08:00
weishu
bd3a1291da kernel: don't fill default value for app profile 2023-06-03 00:06:58 +08:00
weishu
3abb7e4ca2 kernel: baby version of profile 2023-06-03 00:01:00 +08:00
weishu
41265b0203 manager: implement app profile api call 2023-06-02 23:58:07 +08:00
sajadasadollahi83
f2cb841b8a Update Persian Translation. (#569) 2023-06-02 16:01:46 +08:00
dabao1955
c69da29081 Kconfig:Update text information (#567)
![Screenshot_2023-05-31-12-56-27-57_84d3000e3f4017145260f7618db1d683](https://github.com/tiann/KernelSU/assets/79307765/84ab8d8e-c034-4567-b815-ebeccde1fdbc)

![Screenshot_2023-05-31-12-56-09-68_84d3000e3f4017145260f7618db1d683](https://github.com/tiann/KernelSU/assets/79307765/a4209212-997f-4e2f-bbcb-2c5136ab6e71)
2023-06-02 10:41:40 +08:00
github-actions[bot]
e304ef8cfb [add device]: Kernel 4.14.194 exynos9610 Non-GKI Device, Added KernelSu using manual method (#574)
Kernel 4.14.194 exynos9610 Non-GKI Device, Added KernelSu using manual
method has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/573

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-06-02 10:31:41 +08:00
Hikari-no-Tenshi
2ce76351da manager: Scroll app profile view (#565)
close #536
2023-05-31 13:04:22 +08:00
sajadasadollahi83
66cbd931a7 Create strings.xml (#561)
add translation for persian.
2023-05-31 12:44:06 +08:00
s1204IT
07bc28e386 Fix README languages (#564) 2023-05-31 12:08:58 +08:00
AndroPlus
2ef4ffe5eb Update Japanese readme (#560)
Changed the installation link to Japanese one (build page is English)
2023-05-29 20:17:43 +08:00
Murat Kozan
128e7e394e Update Turkish translation (#553) 2023-05-29 10:30:59 +08:00
Akari
998dc9b94b added support(README.md) for Brazilian Portuguese (#558)
added README_PT-BR.md support as mentioned before, for Brazilian
Portuguese.
2023-05-29 10:30:23 +08:00
Hikari-no-Tenshi
c6dafb1333 manager: Shorten long Ukrainian strings (#550) 2023-05-25 11:46:47 +08:00
Hikari-no-Tenshi
8ae7299d59 manager: Update Ukrainian translation (#540) 2023-05-23 10:49:39 +08:00
raystef66
8f1b9c579b Update Flemish/Dutch translation (#541) 2023-05-23 10:43:33 +08:00
ahmeda9a
4b6573b521 Fine tuning for Arabic translation. (#543)
Done some changes to make the translation Arabic clearer
2023-05-23 10:43:03 +08:00
Eduardo Novella
325e843569 (scripts) check_v2.c -add missing header (#548) 2023-05-23 10:24:42 +08:00
dabao1955
d014947a54 change warning about disable kprobes (#549)
#479


Co-authored-by: dabao1955 <195328750@qq.com>
2023-05-23 10:24:18 +08:00
weishu
8858cc899e kernel: remove no-macro-redefined 2023-05-22 10:50:04 +08:00
weishu
8f3e59803f kernel: fix format warnning 2023-05-22 10:39:54 +08:00
weishu
95044bb551 kernel: fix incorrect prune uid in allowlist for work profile app. close #535 2023-05-22 10:32:20 +08:00
Aquarius223
b56448a929 kernel: Modify and adjust KernelSU Kconfig (#538)
1. List KSU as a "KernelSU" menu
2. Overlayfs[1] may be disabled for some early kernels(4.4.y), so
choosing depends on OVERLAY_FS here is useless.
3. KSU_DEBUG is a bool option, it is not a module, fixed from tristate
to bool.
4. Adjust the config order

[1]: github.com/LineageOS/android_kernel_xiaomi_msm8998/commit/dcc27641

Change-Id: I49c77ba30f0a8ed00efc44afef8a12f9ad039d7e

Co-authored-by: admin <paper@localhost>
2023-05-21 20:28:59 +08:00
Mohamed Elsayed
c2b981dbdb Update Arabic translation (#534) 2023-05-20 11:36:29 +08:00
Muhammad Fadlyas
28fb482720 Update Indonesian translation (#532) 2023-05-20 11:28:37 +08:00
Muhammad Fadlyas
d744a705a8 Fix little typo in README.md (#531) 2023-05-20 09:53:38 +08:00
Nipin NA
c62b89f02b [add device]: Xiaomi Redmi Note 7 Pro (violet) (#524) 2023-05-17 17:17:00 +08:00
AndroPlus
f876b0114e Update Japanese translation (#518) 2023-05-17 17:16:24 +08:00
diphons
9965988f26 [add device]: Xiaomi Poco F1 (#520)
Also update link device Xiaomi Poco X3 Pro
2023-05-17 12:43:39 +08:00
github-actions[bot]
828bb6fbb4 [add device]: OPPO Reno6 on ColorOS11.x/ColorOS12.x,kernel version4.14.186+ (#522)
OPPO Reno6 on ColorOS11.x/ColorOS12.x,kernel version4.14.186+ has been
added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/521

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-17 12:43:06 +08:00
Howard Wu
10d8d9efcd ci: upgrade android13 kernel version (#516)
+ android13-5.10.168
+ android13-5.15.94
2023-05-17 10:48:13 +08:00
AndroPlus
e59f3333cb Update and fix Japanese translation (#517) 2023-05-17 10:00:46 +08:00
Nullptr
31a9189d80 manager: several UI improvements (#515) 2023-05-17 09:34:08 +08:00
dabao1955
d162221fac a little change (#513)
Though it is a little not suitable?
2023-05-17 09:31:38 +08:00
weishu
0cdca0d053 website: fix build error 2023-05-16 23:54:36 +08:00
AndroPlus
4c934d460b Update Japanese translation (#508)
I'm not familiar with vitepress, so there may be some mistakes in the
settings.
2023-05-16 23:40:54 +08:00
Nullptr
76612b9cf7 manager: several updates (#510)
+ update deps
+ update app profile page
+ don't show su and module page if no root
2023-05-16 22:32:48 +08:00
github-actions[bot]
9cf8ac9c51 [add device]: (#512)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/511

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-16 22:31:19 +08:00
tiann
b80e06256d Revert "Add option to enable global namespace (#497)"
This reverts commit f81caf75a9.
2023-05-16 22:27:01 +08:00
tiann
08d9e5d6bc manager: add app_profile set/get 2023-05-16 20:33:09 +08:00
tiann
ed0cfd231e ci: fix debug build 2023-05-16 19:46:49 +08:00
weishu
538d3f06f4 ci: Add debug kernel build (#506) 2023-05-16 18:30:33 +08:00
Vayruz Rafli
f5d3fb6217 Fix little typo in setup script. (#505) 2023-05-16 18:12:16 +08:00
tiann
ffa3579e6f manager: minor fixes for app profile 2023-05-16 17:31:57 +08:00
tiann
c7adb8e3b1 manager: Add app profile implementation 2023-05-16 17:15:01 +08:00
tiann
c1427f658a manager: Add working mode UI 2023-05-16 16:31:56 +08:00
tiann
eccce7b31f manager: Add app profile UI 2023-05-16 15:07:26 +08:00
Hikari-no-Tenshi
f81caf75a9 Add option to enable global namespace (#497)
Disabled by default.
To enable/disable use terminal with root.

To enable:
echo 1 > /sys/module/ksu/parameters/global_namespace_enable

To disable:
echo 0 > /sys/module/ksu/parameters/global_namespace_enable

Value will be reset to 0 (disabled) on reboot.
2023-05-16 11:39:48 +08:00
dabao1955
d4680c6de7 Add Japanese language for Readme (#501)
Co-authored-by: dabao1955 <195328750@qq.com>
2023-05-16 10:40:39 +08:00
86 changed files with 3713 additions and 886 deletions

View File

@@ -0,0 +1,31 @@
name: Build debug kernel
on:
workflow_dispatch:
jobs:
build-debug-kernel-a12:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.168
tag: android12-5.10-2023-04
os_patch_level: 2023-04
patch_path: "5.10"
debug: true
build-debug-kernel-a13:
strategy:
matrix:
include:
- version: "5.10"
sub_level: 168
os_patch_level: 2023-04
- version: "5.15"
sub_level: 94
os_patch_level: 2023-04
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: true

View File

@@ -109,7 +109,7 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.160
tag: android12-5.10-2023-02
os_patch_level: 2023-02
version_name: android12-5.10.168
tag: android12-5.10-2023-04
os_patch_level: 2023-04
patch_path: "5.10"

View File

@@ -29,16 +29,19 @@ jobs:
os_patch_level: 2023-01
- version: "5.10"
sub_level: 157
os_patch_level: 2023-02
- version: "5.15"
sub_level: 41
os_patch_level: 2022-11
os_patch_level: 2023-03
- version: "5.10"
sub_level: 168
os_patch_level: 2023-04
- version: "5.15"
sub_level: 74
os_patch_level: 2023-01
- version: "5.15"
sub_level: 78
os_patch_level: 2023-02
os_patch_level: 2023-03
- version: "5.15"
sub_level: 94
os_patch_level: 2023-04
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -119,14 +122,14 @@ jobs:
matrix:
include:
- version: "5.10"
sub_level: 149
os_patch_level: 2022-11
sub_level: 168
os_patch_level: 2023-04
- version: "5.15"
sub_level: 74
os_patch_level: 2023-01
sub_level: 94
os_patch_level: 2023-04
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
patch_path: ${{ matrix.version }}

View File

@@ -18,38 +18,29 @@ jobs:
strategy:
matrix:
arch: [x86_64, arm64]
version: ["5.10.117.2", "5.15.78.1", "5.15.94.1"]
version: ["5.15.78.1", "5.15.94.4"]
include:
- arch: x86_64
file_name: "bzImage"
- arch: arm64
file_name: "Image"
cross_compile: "aarch64-linux-gnu"
- version: "5.10.117.2"
arch: x86_64
make_config: config-wsa-5.10
- version: "5.10.117.2"
arch: arm64
make_config: config-wsa-arm64-5.10
- version: "5.15.78.1"
arch: x86_64
make_config: config-wsa-x64
- version: "5.15.78.1"
arch: arm64
make_config: config-wsa-arm64
- version: "5.15.94.1"
- version: "5.15.94.4"
arch: x86_64
make_config: config-wsa-x64
- version: "5.15.94.1"
- version: "5.15.94.4"
arch: arm64
make_config: config-wsa-arm64
- version: "5.10.117.2"
device_code: latte
kernel_version: "5.10"
- version: "5.15.78.1"
device_code: latte-2
kernel_version: "5.15"
- version: "5.15.94.1"
- version: "5.15.94.4"
device_code: latte-2
kernel_version: "5.15"

View File

@@ -45,6 +45,10 @@ on:
description: >
Artifact name of prebuilt ksud to be embedded
for example: ksud-aarch64-linux-android
debug:
required: false
type: boolean
default: false
secrets:
BOOT_SIGN_KEY:
required: false
@@ -91,6 +95,7 @@ jobs:
- name: Setup KernelSU
env:
PATCH_PATH: ${{ inputs.patch_path }}
IS_DEBUG_KERNEL: ${{ inputs.debug }}
run: |
cd $GITHUB_WORKSPACE/android-kernel
echo "[+] KernelSU setup"
@@ -103,8 +108,13 @@ jobs:
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch
echo "Patch script/setlocalversion"
echo "[+] Patch script/setlocalversion"
sed -i 's/-dirty//g' $GKI_ROOT/common/scripts/setlocalversion
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
echo "[+] Enable debug features for kernel"
echo "ccflags-y += -DCONFIG_KSU_DEBUG" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
fi
echo "[+] KernelSU setup done."
- name: Symbol magic

View File

@@ -1,4 +1,4 @@
**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md)
**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md)
# KernelSU
@@ -11,7 +11,7 @@ A Kernel based root solution for Android devices.
## Compatibility State
KernelSU officially supports Android GKI 2.0 devices(with kernel 5.10+), old kernels(4.14+) is also compatiable, but you need to build kernel yourself.
KernelSU officially supports Android GKI 2.0 devices(with kernel 5.10+), old kernels(4.14+) is also compatible, but you need to build kernel yourself.
WSA and containter-based Android should also work with KernelSU integrated.

View File

@@ -1,4 +1,4 @@
[English](README.md) | **简体中文** | [繁體中文](README_TW.md)
[English](README.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md)
# KernelSU

42
README_JP.md Normal file
View File

@@ -0,0 +1,42 @@
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Portuguese-Brazil](README_PT-BR.md)
# KernelSU
Android におけるカーネルベースの root ソリューションです。
## 特徴
1. カーネルベースの `su` と権限管理
2. OverlayFS に基づくモジュールシステム
## 対応状況
KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上を公式にサポートしています。古いカーネル4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。
WSA とコンテナ上で動作する Android でも KernelSU を統合して動かせます。
現在サポートしているアーキテクチャは `arm64-v8a` および `x86_64` です。
## 使用方法
[インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html)
## ビルド
[ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html)
### ディスカッション
- Telegram: [@KernelSU](https://t.me/KernelSU)
## ライセンス
- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## クレジット
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU のアイデア元
- [genuine](https://github.com/brevent/genuine/)apk v2 の署名検証
- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy の実装

47
README_PT-BR.md Normal file
View File

@@ -0,0 +1,47 @@
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Portuguese-Brazil**
# KernelSU
Uma solução raiz baseada em Kernel para dispositivos Android.
## Características
1. `su` baseado em kernel e gerenciamento de acesso root.
2. Sistema modular baseado em overlayfs.
## Estado de compatibilidade
O KernelSU suporta oficialmente dispositivos Android GKI 2.0 (com kernel 5.10+), kernels antigos (4.14+) também são compatíveis, mas você mesmo precisa construir o kernel.
O Android baseado em WSA e contêiner também deve funcionar com o KernelSU integrado.
E os ABIs atualmente suportados são: `arm64-v8a` e `x86_64`
## Uso
[Instalação](https://kernelsu.org/guide/installation.html)
## Construir
[Como construir?](https://kernelsu.org/guide/how-to-build.html)
### Discussão
- Telegram: [@KernelSU](https://t.me/KernelSU)
## 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)
## Créditos
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): a ideia do KernelSU.
- [genuine](https://github.com/brevent/genuine/): validação de assinatura apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algumas habilidades de rootkit.
- [Magisk](https://github.com/topjohnwu/Magisk): a implementação da sepolicy.

View File

@@ -1,4 +1,4 @@
[English](README.md) | [简体中文](README_CN.md) | **繁體中文**
[English](README.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md)
# KernelSU

View File

@@ -1,13 +1,17 @@
menu "KernelSU"
config KSU
tristate "KernelSU module"
tristate "KernelSU function support"
select OVERLAY_FS
default y
depends on OVERLAY_FS
help
This is the KSU privilege driver for android system.
Enable kernel-level root privileges on Android System.
config KSU_DEBUG
tristate "KernelSU module debug mode"
default n
bool "KernelSU debug mode"
depends on KSU
default n
help
This enables debug mode for KSU
Enable KernelSU debug mode
endmenu

View File

@@ -29,4 +29,4 @@ endif
ccflags-y += -DEXPECTED_SIZE=$(EXPECTED_SIZE)
ccflags-y += -DEXPECTED_HASH=$(EXPECTED_HASH)
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-macro-redefined -Wno-declaration-after-statement
ccflags-y += -Wno-declaration-after-statement

View File

@@ -1,23 +1,52 @@
#include "linux/delay.h"
#include "ksu.h"
#include "linux/compiler.h"
#include "linux/fs.h"
#include "linux/gfp.h"
#include "linux/kernel.h"
#include "linux/list.h"
#include "linux/printk.h"
#include "linux/slab.h"
#include "linux/types.h"
#include "linux/version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#include "linux/compiler_types.h"
#endif
#include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#include "kernel_compat.h"
#include "allowlist.h"
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 1 // u32
#define FILE_FORMAT_VERSION 3 // u32
#define KSU_APP_PROFILE_PRESERVE_UID 9999 // NOBODY_UID
#define KSU_DEFAULT_SELINUX_DOMAIN "u:r:su:s0"
static DEFINE_MUTEX(allowlist_mutex);
// default profiles, these may be used frequently, so we cache it
static struct root_profile default_root_profile;
static struct non_root_profile default_non_root_profile;
static void init_default_profiles()
{
default_root_profile.uid = 0;
default_root_profile.gid = 0;
default_root_profile.groups_count = 1;
default_root_profile.groups[0] = 0;
memset(&default_root_profile.capabilities, 0xff,
sizeof(default_root_profile.capabilities));
default_root_profile.namespaces = 0;
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
// This means that we will umount modules by default!
default_non_root_profile.umount_modules = true;
}
struct perm_data {
struct list_head list;
uid_t uid;
bool allow;
struct app_profile profile;
};
static struct list_head allow_list;
@@ -36,20 +65,87 @@ void ksu_show_allow_list(void)
pr_info("ksu_show_allow_list");
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("uid :%d, allow: %d\n", p->uid, p->allow);
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
p->profile.allow_su);
}
}
bool ksu_allow_uid(uid_t uid, bool allow, bool persist)
#ifdef CONFIG_KSU_DEBUG
static void ksu_grant_root_to_shell()
{
struct app_profile profile = {
.allow_su = true,
.current_uid = 2000,
};
strcpy(profile.key, "com.android.shell");
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
ksu_set_app_profile(&profile, false);
}
#endif
bool ksu_get_app_profile(struct app_profile *profile)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool found = false;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
bool uid_match = profile->current_uid == p->profile.current_uid;
if (uid_match) {
// found it, override it with ours
memcpy(profile, &p->profile, sizeof(*profile));
found = true;
goto exit;
}
}
exit:
return found;
}
static bool profile_valid(struct app_profile *profile)
{
if (!profile) {
return false;
}
if (profile->version < KSU_APP_PROFILE_VER) {
pr_info("Unsupported profile version: %d\n", profile->version);
return false;
}
if (profile->allow_su) {
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
return false;
}
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
return false;
}
}
return true;
}
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
{
// find the node first!
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool result = false;
if (!profile_valid(profile)) {
pr_err("Failed to set app profile: invalid profile!\n");
return false;
}
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
if (uid == p->uid) {
p->allow = allow;
// both uid and package must match, otherwise it will break multiple package with different user id
if (profile->current_uid == p->profile.current_uid &&
!strcmp(profile->key, p->profile.key)) {
// found it, just override it all!
memcpy(&p->profile, profile, sizeof(*profile));
result = true;
goto exit;
}
@@ -58,18 +154,38 @@ bool ksu_allow_uid(uid_t uid, bool allow, bool persist)
// not found, alloc a new node!
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
if (!p) {
pr_err("alloc allow node failed.\n");
pr_err("ksu_set_app_profile alloc failed\n");
return false;
}
p->uid = uid;
p->allow = allow;
pr_info("allow_uid: %d, allow: %d", uid, allow);
memcpy(&p->profile, profile, sizeof(*profile));
if (profile->allow_su) {
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
profile->key, profile->current_uid,
profile->rp_config.profile.gid,
profile->rp_config.profile.selinux_domain);
} else {
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
profile->key, profile->current_uid,
profile->nrp_config.profile.umount_modules);
}
list_add_tail(&p->list, &allow_list);
result = true;
exit:
// check if the default profiles is changed, cache it to a single struct to accelerate access.
if (unlikely(!strcmp(profile->key, "$"))) {
// set default non root profile
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
sizeof(default_non_root_profile));
}
if (unlikely(!strcmp(profile->key, "#"))) {
// set default root profile
memcpy(&default_root_profile, &profile->rp_config.profile,
sizeof(default_root_profile));
}
if (persist)
persistent_allow_list();
@@ -89,14 +205,53 @@ bool ksu_is_allow_uid(uid_t uid)
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
// pr_info("is_allow_uid uid :%d, allow: %d\n", p->uid, p->allow);
if (uid == p->uid) {
return p->allow;
if (uid == p->profile.current_uid) {
return p->profile.allow_su;
}
}
return false;
}
bool ksu_uid_should_umount(uid_t uid)
{
struct app_profile profile = { .current_uid = uid };
bool found = ksu_get_app_profile(&profile);
if (!found) {
// no app profile found, it must be non root app
return default_non_root_profile.umount_modules;
}
if (profile.allow_su) {
// if found and it is granted to su, we shouldn't umount for it
return false;
} else {
// found an app profile
if (profile.nrp_config.use_default) {
return default_non_root_profile.umount_modules;
} else {
return profile.nrp_config.profile.umount_modules;
}
}
}
struct root_profile *ksu_get_root_profile(uid_t uid)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
if (uid == p->profile.current_uid && p->profile.allow_su) {
if (!p->profile.rp_config.use_default) {
return &p->profile.rp_config.profile;
}
}
}
// use default profile
return &default_root_profile;
}
bool ksu_get_allow_list(int *array, int *length, bool allow)
{
struct perm_data *p = NULL;
@@ -105,8 +260,8 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
if (p->allow == allow) {
array[i++] = p->uid;
if (p->profile.allow_su == allow) {
array[i++] = p->profile.current_uid;
}
}
*length = i;
@@ -114,7 +269,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
return true;
}
void do_persistent_allow_list(struct work_struct *work)
void do_save_allow_list(struct work_struct *work)
{
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
@@ -126,12 +281,13 @@ void do_persistent_allow_list(struct work_struct *work)
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
if (IS_ERR(fp)) {
pr_err("save_allow_list creat file failed: %d\n", PTR_ERR(fp));
pr_err("save_allow_list creat file failed: %ld\n", PTR_ERR(fp));
return;
}
// store magic and version
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic)) {
pr_err("save_allow_list write magic failed.\n");
goto exit;
}
@@ -144,10 +300,12 @@ void do_persistent_allow_list(struct work_struct *work)
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("save allow list uid :%d, allow: %d\n", p->uid,
p->allow);
ksu_kernel_write_compat(fp, &p->uid, sizeof(p->uid), &off);
ksu_kernel_write_compat(fp, &p->allow, sizeof(p->allow), &off);
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
p->profile.key, p->profile.current_uid,
p->profile.allow_su);
ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile),
&off);
}
exit:
@@ -163,27 +321,21 @@ void do_load_allow_list(struct work_struct *work)
u32 version;
KWORKER_INSTALL_KEYRING();
#ifdef CONFIG_KSU_DEBUG
// always allow adb shell by default
ksu_grant_root_to_shell();
#endif
// load allowlist now!
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
if (IS_ERR(fp)) {
#ifdef CONFIG_KSU_DEBUG
int errno = PTR_ERR(fp);
if (errno == -ENOENT) {
ksu_allow_uid(2000, true,
true); // allow adb shell by default
} else {
pr_err("load_allow_list open file failed: %d\n",
PTR_ERR(fp));
}
#else
pr_err("load_allow_list open file failed: %d\n", PTR_ERR(fp));
#endif
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
return;
}
// verify magic
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic) ||
magic != FILE_MAGIC) {
pr_err("allowlist file invalid: %d!\n", magic);
goto exit;
@@ -198,18 +350,19 @@ void do_load_allow_list(struct work_struct *work)
pr_info("allowlist version: %d\n", version);
while (true) {
u32 uid;
bool allow = false;
ret = ksu_kernel_read_compat(fp, &uid, sizeof(uid), &off);
struct app_profile profile;
ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile),
&off);
if (ret <= 0) {
pr_info("load_allow_list read err: %d\n", ret);
pr_info("load_allow_list read err: %zd\n", ret);
break;
}
ret = ksu_kernel_read_compat(fp, &allow, sizeof(allow), &off);
pr_info("load_allow_uid: %d, allow: %d\n", uid, allow);
ksu_allow_uid(uid, allow, false);
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n",
profile.key, profile.current_uid, profile.allow_su);
ksu_set_app_profile(&profile, false);
}
exit:
@@ -226,8 +379,10 @@ void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data)
// TODO: use RCU!
mutex_lock(&allowlist_mutex);
list_for_each_entry_safe (np, n, &allow_list, list) {
uid_t uid = np->uid;
if (!is_uid_exist(uid, data)) {
uid_t uid = np->profile.current_uid;
// we use this uid for special cases, don't prune it!
bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID;
if (!is_preserved_uid && !is_uid_exist(uid, data)) {
modified = true;
pr_info("prune uid: %d\n", uid);
list_del(&np->list);
@@ -256,8 +411,10 @@ void ksu_allowlist_init(void)
{
INIT_LIST_HEAD(&allow_list);
INIT_WORK(&ksu_save_work, do_persistent_allow_list);
INIT_WORK(&ksu_save_work, do_save_allow_list);
INIT_WORK(&ksu_load_work, do_load_allow_list);
init_default_profiles();
}
void ksu_allowlist_exit(void)
@@ -265,7 +422,7 @@ void ksu_allowlist_exit(void)
struct perm_data *np = NULL;
struct perm_data *n = NULL;
do_persistent_allow_list(NULL);
do_save_allow_list(NULL);
// free allowlist
mutex_lock(&allowlist_mutex);
@@ -274,4 +431,4 @@ void ksu_allowlist_exit(void)
kfree(np);
}
mutex_unlock(&allowlist_mutex);
}
}

View File

@@ -2,6 +2,7 @@
#define __KSU_H_ALLOWLIST
#include "linux/types.h"
#include "ksu.h"
void ksu_allowlist_init(void);
@@ -13,10 +14,13 @@ void ksu_show_allow_list(void);
bool ksu_is_allow_uid(uid_t uid);
bool ksu_allow_uid(uid_t uid, bool allow, bool persist);
bool ksu_get_allow_list(int *array, int *length, bool allow);
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data);
bool ksu_get_app_profile(struct app_profile *);
bool ksu_set_app_profile(struct app_profile *, bool persist);
bool ksu_uid_should_umount(uid_t uid);
struct root_profile *ksu_get_root_profile(uid_t uid);
#endif

View File

@@ -1,3 +1,4 @@
#include "linux/capability.h"
#include "linux/cred.h"
#include "linux/dcache.h"
#include "linux/err.h"
@@ -51,7 +52,39 @@ static inline bool is_isolated_uid(uid_t uid)
appid <= LAST_APP_ZYGOTE_ISOLATED_UID);
}
static struct group_info root_groups = { .usage = ATOMIC_INIT(2) };
static void setup_groups(struct root_profile *profile, struct cred *cred)
{
if (profile->groups_count > KSU_MAX_GROUPS) {
pr_warn("Failed to setgroups, too large group: %d!\n",
profile->uid);
return;
}
u32 ngroups = profile->groups_count;
struct group_info *group_info = groups_alloc(ngroups);
if (!group_info) {
pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid);
return;
}
for (int i = 0; i < ngroups; i++) {
gid_t gid = profile->groups[i];
kgid_t kgid = make_kgid(current_user_ns(), gid);
if (!gid_valid(kgid)) {
pr_warn("Failed to setgroups, invalid gid: %d\n", gid);
put_group_info(group_info);
return;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
group_info->gid[i] = kgid;
#else
GROUP_AT(group_info, i) = kgid;
#endif
}
groups_sort(group_info);
set_groups(cred, group_info);
}
void escape_to_root(void)
{
@@ -59,18 +92,36 @@ void escape_to_root(void)
cred = (struct cred *)__task_cred(current);
memset(&cred->uid, 0, sizeof(cred->uid));
memset(&cred->gid, 0, sizeof(cred->gid));
memset(&cred->suid, 0, sizeof(cred->suid));
memset(&cred->euid, 0, sizeof(cred->euid));
memset(&cred->egid, 0, sizeof(cred->egid));
memset(&cred->fsuid, 0, sizeof(cred->fsuid));
memset(&cred->fsgid, 0, sizeof(cred->fsgid));
memset(&cred->cap_inheritable, 0xff, sizeof(cred->cap_inheritable));
memset(&cred->cap_permitted, 0xff, sizeof(cred->cap_permitted));
memset(&cred->cap_effective, 0xff, sizeof(cred->cap_effective));
memset(&cred->cap_bset, 0xff, sizeof(cred->cap_bset));
memset(&cred->cap_ambient, 0xff, sizeof(cred->cap_ambient));
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
return;
}
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
cred->uid.val = profile->uid;
cred->suid.val = profile->uid;
cred->euid.val = profile->uid;
cred->fsuid.val = profile->uid;
cred->gid.val = profile->gid;
cred->fsgid.val = profile->gid;
cred->sgid.val = profile->gid;
cred->egid.val = profile->gid;
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
sizeof(kernel_cap_t));
// capabilities
memcpy(&cred->cap_effective, &profile->capabilities.effective,
sizeof(cred->cap_effective));
memcpy(&cred->cap_inheritable, &profile->capabilities.effective,
sizeof(cred->cap_inheritable));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
memcpy(&cred->cap_ambient, &profile->capabilities.effective,
sizeof(cred->cap_ambient));
// disable seccomp
#if defined(CONFIG_GENERIC_ENTRY) && \
@@ -86,12 +137,9 @@ void escape_to_root(void)
#else
#endif
// setgroup to root
if (cred->group_info)
put_group_info(cred->group_info);
cred->group_info = get_group_info(&root_groups);
setup_groups(profile, cred);
setup_selinux();
setup_selinux(profile->selinux_domain);
}
int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
@@ -186,7 +234,8 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (userId == 0) {
prefix = "/data/data";
} else {
snprintf(prefixTmp, sizeof(prefixTmp), "/data/user/%d", userId);
snprintf(prefixTmp, sizeof(prefixTmp), "/data/user/%d",
userId);
prefix = prefixTmp;
}
@@ -227,10 +276,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("grant_root: prctl reply error\n");
}
} else {
pr_info("deny root for: %d\n", current_uid());
// add it to deny list!
ksu_allow_uid(current_uid().val, false, true);
}
return 0;
}
@@ -325,6 +370,30 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
if (arg2 == CMD_UID_GRANTED_ROOT || arg2 == CMD_UID_SHOULD_UMOUNT) {
if (is_manager() || 0 == current_uid().val) {
uid_t target_uid = (uid_t)arg3;
bool allow = false;
if (arg2 == CMD_UID_GRANTED_ROOT) {
allow = ksu_is_allow_uid(target_uid);
} else if (arg2 == CMD_UID_SHOULD_UMOUNT) {
allow = ksu_uid_should_umount(target_uid);
} else {
pr_err("unknown cmd: %d\n", arg2);
}
if (!copy_to_user(arg4, &allow, sizeof(allow))) {
if (copy_to_user(result, &reply_ok,
sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n",
arg2);
}
} else {
pr_err("prctl copy err, cmd: %d\n", arg2);
}
}
return 0;
}
// all other cmds are for 'root manager'
if (!is_manager()) {
last_failed_uid = current_uid().val;
@@ -332,17 +401,39 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
// we are already manager
if (arg2 == CMD_ALLOW_SU || arg2 == CMD_DENY_SU) {
bool allow = arg2 == CMD_ALLOW_SU;
bool success = false;
uid_t uid = (uid_t)arg3;
success = ksu_allow_uid(uid, allow, true);
if (arg2 == CMD_GET_APP_PROFILE) {
struct app_profile profile;
if (copy_from_user(&profile, arg3, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
bool success = ksu_get_app_profile(&profile);
if (success) {
if (copy_to_user(arg3, &profile, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
}
return 0;
}
if (arg2 == CMD_SET_APP_PROFILE) {
struct app_profile profile;
if (copy_from_user(&profile, arg3, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
// todo: validate the params
if (ksu_set_app_profile(&profile, true)) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
}
ksu_show_allow_list();
return 0;
}
@@ -366,13 +457,19 @@ static bool should_umount(struct path *path)
}
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
pr_info("ignore global mnt namespace process: %d\n", current_uid().val);
pr_info("ignore global mnt namespace process: %d\n",
current_uid().val);
return false;
}
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
const char *fstype = path->mnt->mnt_sb->s_type->name;
return strcmp(fstype, "overlay") == 0;
if (strcmp(fstype, "overlay") == 0) {
return ksu_uid_should_umount(current_uid().val);
}
#ifdef CONFIG_KSU_DEBUG
pr_info("uid: %d should not umount!\n", current_uid().val);
#endif
}
return false;
}

View File

@@ -57,7 +57,7 @@ int __init kernelsu_init(void)
ksu_enable_sucompat();
ksu_enable_ksud();
#else
#warning("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html")
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
#endif
return 0;

View File

@@ -1,13 +1,17 @@
#ifndef __KSU_H_KSU
#define __KSU_H_KSU
#include "linux/types.h"
#include "linux/workqueue.h"
#ifndef KSU_GIT_VERSION
#warning "KSU_GIT_VERSION not defined! It is better to make KernelSU a git submodule!"
#warning \
"KSU_GIT_VERSION not defined! It is better to make KernelSU a git submodule!"
#define KERNEL_SU_VERSION (16)
#else
#define KERNEL_SU_VERSION (10000 + KSU_GIT_VERSION + 200) // major * 10000 + git version + 200 for historical reasons
#define KERNEL_SU_VERSION \
(10000 + KSU_GIT_VERSION + \
200) // major * 10000 + git version + 200 for historical reasons
#endif
#define KERNEL_SU_OPTION 0xDEADBEEF
@@ -22,10 +26,68 @@
#define CMD_REPORT_EVENT 7
#define CMD_SET_SEPOLICY 8
#define CMD_CHECK_SAFEMODE 9
#define CMD_GET_APP_PROFILE 10
#define CMD_SET_APP_PROFILE 11
#define CMD_UID_GRANTED_ROOT 12
#define CMD_UID_SHOULD_UMOUNT 13
#define EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2
#define KSU_APP_PROFILE_VER 2
#define KSU_MAX_PACKAGE_NAME 256
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
#define KSU_MAX_GROUPS 32
#define KSU_SELINUX_DOMAIN 64
struct root_profile {
int32_t uid;
int32_t gid;
int32_t groups_count;
int32_t groups[KSU_MAX_GROUPS];
// kernel_cap_t is u32[2] for capabilities v3
struct {
u64 effective;
u64 permitted;
u64 inheritable;
} capabilities;
char selinux_domain[KSU_SELINUX_DOMAIN];
int32_t namespaces;
};
struct non_root_profile {
bool umount_modules;
};
struct app_profile {
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
u32 version;
// this is usually the package of the app, but can be other value for special apps
char key[KSU_MAX_PACKAGE_NAME];
int32_t current_uid;
bool allow_su;
union {
struct {
bool use_default;
char template_name[KSU_MAX_PACKAGE_NAME];
struct root_profile profile;
} rp_config;
struct {
bool use_default;
struct non_root_profile profile;
} nrp_config;
};
};
bool ksu_queue_work(struct work_struct *work);
static inline int startswith(char *s, char *prefix)

View File

@@ -13,7 +13,7 @@
#include "ksu.h"
#include "manager.h"
uid_t ksu_manager_uid = INVALID_UID;
uid_t ksu_manager_uid = KSU_INVALID_UID;
bool become_manager(char *pkg)
{

View File

@@ -4,13 +4,13 @@
#include "linux/cred.h"
#include "linux/types.h"
#define INVALID_UID -1
#define KSU_INVALID_UID -1
extern uid_t ksu_manager_uid; // DO NOT DIRECT USE
static inline bool ksu_is_manager_uid_valid()
{
return ksu_manager_uid != INVALID_UID;
return ksu_manager_uid != KSU_INVALID_UID;
}
static inline bool is_manager()
@@ -30,7 +30,7 @@ static inline void ksu_set_manager_uid(uid_t uid)
static inline void ksu_invalidate_manager_uid()
{
ksu_manager_uid = INVALID_UID;
ksu_manager_uid = KSU_INVALID_UID;
}
bool become_manager(char *pkg);

View File

@@ -11,6 +11,6 @@ ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE
endif
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion
ccflags-y += -Wno-macro-redefined -Wno-declaration-after-statement -Wno-unused-function
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-y += -I$(objtree)/security/selinux
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h

View File

@@ -39,9 +39,9 @@ static int transive_to_domain(const char *domain)
return error;
}
void setup_selinux()
void setup_selinux(const char *domain)
{
if (transive_to_domain(KERNEL_SU_DOMAIN)) {
if (transive_to_domain(domain)) {
pr_err("transive domain failed.");
return;
}
@@ -88,7 +88,8 @@ bool getenforce()
#endif
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && !defined(KSU_COMPAT_HAS_CURRENT_SID)
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \
!defined(KSU_COMPAT_HAS_CURRENT_SID)
/*
* get the subjective security ID of the current task
*/

View File

@@ -8,7 +8,7 @@
#define KSU_COMPAT_USE_SELINUX_STATE
#endif
void setup_selinux();
void setup_selinux(const char *);
void setenforce(bool);

View File

@@ -73,7 +73,7 @@ static bool add_typeattribute(struct policydb *db, const char *type,
// rules
#define strip_av(effect, invert) ((effect == AVTAB_AUDITDENY) == !invert)
#define hash_for_each(node_ptr, n_slot, cur) \
#define ksu_hash_for_each(node_ptr, n_slot, cur) \
int i; \
for (i = 0; i < n_slot; ++i) \
for (cur = node_ptr[i]; cur; cur = cur->next)
@@ -81,10 +81,10 @@ static bool add_typeattribute(struct policydb *db, const char *type,
// htable is a struct instead of pointer above 5.8.0:
// https://elixir.bootlin.com/linux/v5.8-rc1/source/security/selinux/ss/symtab.h
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
#define hashtab_for_each(htab, cur) hash_for_each (htab.htable, htab.size, cur)
#define ksu_hashtab_for_each(htab, cur) ksu_hash_for_each (htab.htable, htab.size, cur)
#else
#define hashtab_for_each(htab, cur) \
hash_for_each (htab->htable, htab->size, cur)
#define ksu_hashtab_for_each(htab, cur) \
ksu_hash_for_each (htab->htable, htab->size, cur)
#endif
// symtab_search is introduced on 5.9.0:
@@ -95,7 +95,7 @@ static bool add_typeattribute(struct policydb *db, const char *type,
#endif
#define avtab_for_each(avtab, cur) \
hash_for_each (avtab.htable, avtab.nslot, cur) \
ksu_hash_for_each (avtab.htable, avtab.nslot, cur) \
;
static struct avtab_node *get_avtab_node(struct policydb *db,
@@ -210,14 +210,14 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src,
if (src == NULL) {
struct hashtab_node *node;
if (strip_av(effect, invert)) {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
add_rule_raw(db,
(struct type_datum *)node->datum,
tgt, cls, perm, effect, invert);
};
} else {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -230,14 +230,14 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src,
} else if (tgt == NULL) {
struct hashtab_node *node;
if (strip_av(effect, invert)) {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
add_rule_raw(db, src,
(struct type_datum *)node->datum,
cls, perm, effect, invert);
};
} else {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -249,7 +249,7 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src,
}
} else if (cls == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_classes.table, node)
ksu_hashtab_for_each(db->p_classes.table, node)
{
add_rule_raw(db, src, tgt,
(struct class_datum *)node->datum, perm,
@@ -292,7 +292,7 @@ static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src,
{
if (src == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -303,7 +303,7 @@ static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src,
};
} else if (tgt == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -314,7 +314,7 @@ static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src,
};
} else if (cls == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_classes.table, node)
ksu_hashtab_for_each(db->p_classes.table, node)
{
add_xperm_rule_raw(db, src, tgt,
(struct class_datum *)(node->datum),
@@ -870,7 +870,7 @@ static bool set_type_state(struct policydb *db, const char *type_name,
struct type_datum *type;
if (type_name == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
type = (struct type_datum *)(node->datum);
if (ebitmap_set_bit(&db->permissive_map, type->value,
@@ -913,7 +913,7 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type,
struct hashtab_node *node;
struct constraint_node *n;
struct constraint_expr *e;
hashtab_for_each(db->p_classes.table, node)
ksu_hashtab_for_each(db->p_classes.table, node)
{
struct class_datum *cls = (struct class_datum *)(node->datum);
for (n = cls->constraints; n; n = n->next) {

View File

@@ -11,7 +11,7 @@ elif test -d "$GKI_ROOT/drivers"; then
DRIVER_DIR="$GKI_ROOT/drivers"
else
echo '[ERROR] "drivers/" directory is not found.'
echo '[+] You should modify this scrpit by yourself.'
echo '[+] You should modify this script by yourself.'
exit 127
fi
@@ -43,6 +43,8 @@ cd "$GKI_ROOT"
echo '[+] Add kernel su driver to Makefile'
DRIVER_MAKEFILE=$DRIVER_DIR/Makefile
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-y += kernelsu/\n" >> "$DRIVER_MAKEFILE"
DRIVER_KCONFIG=$DRIVER_DIR/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "obj-\$(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.'

View File

@@ -29,7 +29,7 @@ static bool is_uid_exist(uid_t uid, void *data)
bool exist = false;
list_for_each_entry (np, list, list) {
if (np->uid == uid) {
if (np->uid == uid % 100000) {
exist = true;
break;
}
@@ -136,4 +136,4 @@ int ksu_uid_observer_init()
int ksu_uid_observer_exit()
{
return 0;
}
}

View File

@@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.kotlin)
alias(libs.plugins.ksp)
alias(libs.plugins.lsplugin.apksign)
id("kotlin-parcelize")
}
val managerVersionCode: Int by rootProject.extra
@@ -96,8 +97,6 @@ dependencies {
implementation(libs.compose.destinations.animations.core)
ksp(libs.compose.destinations.ksp)
implementation(libs.com.github.alorma.compose.settings.ui.m3)
implementation(libs.com.github.topjohnwu.libsu.core)
implementation(libs.com.github.topjohnwu.libsu.service)
@@ -108,4 +107,7 @@ dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.me.zhanghai.android.appiconloader.coil)
implementation(libs.sheet.compose.dialogs.core)
implementation(libs.sheet.compose.dialogs.list)
}

View File

@@ -3,15 +3,16 @@
#include <sys/prctl.h>
#include <android/log.h>
#include <cstring>
#include "ksu.h"
#define LOG_TAG "KernelSu"
#define LOG_TAG "KernelSU"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jclass clazz, jstring pkg) {
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jobject, jstring pkg) {
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
auto result = become_manager(cpkg);
env->ReleaseStringUTFChars(pkg, cpkg);
@@ -20,13 +21,13 @@ Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jclass clazz, jstring
extern "C"
JNIEXPORT jint JNICALL
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jclass clazz) {
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jobject) {
return get_version();
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jclass clazz) {
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jobject) {
int uids[1024];
int size = 0;
bool result = get_allow_list(uids, &size);
@@ -39,31 +40,260 @@ Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jclass clazz) {
return env->NewIntArray(0);
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_me_weishu_kernelsu_Natives_getDenyList(JNIEnv *env, jclass clazz) {
int uids[1024];
int size = 0;
bool result = get_deny_list(uids, &size);
if (result) {
// success!
auto array = env->NewIntArray(size);
env->SetIntArrayRegion(array, 0, size, uids);
return array;
}
return env->NewIntArray(0);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_allowRoot(JNIEnv *env, jclass clazz, jint uid, jboolean allow) {
return allow_su(uid, allow);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_isSafeMode(JNIEnv *env, jclass clazz) {
return is_safe_mode();
}
static void fillIntArray(JNIEnv *env, jobject list, int *data, int count) {
auto cls = env->GetObjectClass(list);
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
auto integerCls = env->FindClass("java/lang/Integer");
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
for (int i = 0; i < count; ++i) {
auto integer = env->NewObject(integerCls, constructor, data[i]);
env->CallBooleanMethod(list, add, integer);
}
}
static void addIntToList(JNIEnv *env, jobject list, int ele) {
auto cls = env->GetObjectClass(list);
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
auto integerCls = env->FindClass("java/lang/Integer");
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
auto integer = env->NewObject(integerCls, constructor, ele);
env->CallBooleanMethod(list, add, integer);
}
static uint64_t capListToBits(JNIEnv *env, jobject list) {
auto cls = env->GetObjectClass(list);
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
auto size = env->GetMethodID(cls, "size", "()I");
auto listSize = env->CallIntMethod(list, size);
auto integerCls = env->FindClass("java/lang/Integer");
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
uint64_t result = 0;
for (int i = 0; i < listSize; ++i) {
auto integer = env->CallObjectMethod(list, get, i);
int data = env->CallIntMethod(integer, intValue);
if (cap_valid(data)) {
result |= (1ULL << data);
}
}
return result;
}
static int getListSize(JNIEnv *env, jobject list) {
auto cls = env->GetObjectClass(list);
auto size = env->GetMethodID(cls, "size", "()I");
return env->CallIntMethod(list, size);
}
static void fillArrayWithList(JNIEnv *env, jobject list, int *data, int count) {
auto cls = env->GetObjectClass(list);
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
auto integerCls = env->FindClass("java/lang/Integer");
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
for (int i = 0; i < count; ++i) {
auto integer = env->CallObjectMethod(list, get, i);
data[i] = env->CallIntMethod(integer, intValue);
}
}
extern "C"
JNIEXPORT jobject JNICALL
Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg, jint uid) {
if (env->GetStringLength(pkg) > KSU_MAX_PACKAGE_NAME) {
return nullptr;
}
p_key_t key = {};
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
strcpy(key, cpkg);
env->ReleaseStringUTFChars(pkg, cpkg);
app_profile profile = {};
profile.version = KSU_APP_PROFILE_VER;
strcpy(profile.key, key);
profile.current_uid = uid;
bool useDefaultProfile = !get_app_profile(key, &profile);
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
auto constructor = env->GetMethodID(cls, "<init>", "()V");
auto obj = env->NewObject(cls, constructor);
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
auto uidField = env->GetFieldID(cls, "uid", "I");
auto gidField = env->GetFieldID(cls, "gid", "I");
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
env->SetObjectField(obj, keyField, env->NewStringUTF(profile.key));
env->SetIntField(obj, currentUidField, profile.current_uid);
if (useDefaultProfile) {
// no profile found, so just use default profile:
// don't allow root and use default profile!
LOGD("use default profile for: %s, %d", key, uid);
// allow_su = false
// non root use default = true
env->SetBooleanField(obj, allowSuField, false);
env->SetBooleanField(obj, nonRootUseDefaultField, true);
jobject capList = env->GetObjectField(obj, capabilitiesField);
int DEFAULT_CAPS[] = {CAP_DAC_READ_SEARCH};
for (auto i: DEFAULT_CAPS) {
addIntToList(env, capList, i);
}
return obj;
}
auto allowSu = profile.allow_su;
if (allowSu) {
env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default);
if (strlen(profile.rp_config.template_name) > 0) {
env->SetObjectField(obj, rootTemplateField,
env->NewStringUTF(profile.rp_config.template_name));
}
env->SetIntField(obj, uidField, profile.rp_config.profile.uid);
env->SetIntField(obj, gidField, profile.rp_config.profile.gid);
jobject groupList = env->GetObjectField(obj, groupsField);
int groupCount = profile.rp_config.profile.groups_count;
if (groupCount > KSU_MAX_GROUPS) {
LOGD("kernel group count too large: %d???", groupCount);
groupCount = KSU_MAX_GROUPS;
}
fillIntArray(env, groupList, profile.rp_config.profile.groups, groupCount);
jobject capList = env->GetObjectField(obj, capabilitiesField);
for (int i = 0; i <= CAP_LAST_CAP; i++) {
if (profile.rp_config.profile.capabilities.effective & (1ULL << i)) {
addIntToList(env, capList, i);
}
}
env->SetObjectField(obj, domainField,
env->NewStringUTF(profile.rp_config.profile.selinux_domain));
env->SetIntField(obj, namespacesField, profile.rp_config.profile.namespaces);
env->SetBooleanField(obj, allowSuField, profile.allow_su);
} else {
env->SetBooleanField(obj, nonRootUseDefaultField,
(jboolean) profile.nrp_config.use_default);
env->SetBooleanField(obj, umountModulesField, profile.nrp_config.profile.umount_modules);
}
return obj;
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobject profile) {
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
auto uidField = env->GetFieldID(cls, "uid", "I");
auto gidField = env->GetFieldID(cls, "gid", "I");
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
auto key = env->GetObjectField(profile, keyField);
if (!key) {
return false;
}
if (env->GetStringLength((jstring) key) > KSU_MAX_PACKAGE_NAME) {
return false;
}
auto cpkg = env->GetStringUTFChars((jstring) key, nullptr);
p_key_t p_key = {};
strcpy(p_key, cpkg);
env->ReleaseStringUTFChars((jstring) key, cpkg);
auto currentUid = env->GetIntField(profile, currentUidField);
auto uid = env->GetIntField(profile, uidField);
auto gid = env->GetIntField(profile, gidField);
auto groups = env->GetObjectField(profile, groupsField);
auto capabilities = env->GetObjectField(profile, capabilitiesField);
auto domain = env->GetObjectField(profile, domainField);
auto allowSu = env->GetBooleanField(profile, allowSuField);
auto umountModules = env->GetBooleanField(profile, umountModulesField);
app_profile p = {};
p.version = KSU_APP_PROFILE_VER;
strcpy(p.key, p_key);
p.allow_su = allowSu;
p.current_uid = currentUid;
if (allowSu) {
p.rp_config.use_default = env->GetBooleanField(profile, rootUseDefaultField);
auto templateName = env->GetObjectField(profile, rootTemplateField);
if (templateName) {
auto ctemplateName = env->GetStringUTFChars((jstring) templateName, nullptr);
strcpy(p.rp_config.template_name, ctemplateName);
env->ReleaseStringUTFChars((jstring) templateName, ctemplateName);
}
p.rp_config.profile.uid = uid;
p.rp_config.profile.gid = gid;
int groups_count = getListSize(env, groups);
if (groups_count > KSU_MAX_GROUPS) {
LOGD("groups count too large: %d", groups_count);
return false;
}
p.rp_config.profile.groups_count = groups_count;
fillArrayWithList(env, groups, p.rp_config.profile.groups, groups_count);
p.rp_config.profile.capabilities.effective = capListToBits(env, capabilities);
auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr);
strcpy(p.rp_config.profile.selinux_domain, cdomain);
env->ReleaseStringUTFChars((jstring) domain, cdomain);
p.rp_config.profile.namespaces = env->GetIntField(profile, namespacesField);
} else {
p.nrp_config.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
p.nrp_config.profile.umount_modules = umountModules;
}
return set_app_profile(&p);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_uidShouldUmount(JNIEnv *env, jobject thiz, jint uid) {
return uid_should_umount(uid);
}

View File

@@ -18,10 +18,16 @@
#define CMD_GET_VERSION 2
#define CMD_ALLOW_SU 3
#define CMD_DENY_SU 4
#define CMD_GET_ALLOW_LIST 5
#define CMD_GET_SU_LIST 5
#define CMD_GET_DENY_LIST 6
#define CMD_CHECK_SAFEMODE 9
#define CMD_GET_APP_PROFILE 10
#define CMD_SET_APP_PROFILE 11
#define CMD_IS_UID_GRANTED_ROOT 12
#define CMD_IS_UID_SHOULD_UMOUNT 13
static bool ksuctl(int cmd, void* arg1, void* arg2) {
int32_t result = 0;
prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result);
@@ -49,19 +55,23 @@ int get_version() {
return version;
}
bool allow_su(int uid, bool allow) {
int cmd = allow ? CMD_ALLOW_SU : CMD_DENY_SU;
return ksuctl(cmd, (void*) uid, nullptr);
}
bool get_allow_list(int *uids, int *size) {
return ksuctl(CMD_GET_ALLOW_LIST, uids, size);
}
bool get_deny_list(int *uids, int *size) {
return ksuctl(CMD_GET_DENY_LIST, uids, size);
return ksuctl(CMD_GET_SU_LIST, uids, size);
}
bool is_safe_mode() {
return ksuctl(CMD_CHECK_SAFEMODE, nullptr, nullptr);
}
}
bool uid_should_umount(int uid) {
bool should;
return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, reinterpret_cast<void*>(uid), &should) && should;
}
bool set_app_profile(const app_profile *profile) {
return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, nullptr);
}
bool get_app_profile(p_key_t key, app_profile *profile) {
return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr);
}

View File

@@ -5,16 +5,76 @@
#ifndef KERNELSU_KSU_H
#define KERNELSU_KSU_H
bool become_manager(const char*);
#include <linux/capability.h>
bool become_manager(const char *);
int get_version();
bool allow_su(int uid, bool allow);
bool get_allow_list(int *uids, int *size);
bool get_deny_list(int *uids, int *size);
bool uid_should_umount(int uid);
bool is_safe_mode();
#define KSU_APP_PROFILE_VER 2
#define KSU_MAX_PACKAGE_NAME 256
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
#define KSU_MAX_GROUPS 32
#define KSU_SELINUX_DOMAIN 64
using p_key_t = char[KSU_MAX_PACKAGE_NAME];
struct root_profile {
int32_t uid;
int32_t gid;
int32_t groups_count;
int32_t groups[KSU_MAX_GROUPS];
// kernel_cap_t is u32[2] for capabilities v3
struct {
uint64_t effective;
uint64_t permitted;
uint64_t inheritable;
} capabilities;
char selinux_domain[KSU_SELINUX_DOMAIN];
int32_t namespaces;
};
struct non_root_profile {
bool umount_modules;
};
struct app_profile {
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
uint32_t version;
// this is usually the package of the app, but can be other value for special apps
char key[KSU_MAX_PACKAGE_NAME];
int32_t current_uid;
bool allow_su;
union {
struct {
bool use_default;
char template_name[KSU_MAX_PACKAGE_NAME];
struct root_profile profile;
} rp_config;
struct {
bool use_default;
struct non_root_profile profile;
} nrp_config;
};
};
bool set_app_profile(const app_profile *profile);
bool get_app_profile(p_key_t key, app_profile *profile);
#endif //KERNELSU_KSU_H

View File

@@ -1,26 +0,0 @@
package me.weishu.kernelsu;
/**
* @author weishu
* @date 2022/12/8.
*/
public final class Natives {
static {
System.loadLibrary("kernelsu");
}
// become root manager, return true if success.
public static native boolean becomeManager(String pkg);
public static native int getVersion();
// get the uid list of allowed su processes.
public static native int[] getAllowList();
public static native int[] getDenyList();
public static native boolean allowRoot(int uid, boolean allow);
public static native boolean isSafeMode();
}

View File

@@ -0,0 +1,105 @@
package me.weishu.kernelsu
import android.os.Parcelable
import androidx.annotation.Keep
import androidx.compose.runtime.Immutable
import kotlinx.parcelize.Parcelize
/**
* @author weishu
* @date 2022/12/8.
*/
object Natives {
// minimal supported kernel version
// 10915: allowlist breaking change, add app profile
// 10931: app profile struct add 'version' field
// 10946: add capabilities
// 10977: change groups_count and groups to avoid overflow write
const val MINIMAL_SUPPORTED_KERNEL = 10977
init {
System.loadLibrary("kernelsu")
}
// become root manager, return true if success.
external fun becomeManager(pkg: String?): Boolean
val version: Int
external get
// get the uid list of allowed su processes.
val allowList: IntArray
external get
val isSafeMode: Boolean
external get
external fun uidShouldUmount(uid: Int): Boolean
/**
* Get the profile of the given package.
* @param key usually the package name
* @return return null if failed.
*/
external fun getAppProfile(key: String?, uid: Int): Profile
external fun setAppProfile(profile: Profile?): Boolean
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
private const val ROOT_DEFAULT_PROFILE_KEY = "#"
private const val NOBODY_UID = 9999
fun setDefaultUmountModules(umountModules: Boolean): Boolean {
Profile(
NON_ROOT_DEFAULT_PROFILE_KEY,
NOBODY_UID,
false,
umountModules = umountModules
).let {
return setAppProfile(it)
}
}
fun isDefaultUmountModules(): Boolean {
getAppProfile(NON_ROOT_DEFAULT_PROFILE_KEY, NOBODY_UID).let {
return it.umountModules
}
}
fun requireNewKernel(): Boolean {
return version < MINIMAL_SUPPORTED_KERNEL
}
@Immutable
@Parcelize
@Keep
data class Profile(
// and there is a default profile for root and non-root
val name: String,
// current uid for the package, this is convivent for kernel to check
// if the package name doesn't match uid, then it should be invalidated.
val currentUid: Int = 0,
// if this is true, kernel will grant root permission to this package
val allowSu: Boolean = false,
// these are used for root profile
val rootUseDefault: Boolean = true,
val rootTemplate: String? = null,
val uid: Int = 0,
val gid: Int = 0,
val groups: List<Int> = mutableListOf(),
val capabilities: List<Int> = mutableListOf(),
val context: String = "u:r:su:s0",
val namespace: Int = Namespace.Inherited.ordinal,
val nonRootUseDefault: Boolean = true,
val umountModules: Boolean = true,
) : Parcelable {
enum class Namespace {
Inherited,
Global,
Individual,
}
constructor() : this("")
}
}

View File

@@ -0,0 +1,49 @@
package me.weishu.kernelsu.profile
/**
* @author weishu
* @date 2023/6/3.
*/
enum class Capabilities(val cap: Int, val display: String, val desc: String) {
CAP_CHOWN(0, "CHOWN", "Make arbitrary changes to file UIDs and GIDs (see chown(2))"),
CAP_DAC_OVERRIDE(1, "DAC_OVERRIDE", "Bypass file read, write, and execute permission checks"),
CAP_DAC_READ_SEARCH(2, "DAC_READ_SEARCH", "Bypass file read permission checks and directory read and execute permission checks"),
CAP_FOWNER(3, "FOWNER", "Bypass permission checks on operations that normally require the filesystem UID of the process to match the UID of the file (e.g., chmod(2), utime(2)), excluding those operations covered by CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH"),
CAP_FSETID(4, "FSETID", "Dont clear set-user-ID and set-group-ID permission bits when a file is modified; set the set-group-ID bit for a file whose GID does not match the filesystem or any of the supplementary GIDs of the calling process"),
CAP_KILL(5, "KILL", "Bypass permission checks for sending signals (see kill(2))."),
CAP_SETGID(6, "SETGID", "Make arbitrary manipulations of process GIDs and supplementary GID list; allow setgid(2) manipulation of the callers effective and real group IDs"),
CAP_SETUID(7, "SETUID", "Make arbitrary manipulations of process UIDs (setuid(2), setreuid(2), setresuid(2), setfsuid(2)); allow changing the current process user IDs; allow changing of the current process group ID to any value in the systems range of legal group IDs"),
CAP_SETPCAP(8, "SETPCAP", "If file capabilities are supported: grant or remove any capability in the callers permitted capability set to or from any other process. (This property supersedes the obsolete notion of giving a process all capabilities by granting all capabilities in its permitted set, and of removing all capabilities from a process by granting no capabilities in its permitted set. It does not permit any actions that were not permitted before.)"),
CAP_LINUX_IMMUTABLE(9, "LINUX_IMMUTABLE", "Set the FS_APPEND_FL and FS_IMMUTABLE_FL inode flags (see chattr(1))."),
CAP_NET_BIND_SERVICE(10, "NET_BIND_SERVICE", "Bind a socket to Internet domain"),
CAP_NET_BROADCAST(11, "NET_BROADCAST", "Make socket broadcasts, and listen to multicasts"),
CAP_NET_ADMIN(12, "NET_ADMIN", "Perform various network-related operations: interface configuration, administration of IP firewall, masquerading, and accounting, modify routing tables, bind to any address for transparent proxying, set type-of-service (TOS), clear driver statistics, set promiscuous mode, enabling multicasting, use setsockopt(2) to set the following socket options: SO_DEBUG, SO_MARK, SO_PRIORITY (for a priority outside the range 0 to 6), SO_RCVBUFFORCE, and SO_SNDBUFFORCE"),
CAP_NET_RAW(13, "NET_RAW", "Use RAW and PACKET sockets"),
CAP_IPC_LOCK(14, "IPC_LOCK", "Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2))"),
CAP_IPC_OWNER(15, "IPC_OWNER", "Bypass permission checks for operations on System V IPC objects"),
CAP_SYS_MODULE(16, "SYS_MODULE", "Load and unload kernel modules (see init_module(2) and delete_module(2)); in kernels before 2.6.25, this also granted rights for various other operations related to kernel modules"),
CAP_SYS_RAWIO(17, "SYS_RAWIO", "Perform I/O port operations (iopl(2) and ioperm(2)); access /proc/kcore"),
CAP_SYS_CHROOT(18, "SYS_CHROOT", "Use chroot(2)"),
CAP_SYS_PTRACE(19, "SYS_PTRACE", "Trace arbitrary processes using ptrace(2)"),
CAP_SYS_PACCT(20, "SYS_PACCT", "Use acct(2)"),
CAP_SYS_ADMIN(21, "SYS_ADMIN", "Perform a range of system administration operations including: quotactl(2), mount(2), umount(2), swapon(2), swapoff(2), sethostname(2), and setdomainname(2); set and modify process resource limits (setrlimit(2)); perform various network-related operations (e.g., setting privileged socket options, enabling multicasting, interface configuration); perform various IPC operations (e.g., SysV semaphores, POSIX message queues, System V shared memory); allow reboot and kexec_load(2); override /proc/sys kernel tunables; perform ptrace(2) PTRACE_SECCOMP_GET_FILTER operation; perform some tracing and debugging operations (see ptrace(2)); administer the lifetime of kernel tracepoints (tracefs(5)); perform the KEYCTL_CHOWN and KEYCTL_SETPERM keyctl(2) operations; perform the following keyctl(2) operations: KEYCTL_CAPABILITIES, KEYCTL_CAPSQUASH, and KEYCTL_PKEY_ OPERATIONS; set state for the Extensible Authentication Protocol (EAP) kernel module; and override the RLIMIT_NPROC resource limit; allow ioperm/iopl access to I/O ports"),
CAP_SYS_BOOT(22, "SYS_BOOT", "Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution"),
CAP_SYS_NICE(23, "SYS_NICE", "Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes; set real-time scheduling policies for calling process, and set scheduling policies and priorities for arbitrary processes (sched_setscheduler(2), sched_setparam(2)"),
CAP_SYS_RESOURCE(24, "SYS_RESOURCE", "Override resource Limits. Set resource limits (setrlimit(2), prlimit(2)), override quota limits (quota(2), quotactl(2)), override reserved space on ext2 filesystem (ext2_ioctl(2)), override size restrictions on IPC message queues (msg(2)) and system V shared memory segments (shmget(2)), and override the /proc/sys/fs/pipe-size-max limit"),
CAP_SYS_TIME(25, "SYS_TIME", "Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock"),
CAP_SYS_TTY_CONFIG(26, "SYS_TTY_CONFIG", "Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals"),
CAP_MKNOD(27, "MKNOD", "Create special files using mknod(2)"),
CAP_LEASE(28, "LEASE", "Establish leases on arbitrary files (see fcntl(2))"),
CAP_AUDIT_WRITE(29, "AUDIT_WRITE", "Write records to kernel auditing log"),
CAP_AUDIT_CONTROL(30, "AUDIT_CONTROL", "Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules"),
CAP_SETFCAP(31, "SETFCAP", "If file capabilities are supported: grant or remove any capability in any capability set to any file"),
CAP_MAC_OVERRIDE(32, "MAC_OVERRIDE", "Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM)"),
CAP_MAC_ADMIN(33, "MAC_ADMIN", "Allow MAC configuration or state changes. Implemented for the Smack LSM"),
CAP_SYSLOG(34, "SYSLOG", "Perform privileged syslog(2) operations. See syslog(2) for information on which operations require privilege"),
CAP_WAKE_ALARM(35, "WAKE_ALARM", "Trigger something that will wake up the system"),
CAP_BLOCK_SUSPEND(36, "BLOCK_SUSPEND", "Employ features that can block system suspend"),
CAP_AUDIT_READ(37, "AUDIT_READ", "Allow reading the audit log via a multicast netlink socket"),
CAP_PERFMON(38, "PERFMON", "Allow performance monitoring via perf_event_open(2)"),
CAP_BPF(39, "BPF", "Allow BPF operations via bpf(2)"),
CAP_CHECKPOINT_RESTORE(40, "CHECKPOINT_RESTORE", "Allow processes to be checkpointed via checkpoint/restore in user namespace(2)"),
}

View File

@@ -0,0 +1,87 @@
package me.weishu.kernelsu.profile
/**
* @author weishu
* @date 2023/6/3.
*/
enum class Groups(val gid: Int, val display: String, val desc: String) {
ROOT(0, "root", "traditional unix root user"),
DAEMON(1, "daemon", "Traditional unix daemon owner."),
BIN(2, "bin", "Traditional unix binaries owner."),
SYS(3, "sys", "A group with the same gid on Linux/macOS/Android."),
SYSTEM(1000, "system", "system server"),
RADIO(1001, "radio", "telephony subsystem, RIL"),
BLUETOOTH(1002, "bluetooth", "bluetooth subsystem"),
GRAPHICS(1003, "graphics", "graphics devices"),
INPUT(1004, "input", "input devices"),
AUDIO(1005, "audio", "audio devices"),
CAMERA(1006, "camera", "camera devices"),
LOG(1007, "log", "log devices"),
COMPASS(1008, "compass", "compass device"),
MOUNT(1009, "mount", "mountd socket"),
WIFI(1010, "wifi", "wifi subsystem"),
ADB(1011, "adb", "android debug bridge (adbd)"),
INSTALL(1012, "install", "group for installing packages"),
MEDIA(1013, "media", "mediaserver process"),
DHCP(1014, "dhcp", "dhcp client"),
SDCARD_RW(1015, "sdcard_rw", "external storage write access"),
VPN(1016, "vpn", "vpn system"),
KEYSTORE(1017, "keystore", "keystore subsystem"),
USB(1018, "usb", "USB devices"),
DRM(1019, "drm", "DRM server"),
MDNSR(1020, "mdnsr", "MulticastDNSResponder (service discovery)"),
GPS(1021, "gps", "GPS daemon"),
UNUSED1(1022, "unused1", "deprecated, DO NOT USE"),
MEDIA_RW(1023, "media_rw", "internal media storage write access"),
MTP(1024, "mtp", "MTP USB driver access"),
UNUSED2(1025, "unused2", "deprecated, DO NOT USE"),
DRMRPC(1026, "drmrpc", "group for drm rpc"),
NFC(1027, "nfc", "nfc subsystem"),
SDCARD_R(1028, "sdcard_r", "external storage read access"),
CLAT(1029, "clat", "clat part of nat464"),
LOOP_RADIO(1030, "loop_radio", "loop radio devices"),
MEDIA_DRM(1031, "media_drm", "MediaDrm plugins"),
PACKAGE_INFO(1032, "package_info", "access to installed package details"),
SDCARD_PICS(1033, "sdcard_pics", "external storage photos access"),
SDCARD_AV(1034, "sdcard_av", "external storage audio/video access"),
SDCARD_ALL(1035, "sdcard_all", "access all users external storage"),
LOGD(1036, "logd", "log daemon"),
SHARED_RELRO(1037, "shared_relro", "creator of shared GNU RELRO files"),
DBUS(1038, "dbus", "dbus-daemon IPC broker process"),
TLSDATE(1039, "tlsdate", "tlsdate unprivileged user"),
MEDIA_EX(1040, "media_ex", "mediaextractor process"),
AUDIOSERVER(1041, "audioserver", "audioserver process"),
METRICS_COLL(1042, "metrics_coll", "metrics_collector process"),
METRICSD(1043, "metricsd", "metricsd process"),
WEBSERV(1044, "webserv", "webservd process"),
DEBUGGERD(1045, "debuggerd", "debuggerd unprivileged user"),
MEDIA_CODEC(1046, "media_codec", "media_codec process"),
CAMERASERVER(1047, "cameraserver", "cameraserver process"),
FIREWALL(1048, "firewall", "firewall process"),
TRUNKS(1049, "trunks", "trunksd process"),
NVRAM(1050, "nvram", "nvram daemon"),
DNS_TETHER(1051, "dns_tether", "dns_tether device"),
DNS_TETHER_RESERVED(1052, "dns_tether_reserved", "Reserved range for dns_tether"),
WEBVIEW_ZYGOTE(1053, "webview_zygote", "zygote process"),
WEBVIEW_USER(1054, "webview_user", "webview chromium user"),
ETHERNET(1055, "ethernet", "Ethernet"),
TOMBSTONED(1056, "tombstoned", "tombstoned process"),
GRAPHICS_RW(1057, "graphics_rw", "graphics devices"),
SHELL(2000, "shell", "adb and debug shell user"),
CACHE(2001, "cache", "cache access"),
DIAG(2002, "diag", "diagnostics"),
NET_BT_ADMIN(3001, "net_bt_admin", "bluetooth: create any socket"),
NET_BT(3002, "net_bt", "bluetooth: create sco, rfcomm or l2cap sockets"),
INET(3003, "inet", "can create AF_INET and AF_INET6 sockets"),
NET_RAW(3004, "net_raw", "can create raw INET sockets"),
NET_ADMIN(3005, "net_admin", "can configure interfaces and routing tables."),
NET_BW_STATS(3006, "net_bw_stats", "read bandwidth statistics"),
NET_BW_ACCT(3007, "net_bw_acct", "change bandwidth statistics accounting"),
NET_BT_STACK(3008, "net_bt_stack", "access to various bluetooth management functions"),
QCOM_DIAG(3009, "qcom_diag", "allow msm specific diag commands"),
EVERYBODY(9997, "everybody", "Shared external storage read/write"),
MISC(9998, "misc", "Access to misc storage"),
NOBODY(9999, "nobody", "Reserved"),
APP(10000, "app", "Access to app data"),
}

View File

@@ -5,7 +5,6 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
@@ -25,6 +24,8 @@ import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.navigation.popBackStack
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.component.rememberDialogHostState
import me.weishu.kernelsu.ui.screen.BottomBarDestination
import me.weishu.kernelsu.ui.screen.NavGraphs
@@ -34,7 +35,7 @@ import me.weishu.kernelsu.ui.util.LocalSnackbarHost
class MainActivity : ComponentActivity() {
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterial3Api::class)
@OptIn(ExperimentalAnimationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -64,8 +65,11 @@ class MainActivity : ComponentActivity() {
@Composable
private fun BottomBar(navController: NavHostController) {
val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel()
NavigationBar(tonalElevation = 8.dp) {
BottomBarDestination.values().forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
NavigationBarItem(
selected = isCurrentDestOnBackStack,

View File

@@ -10,10 +10,22 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -21,11 +33,9 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import me.weishu.kernelsu.R
private const val TAG = "SearchBar"

View File

@@ -0,0 +1,52 @@
package me.weishu.kernelsu.ui.component
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
@Composable
fun SwitchItem(
icon: ImageVector? = null,
title: String,
summary: String? = null,
checked: Boolean,
enabled: Boolean = true,
onCheckedChange: (Boolean) -> Unit
) {
ListItem(
headlineContent = {
Text(title)
},
leadingContent = icon?.let {
{ Icon(icon, title) }
},
trailingContent = {
Switch(checked = checked, enabled = enabled, onCheckedChange = onCheckedChange)
},
supportingContent = {
if (summary != null) {
Text(summary)
}
}
)
}
@Composable
fun RadioItem(
title: String,
selected: Boolean,
onClick: () -> Unit,
) {
ListItem(
headlineContent = {
Text(title)
},
leadingContent = {
RadioButton(selected = selected, onClick = onClick)
},
)
}

View File

@@ -0,0 +1,63 @@
package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.SwitchItem
@Composable
fun AppProfileConfig(
modifier: Modifier = Modifier,
fixedName: Boolean,
enabled: Boolean,
profile: Natives.Profile,
onProfileChange: (Natives.Profile) -> Unit,
) {
Column(modifier = modifier) {
if (!fixedName) {
OutlinedTextField(
label = { Text(stringResource(R.string.profile_name)) },
value = profile.name,
onValueChange = { onProfileChange(profile.copy(name = it)) }
)
}
SwitchItem(
title = stringResource(R.string.profile_umount_modules),
summary = stringResource(R.string.profile_umount_modules_summary),
checked = if (enabled) {
profile.umountModules
} else {
Natives.isDefaultUmountModules()
},
enabled = enabled,
onCheckedChange = {
onProfileChange(
profile.copy(
umountModules = it,
nonRootUseDefault = false
)
)
}
)
}
}
@Preview
@Composable
private fun AppProfileConfigPreview() {
var profile by remember { mutableStateOf(Natives.Profile("")) }
AppProfileConfig(fixedName = true, enabled = false, profile = profile) {
profile = it
}
}

View File

@@ -0,0 +1,359 @@
@file:OptIn(ExperimentalMaterial3Api::class)
package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material3.AssistChip
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.text.isDigitsOnly
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.profile.Capabilities
import me.weishu.kernelsu.profile.Groups
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun RootProfileConfig(
modifier: Modifier = Modifier,
fixedName: Boolean,
profile: Natives.Profile,
onProfileChange: (Natives.Profile) -> Unit,
) {
Column(modifier = modifier) {
if (!fixedName) {
OutlinedTextField(
label = { Text(stringResource(R.string.profile_name)) },
value = profile.name,
onValueChange = { onProfileChange(profile.copy(name = it)) }
)
}
var expanded by remember { mutableStateOf(false) }
val currentNamespace = when (profile.namespace) {
Natives.Profile.Namespace.Inherited.ordinal -> stringResource(R.string.profile_namespace_inherited)
Natives.Profile.Namespace.Global.ordinal -> stringResource(R.string.profile_namespace_global)
Natives.Profile.Namespace.Individual.ordinal -> stringResource(R.string.profile_namespace_individual)
else -> stringResource(R.string.profile_namespace_inherited)
}
ListItem(headlineContent = {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded }
) {
OutlinedTextField(
modifier = Modifier
.menuAnchor()
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_namespace)) },
value = currentNamespace,
onValueChange = {},
trailingIcon = {
if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
else Icon(Icons.Filled.ArrowDropDown, null)
},
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_inherited)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Inherited.ordinal))
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_global)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Global.ordinal))
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_individual)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Individual.ordinal))
expanded = false
},
)
}
}
})
UidPanel(uid = profile.uid, label = "uid", onUidChange = {
onProfileChange(
profile.copy(
uid = it,
rootUseDefault = false
)
)
})
UidPanel(uid = profile.gid, label = "gid", onUidChange = {
onProfileChange(
profile.copy(
gid = it,
rootUseDefault = false
)
)
})
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e ->
e.mapNotNull { g ->
Groups.values().find { it.gid == g }
}
}
GroupsPanel(selectedGroups) {
onProfileChange(
profile.copy(
groups = it.map { group -> group.gid }.ifEmpty { listOf(0) },
rootUseDefault = false
)
)
}
val selectedCaps = profile.capabilities.mapNotNull { e ->
Capabilities.values().find { it.cap == e }
}
CapsPanel(selectedCaps) {
onProfileChange(
profile.copy(
capabilities = it.map { cap -> cap.cap },
rootUseDefault = false
)
)
}
ListItem(headlineContent = {
val keyboardController = LocalSoftwareKeyboardController.current
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text("SELinux context") },
value = profile.context,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Ascii,
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(onDone = {
keyboardController?.hide()
}),
onValueChange = {
onProfileChange(profile.copy(context = it, rootUseDefault = false))
}
)
})
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>) -> Unit) {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
val groups = Groups.values()
val options = groups.map { value ->
ListOption(
titleText = value.display,
selected = selected.contains(value),
)
}
val selection = HashSet(selected)
ListDialog(
state = rememberUseCaseState(visible = true, onFinishedRequest = {
closeSelection(selection)
}, onCloseRequest = {
showDialog = false
}),
selection = ListSelection.Multiple(
showCheckBoxes = true,
options = options,
maxChoices = 32, // Kernel only supports 32 groups at most
) { indecies, _ ->
// Handle selection
selection.clear()
indecies.forEach { index ->
val group = groups[index]
selection.add(group)
}
}
)
}
OutlinedCard(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
showDialog = true
}) {
Column(modifier = Modifier.padding(16.dp)) {
Text("groups")
FlowRow {
selected.forEach { group ->
AssistChip(
modifier = Modifier.padding(3.dp),
onClick = { /*TODO*/ },
label = { Text(group.display) })
}
}
}
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun CapsPanel(
selected: Collection<Capabilities>,
closeSelection: (selection: Set<Capabilities>) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
val caps = Capabilities.values()
val options = caps.map { value ->
ListOption(
titleText = value.display,
selected = selected.contains(value),
)
}
val selection = HashSet(selected)
ListDialog(
state = rememberUseCaseState(visible = true, onFinishedRequest = {
closeSelection(selection)
}, onCloseRequest = {
showDialog = false
}),
selection = ListSelection.Multiple(
showCheckBoxes = true,
options = options
) { indecies, _ ->
// Handle selection
selection.clear()
indecies.forEach { index ->
val group = caps[index]
selection.add(group)
}
}
)
}
OutlinedCard(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
showDialog = true
}) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Capabilities")
FlowRow {
selected.forEach { group ->
AssistChip(
modifier = Modifier.padding(3.dp),
onClick = { /*TODO*/ },
label = { Text(group.display) })
}
}
}
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
ListItem(headlineContent = {
var isError by remember {
mutableStateOf(false)
}
var lastValidUid by remember {
mutableStateOf(uid)
}
val keyboardController = LocalSoftwareKeyboardController.current
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
value = uid.toString(),
isError = isError,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = {
keyboardController?.hide()
}),
onValueChange = {
val valid = isTextValidUid(it)
val targetUid = if (valid) it.toInt() else lastValidUid
if (valid) {
lastValidUid = it.toInt()
}
onUidChange(targetUid)
isError = !valid
}
)
})
}
@Preview
@Composable
private fun RootProfileConfigPreview() {
var profile by remember { mutableStateOf(Natives.Profile("")) }
RootProfileConfig(fixedName = true, profile = profile) {
profile = it
}
}
private fun isTextValidUid(text: String): Boolean {
return text.isNotEmpty() && text.isDigitsOnly() && text.toInt() >= 0 && text.toInt() <= Int.MAX_VALUE
}

View File

@@ -0,0 +1,308 @@
package me.weishu.kernelsu.ui.screen
import android.util.Log
import androidx.annotation.StringRes
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material.icons.filled.Security
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.profile.AppProfileConfig
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
/**
* @author weishu
* @date 2023/5/16.
*/
@Destination
@Composable
fun AppProfileScreen(
navigator: DestinationsNavigator,
appInfo: SuperUserViewModel.AppInfo,
) {
val context = LocalContext.current
val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val failToUpdateAppProfile =
stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
val packageName = appInfo.packageName
var profile by rememberSaveable {
mutableStateOf(Natives.getAppProfile(packageName, appInfo.uid))
}
Log.i("mylog", "profile: $profile")
Scaffold(
topBar = { TopBar { navigator.popBackStack() } }
) { paddingValues ->
AppProfileInner(
modifier = Modifier
.padding(paddingValues)
.verticalScroll(rememberScrollState()),
packageName = appInfo.packageName,
appLabel = appInfo.label,
appIcon = {
AsyncImage(
model = ImageRequest.Builder(context)
.data(appInfo.packageInfo)
.crossfade(true)
.build(),
contentDescription = appInfo.label,
modifier = Modifier
.padding(4.dp)
.width(48.dp)
.height(48.dp)
)
},
profile = profile,
onProfileChange = {
scope.launch {
if (!Natives.setAppProfile(it)) {
snackbarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
} else {
profile = it
}
}
},
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AppProfileInner(
modifier: Modifier = Modifier,
packageName: String,
appLabel: String,
appIcon: @Composable () -> Unit,
profile: Natives.Profile,
onProfileChange: (Natives.Profile) -> Unit,
) {
val isRootGranted = profile.allowSu
Column(modifier = modifier) {
ListItem(
headlineContent = { Text(appLabel) },
supportingContent = { Text(packageName) },
leadingContent = appIcon,
)
SwitchItem(
icon = Icons.Filled.Security,
title = stringResource(id = R.string.superuser),
checked = isRootGranted,
onCheckedChange = { onProfileChange(profile.copy(allowSu = it)) },
)
Crossfade(targetState = isRootGranted, label = "") { current ->
Column {
if (current) {
val initialMode = if (profile.rootUseDefault) {
Mode.Default
} else if (profile.rootTemplate != null) {
Mode.Template
} else {
Mode.Custom
}
var mode by remember {
mutableStateOf(initialMode)
}
ProfileBox(mode, false) {
// template mode shouldn't change profile here!
if (it == Mode.Default || it == Mode.Custom) {
onProfileChange(profile.copy(rootUseDefault = it == Mode.Default))
}
mode = it
}
Crossfade(targetState = mode, label = "") { currentMode ->
if (currentMode == Mode.Template) {
var expanded by remember { mutableStateOf(false) }
val templateNone = "None"
var template by rememberSaveable {
mutableStateOf(
profile.rootTemplate
?: templateNone
)
}
ListItem(headlineContent = {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = it },
) {
OutlinedTextField(
modifier = Modifier.menuAnchor(),
readOnly = true,
label = { Text(stringResource(R.string.profile_template)) },
value = template,
onValueChange = {
if (template != templateNone) {
onProfileChange(
profile.copy(
rootTemplate = it,
rootUseDefault = false
)
)
template = it
}
},
trailingIcon = {
if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
else Icon(Icons.Filled.ArrowDropDown, null)
},
)
// TODO: Template
}
})
} else if (mode == Mode.Custom) {
RootProfileConfig(
fixedName = true,
profile = profile,
onProfileChange = onProfileChange
)
}
}
} else {
val mode = if (profile.nonRootUseDefault) Mode.Default else Mode.Custom
ProfileBox(mode, false) {
onProfileChange(profile.copy(nonRootUseDefault = (it == Mode.Default)))
}
Crossfade(targetState = mode, label = "") { currentMode ->
val modifyEnabled = currentMode == Mode.Custom
AppProfileConfig(
fixedName = true,
profile = profile,
enabled = modifyEnabled,
onProfileChange = onProfileChange
)
}
}
}
}
}
}
private enum class Mode(@StringRes private val res: Int) {
Default(R.string.profile_default),
Template(R.string.profile_template),
Custom(R.string.profile_custom);
val text: String
@Composable get() = stringResource(res)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onBack: () -> Unit) {
TopAppBar(
title = {
Text(stringResource(R.string.profile))
},
navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) }
},
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ProfileBox(
mode: Mode,
hasTemplate: Boolean,
onModeChange: (Mode) -> Unit,
) {
ListItem(
headlineContent = { Text(stringResource(R.string.profile)) },
supportingContent = { Text(mode.text) },
leadingContent = { Icon(Icons.Filled.AccountCircle, null) },
)
Divider(thickness = Dp.Hairline)
ListItem(headlineContent = {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
FilterChip(
selected = mode == Mode.Default,
label = { Text(stringResource(R.string.profile_default)) },
onClick = { onModeChange(Mode.Default) },
)
if (hasTemplate) {
FilterChip(
selected = mode == Mode.Template,
label = { Text(stringResource(R.string.profile_template)) },
onClick = { onModeChange(Mode.Template) },
)
}
FilterChip(
selected = mode == Mode.Custom,
label = { Text(stringResource(R.string.profile_custom)) },
onClick = { onModeChange(Mode.Custom) },
)
}
})
}
@Preview
@Composable
private fun AppProfilePreview() {
var profile by remember { mutableStateOf(Natives.Profile("")) }
AppProfileInner(
packageName = "icu.nullptr.test",
appLabel = "Test",
appIcon = { Icon(Icons.Filled.Android, null) },
profile = profile,
onProfileChange = {
profile = it
},
)
}

View File

@@ -15,9 +15,10 @@ enum class BottomBarDestination(
val direction: DirectionDestinationSpec,
@StringRes val label: Int,
val iconSelected: ImageVector,
val iconNotSelected: ImageVector
val iconNotSelected: ImageVector,
val rootRequired: Boolean,
) {
Home(HomeScreenDestination, R.string.home, Icons.Filled.Home, Icons.Outlined.Home),
SuperUser(SuperUserScreenDestination, R.string.superuser, Icons.Filled.Security, Icons.Outlined.Security),
Module(ModuleScreenDestination, R.string.module, Icons.Filled.Apps, Icons.Outlined.Apps)
Home(HomeScreenDestination, R.string.home, Icons.Filled.Home, Icons.Outlined.Home, false),
SuperUser(SuperUserScreenDestination, R.string.superuser, Icons.Filled.Security, Icons.Outlined.Security, true),
Module(ModuleScreenDestination, R.string.module, Icons.Filled.Apps, Icons.Outlined.Apps, true)
}

View File

@@ -33,7 +33,6 @@ import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.screen.destinations.SettingScreenDestination
import me.weishu.kernelsu.ui.util.*
@OptIn(ExperimentalMaterial3Api::class)
@RootNavGraph(start = true)
@Destination
@Composable
@@ -57,9 +56,17 @@ fun HomeScreen(navigator: DestinationsNavigator) {
SideEffect {
if (isManager) install()
}
val ksuVersion = if (isManager) Natives.getVersion() else null
val ksuVersion = if (isManager) Natives.version else null
StatusCard(kernelVersion, ksuVersion)
if (isManager && Natives.requireNewKernel()) {
WarningCard(
stringResource(id = R.string.require_kernel_version).format(
ksuVersion,
Natives.MINIMAL_SUPPORTED_KERNEL
)
)
}
InfoCard()
DonateCard()
LearnMoreCard()
@@ -142,7 +149,7 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
) {
when {
ksuVersion != null -> {
val appendText = if (Natives.isSafeMode()) {
val appendText = if (Natives.isSafeMode) {
" [${stringResource(id = R.string.safe_mode)}]"
} else {
""
@@ -160,7 +167,10 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_superuser_count, getSuperuserCount()),
text = stringResource(
R.string.home_superuser_count,
getSuperuserCount()
),
style = MaterialTheme.typography.bodyMedium
)
Spacer(Modifier.height(4.dp))
@@ -170,6 +180,7 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
)
}
}
kernelVersion.isGKI() -> {
Icon(Icons.Outlined.Warning, stringResource(R.string.home_not_installed))
Column(Modifier.padding(start = 20.dp)) {
@@ -184,6 +195,7 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
)
}
}
else -> {
Icon(Icons.Outlined.Block, stringResource(R.string.home_unsupported))
Column(Modifier.padding(start = 20.dp)) {
@@ -204,6 +216,29 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
}
}
@Composable
fun WarningCard(message: String) {
ElevatedCard(
colors = CardDefaults.elevatedCardColors(
containerColor = MaterialTheme.colorScheme.error
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Column() {
Text(
text = message,
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
@Composable
fun LearnMoreCard() {
val uriHandler = LocalUriHandler.current

View File

@@ -35,7 +35,6 @@ import java.util.*
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@Destination
fun InstallScreen(navigator: DestinationsNavigator, uri: Uri) {

View File

@@ -39,7 +39,6 @@ import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Destination
@Composable
fun ModuleScreen(navigator: DestinationsNavigator) {
@@ -51,11 +50,10 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
}
}
val isSafeMode = Natives.isSafeMode()
val isKSUVersionInvalid = Natives.getVersion() < 0
val isSafeMode = Natives.isSafeMode
val hasMagisk = hasMagisk()
val hideInstallButton = isSafeMode || isKSUVersionInvalid || hasMagisk
val hideInstallButton = isSafeMode || hasMagisk
Scaffold(topBar = {
TopBar()
@@ -94,11 +92,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
ConfirmDialog()
when {
isKSUVersionInvalid -> {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(stringResource(R.string.require_kernel_version_8))
}
}
hasMagisk -> {
Box(
modifier = Modifier

View File

@@ -2,25 +2,31 @@ package me.weishu.kernelsu.ui.screen
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.BugReport
import androidx.compose.material.icons.filled.ContactPage
import androidx.compose.material.icons.filled.RemoveModerator
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.content.FileProvider
import com.alorma.compose.settings.ui.*
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.AboutDialog
import me.weishu.kernelsu.ui.component.LoadingDialog
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.getBugreportFile
@@ -28,7 +34,6 @@ import me.weishu.kernelsu.ui.util.getBugreportFile
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination
@Composable
fun SettingScreen(navigator: DestinationsNavigator) {
@@ -50,11 +55,25 @@ fun SettingScreen(navigator: DestinationsNavigator) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val dialogHost = LocalDialogHost.current
SettingsMenuLink(
title = {
Text(stringResource(id = R.string.send_log))
},
onClick = {
var umountChecked by rememberSaveable {
mutableStateOf(Natives.isDefaultUmountModules())
}
SwitchItem(
icon = Icons.Filled.RemoveModerator,
title = stringResource(id = R.string.settings_umount_modules_default),
summary = stringResource(id = R.string.settings_umount_modules_default_summary),
checked = umountChecked
) {
if (Natives.setDefaultUmountModules(it)) {
umountChecked = it
}
}
ListItem(
leadingContent = { Icon(Icons.Filled.BugReport, stringResource(id = R.string.send_log)) },
headlineContent = { Text(stringResource(id = R.string.send_log)) },
modifier = Modifier.clickable {
scope.launch {
val bugreport = dialogHost.withLoading {
withContext(Dispatchers.IO) {
@@ -85,11 +104,10 @@ fun SettingScreen(navigator: DestinationsNavigator) {
)
val about = stringResource(id = R.string.about)
SettingsMenuLink(
title = {
Text(about)
},
onClick = {
ListItem(
leadingContent = { Icon(Icons.Filled.ContactPage, stringResource(id = R.string.about)) },
headlineContent = { Text(about) },
modifier = Modifier.clickable {
showAboutDialog.value = true
}
)
@@ -108,4 +126,4 @@ private fun TopBar(onBack: () -> Unit = {}) {
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) }
},
)
}
}

View File

@@ -1,8 +1,11 @@
package me.weishu.kernelsu.ui.screen
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
@@ -11,33 +14,32 @@ import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.SearchAppBar
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.screen.destinations.AppProfileScreenDestination
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
import java.util.*
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
@OptIn(ExperimentalMaterialApi::class)
@Destination
@Composable
fun SuperUserScreen() {
fun SuperUserScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel<SuperUserViewModel>()
val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
LaunchedEffect(Unit) {
@@ -105,39 +107,12 @@ fun SuperUserScreen() {
.padding(innerPadding)
.pullRefresh(refreshState)
) {
val failMessage = stringResource(R.string.superuser_failed_to_grant_root)
LazyColumn(Modifier.fillMaxSize()) {
items(viewModel.appList, key = { it.packageName + it.uid }) { app ->
var isChecked by rememberSaveable(app) { mutableStateOf(app.onAllowList) }
val dialogHost = LocalDialogHost.current
val content =
stringResource(id = R.string.superuser_allow_root_confirm, app.label)
val confirm = stringResource(id = android.R.string.ok)
val cancel = stringResource(id = android.R.string.cancel)
AppItem(app, isChecked) { checked ->
scope.launch {
if (checked) {
val confirmResult = dialogHost.showConfirm(
app.label,
content = content,
confirm = confirm,
dismiss = cancel
)
if (confirmResult != ConfirmResult.Confirmed) {
return@launch
}
}
val success = Natives.allowRoot(app.uid, checked)
if (success) {
isChecked = checked
} else {
snackbarHost.showSnackbar(failMessage.format(app.uid))
}
}
AppItem(app) {
navigator.navigate(AppProfileScreenDestination(app))
}
}
}
@@ -150,20 +125,36 @@ fun SuperUserScreen() {
}
}
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun AppItem(
app: SuperUserViewModel.AppInfo,
isChecked: Boolean,
onCheckedChange: (Boolean) -> Unit
onClickListener: () -> Unit,
) {
ListItem(
headlineText = { Text(app.label) },
supportingText = { Text(app.packageName) },
modifier = Modifier.clickable(onClick = onClickListener),
headlineContent = { Text(app.label) },
supportingContent = {
Column {
Text(app.packageName)
FlowRow {
if (app.allowSu) {
LabelText(label = "ROOT")
} else {
if (Natives.uidShouldUmount(app.uid)) {
LabelText(label = "UMOUNT")
}
}
if (app.hasCustomProfile) {
LabelText(label = "CUSTOM")
}
}
}
},
leadingContent = {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(app.icon)
.data(app.packageInfo)
.crossfade(true)
.build(),
contentDescription = app.label,
@@ -173,12 +164,26 @@ private fun AppItem(
.height(48.dp)
)
},
trailingContent = {
Switch(
checked = isChecked,
onCheckedChange = onCheckedChange,
modifier = Modifier.padding(4.dp)
)
}
)
}
@Composable
fun LabelText(label: String) {
Box(
modifier = Modifier
.padding(top = 4.dp, end = 4.dp)
.background(
Color.Black,
shape = RoundedCornerShape(4.dp)
)
) {
Text(
text = label,
modifier = Modifier.padding(vertical = 2.dp, horizontal = 5.dp),
style = TextStyle(
fontSize = 8.sp,
color = Color.White,
)
)
}
}

View File

@@ -71,7 +71,7 @@ fun getModuleCount(): Int {
}
fun getSuperuserCount(): Int {
return Natives.getAllowList().size
return Natives.allowList.size
}
fun toggleModule(id: String, enable: Boolean): Boolean {

View File

@@ -72,9 +72,9 @@ fun getBugreportFile(context: Context): File {
pw.println("Nodename: ${uname.nodename}")
pw.println("Sysname: ${uname.sysname}")
val ksuKernel = Natives.getVersion()
val ksuKernel = Natives.version
pw.println("KernelSU: $ksuKernel")
val safeMode = Natives.isSafeMode()
val safeMode = Natives.isSafeMode
pw.println("SafeMode: $safeMode")
}

View File

@@ -6,6 +6,7 @@ import android.content.ServiceConnection
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.os.IBinder
import android.os.Parcelable
import android.os.SystemClock
import android.util.Log
import androidx.compose.runtime.derivedStateOf
@@ -16,6 +17,7 @@ import androidx.lifecycle.ViewModel
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import me.weishu.kernelsu.IKsuInterface
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
@@ -34,14 +36,32 @@ class SuperUserViewModel : ViewModel() {
private var apps by mutableStateOf<List<AppInfo>>(emptyList())
}
class AppInfo(
@Parcelize
data class AppInfo(
val label: String,
val packageName: String,
val icon: PackageInfo,
val uid: Int,
val onAllowList: Boolean,
val onDenyList: Boolean
)
val packageInfo: PackageInfo,
val profile: Natives.Profile?,
) : Parcelable {
val packageName: String
get() = packageInfo.packageName
val uid: Int
get() = packageInfo.applicationInfo.uid
val allowSu: Boolean
get() = profile != null && profile.allowSu
val hasCustomProfile: Boolean
get() {
if (profile == null) {
return false
}
return if (profile.allowSu) {
!profile.rootUseDefault
} else {
!profile.nonRootUseDefault
}
}
}
var search by mutableStateOf("")
var showSystemApps by mutableStateOf(false)
@@ -51,8 +71,8 @@ class SuperUserViewModel : ViewModel() {
private val sortedList by derivedStateOf {
val comparator = compareBy<AppInfo> {
when {
it.onAllowList -> 0
it.onDenyList -> 1
it.allowSu -> 0
it.hasCustomProfile -> 1
else -> 2
}
}.then(compareBy(Collator.getInstance(Locale.getDefault()), AppInfo::label))
@@ -67,7 +87,7 @@ class SuperUserViewModel : ViewModel() {
.toPinyinString(it.label).contains(search)
}.filter {
it.uid == 2000 // Always show shell
|| showSystemApps || it.icon.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0
|| showSystemApps || it.packageInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0
}
}
@@ -107,13 +127,9 @@ class SuperUserViewModel : ViewModel() {
val result = connectKsuService {
Log.w(TAG, "KsuService disconnected")
}
withContext(Dispatchers.IO) {
val pm = ksuApp.packageManager
val allowList = Natives.getAllowList().toSet()
val denyList = Natives.getDenyList().toSet()
Log.i(TAG, "allowList: $allowList")
Log.i(TAG, "denyList: $denyList")
val start = SystemClock.elapsedRealtime()
val binder = result.first
@@ -128,13 +144,11 @@ class SuperUserViewModel : ViewModel() {
apps = packages.map {
val appInfo = it.applicationInfo
val uid = appInfo.uid
val profile = Natives.getAppProfile(it.packageName, uid)
AppInfo(
label = appInfo.loadLabel(pm).toString(),
packageName = it.packageName,
icon = it,
uid = uid,
onAllowList = uid in allowList,
onDenyList = uid in denyList
packageInfo = it,
profile = profile,
)
}.filter { it.packageName != ksuApp.packageName }
Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}")

View File

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

View File

@@ -11,16 +11,10 @@
<string name="home_module_count">মডিউল: %d</string>
<string name="home_unsupported">অসমর্থিত</string>
<string name="home_unsupported_reason">কার্নেলএসইউ শুধুমাত্র জিকেআই কার্নেল সমর্থন করে</string>
<string name="home_copied_to_clipboard">ক্লিপবোর্ডে কপি করা হয়েছে</string>
<string name="home_support">সমর্থন</string>
<string name="home_kernel">কার্নেল</string>
<string name="home_arch">খিলান</string>
<string name="home_manager_version">ম্যানেজার সংস্করণ</string>
<string name="home_api">এপিআই স্তর</string>
<string name="home_abi">এবিআই</string>
<string name="home_fingerprint">ফিঙ্গারপ্রিন্ট</string>
<string name="home_securitypatch">সিকিউরিটি প্যাচ</string>
<string name="home_selinux_status">সেলিনাক্স স্ট্যাটাস</string>
<string name="selinux_status_disabled">ডিজেবল</string>
@@ -28,8 +22,6 @@
<string name="selinux_status_permissive">অনুমতিমূলক</string>
<string name="selinux_status_unknown">অপরিচিত</string>
<string name="superuser">সুপার ইউজার</string>
<string name="superuser_failed_to_grant_root">এর জন্য রুট প্রদান করতে ব্যর্থ হয়েছে %d</string>
<string name="superuser_allow_root_confirm">নিশ্চিত আপনি রুট দিতে চান %s?</string>
<string name="module_failed_to_enable">মডিউল সক্ষম করতে ব্যর্থ হয়েছে: %s</string>
<string name="module_failed_to_disable">মডিউল নিষ্ক্রিয় করতে ব্যর্থ হয়েছে: %s</string>
<string name="module_empty">কোন মডিউল ইনস্টল করা নেই</string>
@@ -46,7 +38,6 @@
<string name="reboot_download">রিবুট ডাউনলোড</string>
<string name="reboot_edl">রিবুট ইডিএল</string>
<string name="about">এবাউট</string>
<string name="require_kernel_version_8">কার্নেলএসইউ সংস্করণ প্রয়োজন ৮+</string>
<string name="module_uninstall_confirm">মডিউল আনইনস্টল নিশ্চিত করুন %s?</string>
<string name="module_uninstall_success">%s আনইনস্টল সফল</string>
<string name="module_uninstall_failed">আনইন্সটল ব্যর্থ: %s</string>

View File

@@ -0,0 +1,67 @@
<resources>
<string name="app_name" translatable="false">KernelSU</string>
<string name="home">خانه</string>
<string name="home_not_installed">نصب نشده است</string>
<string name="home_click_to_install">برای نصب ضربه بزنید</string>
<string name="home_working">به درستی کار می‌کند</string>
<string name="home_working_version">نسخه: %d</string>
<string name="home_superuser_count">برنامه های با دسترسی روت: %d</string>
<string name="home_module_count">ماژول‌ها: %d</string>
<string name="home_unsupported">پشتیبانی نشده</string>
<string name="home_unsupported_reason">کرنل اس یو فقط هسته های gki را پشتیبانی میکند</string>
<string name="home_kernel">هسته</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>
<string name="selinux_status_enforcing">قانونمند</string>
<string name="selinux_status_permissive">آزاد</string>
<string name="selinux_status_unknown">ناشناخته</string>
<string name="superuser">دسترسی روت</string>
<string name="module_failed_to_enable">فعال کردن ماژول ناموفق بود: %s</string>
<string name="module_failed_to_disable">غیرفعال کردن ماژول ناموفق بود: %s</string>
<string name="module_empty">هیچ ماژولی نصب نشده است</string>
<string name="module">ماژول</string>
<string name="uninstall">لغو نصب</string>
<string name="module_install">نصب</string>
<string name="install">نصب</string>
<string name="reboot">راه اندازی دوباره</string>
<string name="settings">تنظیمات</string>
<string name="reboot_userspace">راه اندازی نرم</string>
<string name="reboot_recovery">راه اندازی به ریکاوری </string>
<string name="reboot_bootloader">راه اندازی به بوتلودر</string>
<string name="reboot_download">راه اندازی به حالت دانلود</string>
<string name="reboot_edl">راه اندازی به EDL</string>
<string name="about">درباره</string>
<string name="module_uninstall_confirm">آیا مطمئنید که میخواهید ماژول %s را پاک کنید؟</string>
<string name="module_uninstall_success">%s پاک شد</string>
<string name="module_uninstall_failed">پاک کردن ناموفق بود: %s</string>
<string name="module_version">نسخه</string>
<string name="module_author">سازنده</string>
<string name="module_overlay_fs_not_available">overlayfs موجود نیست. مازول کار نمیکند!!</string>
<string name="refresh">تازه‌سازی</string>
<string name="show_system_apps">نمایش برنامه های سیستمی</string>
<string name="hide_system_apps">مخفی کردن برنامه های سیستمی</string>
<string name="send_log">ارسال وقایع</string>
<string name="safe_mode">حالت امن</string>
<string name="reboot_to_apply">راه‌اندازی مجدد برای تاثیرگذاری</string>
<string name="module_magisk_conflict">مازول به دلیل تعارض با مجیسک غیرفعال شده اند\'s!</string>
<string name="home_learn_kernelsu">یادگیری کرنل اس یو</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید</string>
<string name="home_support_title">از ما حمایت کنید</string>
<string name="home_support_content">KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است.</string>
<string name="about_source_code">
<![CDATA[ View source code at %1$s<br/>Join our %2$s channel ]]>
</string>
<string name="profile">پروفایل برنامه</string>
<string name="profile_default">پیش‌فرض</string>
<string name="profile_template">قالب</string>
<string name="profile_custom">شخصی سازی شده</string>
<string name="profile_name">اسم پروفایل</string>
<string name="profile_namespace">Mount namespace</string>
<string name="profile_namespace_inherited">اثر گرفته</string>
<string name="profile_namespace_global">گلوبال</string>
<string name="profile_namespace_individual">تکی</string>
<string name="profile_umount_modules">جداکردن ماژول ها</string>
</resources>

View File

@@ -1,64 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home">Beranda</string>
<string name="home_not_installed">Tidak terinstall</string>
<string name="home_click_to_install">Klik untuk menginstall</string>
<string name="home_working">Bekerja</string>
<string name="home_working_version">Versi: %d</string>
<string name="home_superuser_count">Superuser: %d</string>
<string name="home_module_count">Module: %d</string>
<string name="home_unsupported">Tidak didukung</string>
<string name="home_unsupported_reason">Saat ini kernelSu hanya mendukung GKI kernel</string>
<string name="home_copied_to_clipboard">Salin ke clipboard</string>
<string name="home_support">Dukungan</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Arch</string>
<string name="home_manager_version">Versi manager</string>
<string name="home_api">API Level</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">Patch keamanan</string>
<string name="home_selinux_status">Status SElinux</string>
<string name="selinux_status_disabled">Cacat</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">Tidak tersedia</string>
<string name="superuser">Superuser</string>
<string name="superuser_failed_to_grant_root">Gagal mengizinkan root untuk %d</string>
<string name="superuser_allow_root_confirm">Ijinkan akses root untuk aplikasi %s?</string>
<string name="module_failed_to_enable">Gagal mengaktifkan module: %s</string>
<string name="module_failed_to_disable">Gagal menonaktifkan module: %s</string>
<string name="module_empty">Tidak ada module terpasang</string>
<string name="module">Module</string>
<string name="uninstall">Hapus</string>
<string name="module_install">Pasang module</string>
<string name="install">Memasang module...</string>
<string name="reboot">Reboot perangkat</string>
<string name="settings">Pengaturan</string>
<string name="reboot_userspace">Soft Reboot</string>
<string name="reboot_recovery">Reboot ke Recovery</string>
<string name="reboot_bootloader">Reboot ke Bootloader</string>
<string name="reboot_download">Reboot ke Download</string>
<string name="reboot_edl">Reboot ke EDL</string>
<string name="about">Tentang</string>
<string name="require_kernel_version_8">Membutuhkan KernelSU Versi 8+</string>
<string name="module_uninstall_confirm">Apakah anda yakin ingin menghapus module ini %s?</string>
<string name="module_uninstall_success">%s terhapus</string>
<string name="module_uninstall_failed">Gagal untuk menghapus: %s</string>
<string name="module_version">Versi</string>
<string name="module_author">Pembuat</string>
<string name="module_overlay_fs_not_available">overlayfs tidak tersedia, module tidak bekerja!</string>
<string name="refresh">Segarkan</string>
<string name="show_system_apps">Tampilkan system apps</string>
<string name="hide_system_apps">Sembunyikan system apps</string>
<string name="send_log">Kirim logs</string>
<string name="safe_mode">Mode aman</string>
<string name="reboot_to_apply">Restart untuk menerapkan</string>
<string name="module_magisk_conflict">Module akan di nonaktifkan karna konflik dengan magisk\'s!</string>
<string name="home_learn_kernelsu">Belajar KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/id_ID/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Cara menginstall KernelSu dan menggunakan Module</string>
<string name="home_support_title">Dukung kami</string>
<string name="home_support_content">KernelSU akan selalu gratis dan open source. Namun Anda dapat menunjukkan kepada kami bahwa Anda peduli dengan memberikan sedikit donasi.</string>
<string name="about_source_code"><![CDATA[Lihat sumber kode di %1$s<br/>Gabung sekarang %2$s channel]]></string>
</resources>
<resources>
<string name="app_name" translatable="false">KernelSU</string>
<string name="home">Beranda</string>
<string name="home_not_installed">Tidak terpasang</string>
<string name="home_click_to_install">Klik untuk memasang</string>
<string name="home_working">Bekerja</string>
<string name="home_working_version">Versi: %d</string>
<string name="home_superuser_count">Superusers: %d</string>
<string name="home_module_count">Modul: %d</string>
<string name="home_unsupported">Tidak didukung</string>
<string name="home_unsupported_reason">KernelSU hanya mendukung kernel GKI saat ini</string>
<string name="home_kernel">Kernel</string>
<string name="home_manager_version">Versi Manager</string>
<string name="home_fingerprint">Sidik jari</string>
<string name="home_selinux_status">status SELinux</string>
<string name="selinux_status_disabled">Dinonaktifkan</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">Tidak dikenal</string>
<string name="superuser">Superuser</string>
<string name="module_failed_to_enable">Gagal mengaktifkan modul: %s</string>
<string name="module_failed_to_disable">Gagal menonaktifkan modul: %s</string>
<string name="module_empty">Tidak ada modul terpasang</string>
<string name="module">Modul</string>
<string name="uninstall">Copot</string>
<string name="module_install">Pasang</string>
<string name="install">Pasang</string>
<string name="reboot">Reboot</string>
<string name="settings">Pengaturan</string>
<string name="reboot_userspace">Reboot Lembut</string>
<string name="reboot_recovery">Reboot ke Recovery</string>
<string name="reboot_bootloader">Reboot ke Bootloader</string>
<string name="reboot_download">Reboot ke Download</string>
<string name="reboot_edl">Reboot ke EDL</string>
<string name="about">Tentang</string>
<string name="module_uninstall_confirm">Apakah Anda yakin ingin mencopot modul %s?</string>
<string name="module_uninstall_success">%s Tercopot</string>
<string name="module_uninstall_failed">Gagal untuk mencopot: %s</string>
<string name="module_version">Versi</string>
<string name="module_author">Pembuat</string>
<string name="module_overlay_fs_not_available">overlayfs tidak tersedia, modul tidak dapat bekerja!</string>
<string name="refresh">Segarkan</string>
<string name="show_system_apps">Tampilkan apl sistem</string>
<string name="hide_system_apps">Sembunyikan apl sistem</string>
<string name="send_log">Kirim Log</string>
<string name="safe_mode">Mode aman</string>
<string name="reboot_to_apply">Reboot untuk menerapkan</string>
<string name="module_magisk_conflict">Modul dinonaktifkan karena bertentangan dengan Magisk!</string>
<string name="home_learn_kernelsu">Pelajari KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Pelajari cara memasang KernelSU dan menggunakan modul</string>
<string name="home_support_title">Dukung Kami</string>
<string name="home_support_content">KernelSU gratis dan bersumber terbuka, dan akan selalu seperti itu. Bagaimanapun juga Anda dapat menunjukan kepedulian Anda kepada kami dengan mengirimkan sedikit donasi.</string>
<string name="about_source_code"><![CDATA[Lihat sumber code di %1$s<br/>Gabung kanal %2$s kami]]></string>
<string name="profile">Profil Apl</string>
<string name="profile_default">Bawaan</string>
<string name="profile_template">Templat</string>
<string name="profile_custom">Khusus</string>
<string name="profile_name">Nama profil</string>
<string name="profile_namespace">Ikat ruang-nama</string>
<string name="profile_namespace_inherited">Diwariskan</string>
<string name="profile_namespace_global">Universal</string>
<string name="profile_namespace_individual">Personal</string>
<string name="profile_umount_modules">Lepas modul</string>
</resources>

View File

@@ -8,16 +8,10 @@
<string name="home_module_count">Moduli: %d</string>
<string name="home_unsupported">Non supportato</string>
<string name="home_unsupported_reason">KernelSU ora supporta solo i kernel GKI</string>
<string name="home_copied_to_clipboard">Copiato negli appunti</string>
<string name="home_support">Supporto</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Architettura</string>
<string name="home_manager_version">Versione del manager</string>
<string name="home_api">Livello API</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">Patch di sicurezza</string>
<string name="home_selinux_status">Stato SELinux</string>
<string name="selinux_status_disabled">Disabilitato</string>
@@ -25,8 +19,6 @@
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">Sconosciuto</string>
<string name="superuser">Accesso root</string>
<string name="superuser_failed_to_grant_root">Impossibile concedere l\'accesso root per %d</string>
<string name="superuser_allow_root_confirm">Sei sicuro di concedere l\'accesso root a %s?</string>
<string name="module_failed_to_enable">Impossibile abilitare il modulo: %s</string>
<string name="module_failed_to_disable">Impossibile disabilitare il modulo: %s</string>
<string name="module_empty">Nessun modulo installato</string>
@@ -43,7 +35,6 @@
<string name="reboot_download">Riavvia in modalità Download</string>
<string name="reboot_edl">Riavvia in modalità EDL</string>
<string name="about">Informazioni</string>
<string name="require_kernel_version_8">Richiede KernelSU versione 8+</string>
<string name="module_uninstall_confirm">Sei sicuro di voler disinstallare il modulo %s?</string>
<string name="module_uninstall_success">%s disinstallato</string>
<string name="module_uninstall_failed">Impossibile disinstallare: %s</string>

View File

@@ -1,55 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home">ホーム</string>
<string name="home_not_installed">未インストール</string>
<string name="home_click_to_install">タップでインストール</string>
<string name="home_working">動作中</string>
<string name="home_working_version">バージョン: %d</string>
<string name="home_unsupported">非対応</string>
<string name="home_unsupported_reason">KernelSUは現在、GKIカーネルのみサポートをしています</string>
<string name="home_copied_to_clipboard">クリップボードにコピーしました</string>
<string name="home_support">対応</string>
<string name="home_kernel">カーネル</string>
<string name="home_arch">アーキテクチャ</string>
<string name="home_manager_version">バージョン</string>
<string name="home_api">APIレベル</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">セキュリティパッチ</string>
<string name="home_selinux_status">SELinuxの状態</string>
<string name="selinux_status_disabled">無効</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">不明</string>
<string name="superuser">スーパーユーザー</string>
<string name="superuser_failed_to_grant_root">%dの権限の付与に失敗しました</string>
<string name="module_failed_to_enable">モジュールの有効化に失敗: %s</string>
<string name="module_failed_to_disable">モジュールの無効化に失敗: %s</string>
<string name="module_empty">モジュールはインストールされていません</string>
<string name="module">モジュール</string>
<string name="uninstall">アンインストール</string>
<string name="module_install">インストール</string>
<string name="install">インストール</string>
<string name="reboot">再起動</string>
<string name="settings">設定</string>
<string name="reboot_userspace">ソフトリブート</string>
<string name="reboot_recovery">リカバリーで再起動</string>
<string name="reboot_bootloader">Bootloaderで再起動</string>
<string name="reboot_download">ダウンロードモードで再起動</string>
<string name="reboot_edl">EDLで再起動</string>
<string name="about">アプリについて</string>
<string name="require_kernel_version_8">KernelSU バージョン8以降が必要です</string>
<string name="module_uninstall_confirm">モジュール %s をアンインストールしますか?</string>
<string name="module_uninstall_success">%sをアンインストールしました</string>
<string name="module_uninstall_failed">アンインストールに失敗: %s</string>
<string name="module_version">バージョン</string>
<string name="module_author">作者</string>
<string name="module_overlay_fs_not_available">OverlayFSが有効でないためモジュールは動作しません</string>
<string name="refresh">更新</string>
<string name="show_system_apps">システムアプリを表示</string>
<string name="hide_system_apps">システムアプリを非表示</string>
<string name="send_log">ログを送信</string>
<string name="safe_mode">セーフモード</string>
<string name="reboot_to_apply">再起動をして有効化する</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_not_installed">未インストール</string>
<string name="home_click_to_install">タップでインストール</string>
<string name="home_working">動作中</string>
<string name="home_working_version">バージョン: %d</string>
<string name="home_superuser_count">スーパーユーザー: %d</string>
<string name="home_module_count">モジュール: %d</string>
<string name="home_unsupported">非対応</string>
<string name="home_unsupported_reason">KernelSU は現在、GKI カーネルにのみ対応しています</string>
<string name="home_kernel">カーネル</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>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">不明</string>
<string name="superuser">スーパーユーザー</string>
<string name="module_failed_to_enable">モジュールの有効化に失敗: %s</string>
<string name="module_failed_to_disable">モジュールの無効化に失敗: %s</string>
<string name="module_empty">モジュールをインストールしていません</string>
<string name="module">モジュール</string>
<string name="uninstall">アンインストール</string>
<string name="module_install">インストール</string>
<string name="install">インストール</string>
<string name="reboot">再起動</string>
<string name="settings">設定</string>
<string name="reboot_userspace">ソフトリブート</string>
<string name="reboot_recovery">リカバリーへ再起動</string>
<string name="reboot_bootloader">Bootloader へ再起動</string>
<string name="reboot_download">ダウンロードモードへ再起動</string>
<string name="reboot_edl">EDLへ再起動</string>
<string name="about">アプリについて</string>
<string name="module_uninstall_confirm">モジュール %s をアンインストールしますか?</string>
<string name="module_uninstall_success">%sをアンインストールしました</string>
<string name="module_uninstall_failed">アンインストールに失敗: %s</string>
<string name="module_version">バージョン</string>
<string name="module_author">制作者</string>
<string name="module_overlay_fs_not_available">OverlayFS が有効でないためモジュールは動作しません</string>
<string name="refresh">更新</string>
<string name="show_system_apps">システムアプリを表示</string>
<string name="hide_system_apps">システムアプリを非表示</string>
<string name="send_log">ログを送信</string>
<string name="safe_mode">セーフモード</string>
<string name="reboot_to_apply">再起動すると有効化されます</string>
<string name="module_magisk_conflict">Magisk と競合しているためモジュールは無効になっています!</string>
<string name="home_learn_kernelsu">KernelSU の詳細</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/ja_JP/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">KernelSU のインストール方法やモジュールの使い方はこちら</string>
<string name="home_support_title">支援する</string>
<string name="home_support_content">KernelSU は無料かつオープンソースです。寄付していただくことで開発を支援できます。</string>
<string name="about_source_code"><![CDATA[%1$s でソースコードを表示<br/>%2$s チャンネルに参加]]></string>
<string name="profile">アプリのプロファイル</string>
<string name="profile_default">デフォルト</string>
<string name="profile_template">テンプレート</string>
<string name="profile_custom">カスタム</string>
<string name="profile_name">プロファイル名</string>
<string name="profile_namespace">マウント名前空間</string>
<string name="profile_namespace_inherited">継承</string>
<string name="profile_namespace_global">グローバル</string>
<string name="profile_namespace_individual">分離</string>
<string name="profile_umount_modules">モジュールのアンマウント</string>
</resources>

View File

@@ -8,15 +8,10 @@
<string name="home_module_count">설치된 모듈: %d개</string>
<string name="home_unsupported">지원되지 않음</string>
<string name="home_unsupported_reason">KernelSU는 현재 GKI 커널만 지원합니다</string>
<string name="home_copied_to_clipboard">클립보드로 복사됨</string>
<string name="home_support">지원</string>
<string name="home_kernel">커널</string>
<string name="home_arch">아키텍처</string>
<string name="home_manager_version">매니저 버전</string>
<string name="home_api">API 레벨</string>
<string name="home_fingerprint">빌드 정보</string>
<string name="home_securitypatch">보안 패치 버전</string>
<string name="home_selinux_status">SELinux 상태</string>
<string name="selinux_status_disabled">비활성화됨</string>
@@ -24,8 +19,6 @@
<string name="selinux_status_permissive">허용</string>
<string name="selinux_status_unknown">알 수 없음</string>
<string name="superuser">슈퍼유저</string>
<string name="superuser_failed_to_grant_root">%d에 루트 권한 부여 실패</string>
<string name="superuser_allow_root_confirm">%s에 루트 권한을 부여할까요?</string>
<string name="module_failed_to_enable">모듈 활성화 실패: %s</string>
<string name="module_failed_to_disable">모듈 비활성화 실패: %s</string>
<string name="module_empty">설치된 모듈 없음</string>
@@ -42,7 +35,6 @@
<string name="reboot_download">다운로드 모드로 다시 시작</string>
<string name="reboot_edl">EDL 모드로 다시 시작</string>
<string name="about">정보</string>
<string name="require_kernel_version_8">버전 8 이상의 KernelSU가 필요합니다</string>
<string name="module_uninstall_confirm">%s 모듈을 삭제할까요?</string>
<string name="module_uninstall_success">%s 모듈 삭제됨</string>
<string name="module_uninstall_failed">모듈 삭제 실패: %s</string>

View File

@@ -10,16 +10,10 @@
<string name="home_module_count">Modules: %d</string>
<string name="home_unsupported">Niet ondersteund</string>
<string name="home_unsupported_reason">KernelSU ondersteunt alleen GKI kernels</string>
<string name="home_copied_to_clipboard">Gekopiëerd naar clipboard</string>
<string name="home_support">Ondersteuning</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Arch</string>
<string name="home_manager_version">Manager Versie</string>
<string name="home_api">API Niveau</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">Veiligheidspatch</string>
<string name="home_selinux_status">SELinux status</string>
<string name="selinux_status_disabled">Uitgeschakeld</string>
@@ -27,8 +21,6 @@
<string name="selinux_status_permissive">Permissief</string>
<string name="selinux_status_unknown">Niet gekend</string>
<string name="superuser">Superuser</string>
<string name="superuser_failed_to_grant_root">Mislukt om root te geven voor %d</string>
<string name="superuser_allow_root_confirm">Zeker dat je root wil geven aan %s?</string>
<string name="module_failed_to_enable">Mislukt om module in te schakelen: %s</string>
<string name="module_failed_to_disable">Mislukt om module uit te schakelen: %s</string>
<string name="module_empty">Geen module geïnstalleerd</string>
@@ -45,7 +37,6 @@
<string name="reboot_download">Herstart om te downloaden</string>
<string name="reboot_edl">Herstart naar EDL</string>
<string name="about">Over</string>
<string name="require_kernel_version_8">Vereist KernelSU versie 8+</string>
<string name="module_uninstall_confirm">Zeker van het verwijderen van module %s?</string>
<string name="module_uninstall_success">%s verwijderd</string>
<string name="module_uninstall_failed">Mislukt om te verwijderen: %s</string>
@@ -65,4 +56,19 @@
<string name="home_support_title">Ondersteun ons</string>
<string name="home_support_content">KernelSU is, en zal altijd, vrij en open source zijn. Je kan altijd je appreciatie tonen met een donatie.</string>
<string name="about_source_code"><![CDATA[Bekijk source code op %1$s<br/>Vervoeg ons %2$s kanaal]]></string>
<string name="profile" translatable="false">App profiel</string>
<string name="profile_default">Standaard</string>
<string name="profile_template">Sjabloon</string>
<string name="profile_custom">Aangepast</string>
<string name="profile_name">Profiel naam</string>
<string name="profile_namespace">Koppel naamruimte</string>
<string name="profile_namespace_inherited">Overgenomen</string>
<string name="profile_namespace_global">Globaal</string>
<string name="profile_namespace_individual">Individuëel</string>
<string name="profile_umount_modules">Ontkoppel modules</string>
<string name="failed_to_update_app_profile">Mislukt om App Profiel te updaten voor %s</string>
<string name="require_kernel_version">De bestaande kernel versie %d is te laag voor de manager om goed te werken. Upgrade best tot versie %d of hoger!</string>
<string name="settings_umount_modules_default">Ontkoppel standaard de modules</string>
<string name="settings_umount_modules_default_summary">De globale standaard waarde voor \"Ontkoppel modules\" in App Profielen. Indien geactiveerd, zal het alle module wijzigingen tot het systeeem verwijderen voor applicaties die geen Profiel ingesteld hebben.</string>
<string name="profile_umount_modules_summary">Deze optie ingeschakeld zal KernelSU toelaten om alle gewijzigde bestanden door de modules voor deze applicatie te herstellen.</string>
</resources>

View File

@@ -0,0 +1,74 @@
<resources>
<string name="app_name" translatable="false">KernelSU</string>
<string name="home">Início</string>
<string name="home_not_installed">Não instalado</string>
<string name="home_click_to_install">Clique para instalar</string>
<string name="home_working">Trabalhando</string>
<string name="home_working_version">Versão: %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">Por enquanto, KernelSU suporta apenas kernels GKI</string>
<string name="home_kernel">Kernel</string>
<string name="home_manager_version">Versão do gerenciador</string>
<string name="home_fingerprint">Impressão digital</string>
<string name="home_selinux_status">Status do SELinux</string>
<string name="selinux_status_disabled">Desabilitado</string>
<string name="selinux_status_enforcing">Impondo</string>
<string name="selinux_status_permissive">Permissivo</string>
<string name="selinux_status_unknown">Desconhecido</string>
<string name="superuser">Superusuário</string>
<string name="module_failed_to_enable">Falha ao ativar o módulo: %s</string>
<string name="module_failed_to_disable">Falha ao desativar o módulo: %s</string>
<string name="module_empty">Nenhum módulo instalado</string>
<string name="module">Módulo</string>
<string name="uninstall">Desinstalar</string>
<string name="module_install">Instalar</string>
<string name="install">Instalar</string>
<string name="reboot">Reiniciar</string>
<string name="settings">Configurações</string>
<string name="reboot_userspace">Reinicialização suave</string>
<string name="reboot_recovery">Reiniciar para recuperação</string>
<string name="reboot_bootloader">Reinicializar para bootloader</string>
<string name="reboot_download">Reinicializar para download</string>
<string name="reboot_edl">Reinicializar para EDL</string>
<string name="about">Sobre</string>
<string name="module_uninstall_confirm">Tem certeza de que deseja desinstalar o módulo %s?</string>
<string name="module_uninstall_success">%s desinstalado</string>
<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 funcioná!</string>
<string name="refresh">Atualizar</string>
<string name="show_system_apps">Mostrar aplicativos do sistema</string>
<string name="hide_system_apps">Ocultar aplicativos do sistema</string>
<string name="send_log">Enviar log</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 o Magisk\'s!</string>
<string name="home_learn_kernelsu">Leia mais sobre KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Saiba como instalar o KernelSU e usar os módulos</string>
<string name="home_support_title">Apoie-nos</string>
<string name="home_support_content">O KernelSU é, e sempre será, gratuito e de código aberto. No entanto, você pode nos mostrar que se importa fazendo uma doação.</string>
<string name="about_source_code"><![CDATA[Veja o código-fonte em %1$s<br/>Junte-se ao nosso %2$s canal]]></string>
<string name="profile" translatable="false">Perfil do aplicativo</string>
<string name="profile_default">Padrão</string>
<string name="profile_template">Modelo</string>
<string name="profile_custom">Personalizado</string>
<string name="profile_name">Nome do perfil</string>
<string name="profile_namespace">Montar namespace</string>
<string name="profile_namespace_inherited">incluído</string>
<string name="profile_namespace_global">Global</string>
<string name="profile_namespace_individual">Individual</string>
<string name="profile_umount_modules">Módulos não montados</string>
<string name="failed_to_update_app_profile">Falha ao atualizar o perfil do aplicativo para %s</string>
<string name="require_kernel_version">A versão atual do kernel %d é muito baixo para o gerenciador funcionar corretamente. Atualize para a versão %d ou superior!</string>
<string name="settings_umount_modules_default">Não montar módulos por padrão</string>
<string name="settings_umount_modules_default_summary">O valor padrão global para \"Módulos não montados\" em perfis de aplicativos. Se ativado, removerá todas as modificações do módulo do sistema para aplicativos 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 aplicativo.</string>
</resources>

View File

@@ -5,18 +5,14 @@
<string name="home_click_to_install">Click pentru a instala</string>
<string name="home_working">Funcționează</string>
<string name="home_working_version">Versiune: %d</string>
<string name="home_superuser_count">Superuseri: %d</string>
<string name="home_module_count">Module: %d</string>
<string name="home_unsupported">Necompatibil</string>
<string name="home_unsupported_reason">KernelSU suportă doar nuclee GKI acum</string>
<string name="home_copied_to_clipboard">Copiat în clipboard</string>
<string name="home_support">Asistență</string>
<string name="home_kernel">Nucleu</string>
<string name="home_arch">Arhitectură</string>
<string name="home_manager_version">Versiune Manager</string>
<string name="home_api">Nivel API</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Amprentă</string>
<string name="home_securitypatch">Corecție de securitate</string>
<string name="home_selinux_status">Stare SELinux</string>
<string name="selinux_status_disabled">Dezactivat</string>
@@ -24,13 +20,11 @@
<string name="selinux_status_permissive">Permisiv</string>
<string name="selinux_status_unknown">Necunoscut</string>
<string name="superuser">Superutilizator</string>
<string name="superuser_failed_to_grant_root">Nu s-a putut acorda acces root pentru %d</string>
<string name="superuser_allow_root_confirm">Sigur oferi acces root pentru %s?</string>
<string name="module_failed_to_enable">Activarea modulului %s a eșuat</string>
<string name="module_failed_to_disable">Dezactivarea modulului %s a eșuat</string>
<string name="module_empty">Niciun modul instalat</string>
<string name="module">Module</string>
<string name="module">Modul</string>
<string name="uninstall">Dezinstalează</string>
<string name="module_install">Instalează</string>
<string name="install">Instalează</string>
@@ -42,7 +36,6 @@
<string name="reboot_download">Repornire în Download</string>
<string name="reboot_edl">Repornire în EDL</string>
<string name="about">Despre</string>
<string name="require_kernel_version_8">Necesită KernelSU versiunea 8+</string>
<string name="module_uninstall_confirm">Sigur dorești să dezinstalezi modulul %s?</string>
<string name="module_uninstall_success">%s dezinstalat</string>
<string name="module_uninstall_failed">Dezinstalare eșuată: %s</string>
@@ -62,4 +55,18 @@
<string name="home_support_title">Suport</string>
<string name="home_support_content">KernelSU este, și va fi întotdeauna, gratuit și cu codul sursă deschis. Cu toate acestea, ne poți arăta că îți pasă făcând o donație.</string>
<string name="about_source_code"><![CDATA[Vezi codul sursă la %1$s<br/>Alătură-te canalului nostru %2$s]]></string>
<string name="profile_default">Implicit</string>
<string name="profile_template">Șablon</string>
<string name="profile_custom">Personalizat</string>
<string name="profile_name">Nume profil</string>
<string name="profile_namespace">Montare spațiu de nume</string>
<string name="profile_namespace_inherited">Moștenit</string>
<string name="profile_namespace_global">Global</string>
<string name="profile_namespace_individual">Individual</string>
<string name="profile_umount_modules">Module u-montate</string>
<string name="failed_to_update_app_profile">Nu s-a putut actualiza profilul aplicației pentru %s</string>
<string name="require_kernel_version">Versiunea actuală a nucleului %d este prea mică pentru ca managerul să funcționeze corect. Actualizează la versiunea %d sau o versiune superioară!</string>
<string name="settings_umount_modules_default">U-montează modulele în mod implicit</string>
<string name="settings_umount_modules_default_summary">Valoarea implicită globală pentru „Module u-montate” în Profilurile aplicațiilor. Dacă este activat, va elimina toate modificările modulelor aduse sistemului pentru aplicațiile care nu au un profil setat.</string>
<string name="profile_umount_modules_summary">Activarea acestei opțiuni va permite KernelSU să restaureze orice fișiere modificate de către modulele pentru această aplicație.</string>
</resources>

View File

@@ -8,16 +8,10 @@
<string name="home_module_count">Модули: %d</string>
<string name="home_unsupported">Не поддерживается</string>
<string name="home_unsupported_reason">KernelSU поддерживает только GKI ядра</string>
<string name="home_copied_to_clipboard">Скопировано в буфер обмена</string>
<string name="home_support">Поддержка</string>
<string name="home_kernel">Ядро</string>
<string name="home_arch">Архитектура</string>
<string name="home_manager_version">Версия</string>
<string name="home_api">Уровень API</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Подпись</string>
<string name="home_securitypatch">Патч Безопасности</string>
<string name="home_selinux_status">Состояние SELinux</string>
<string name="selinux_status_disabled">Выключен</string>
@@ -25,8 +19,6 @@
<string name="selinux_status_permissive">Разрешающий</string>
<string name="selinux_status_unknown">Неизвестно</string>
<string name="superuser">Superuser</string>
<string name="superuser_failed_to_grant_root">Не удалось предоставить root права для %d</string>
<string name="superuser_allow_root_confirm">Вы уверены, что хотите предоставить root права для %s?</string>
<string name="module_failed_to_enable">Не удалось включить модуль: %s</string>
<string name="module_failed_to_disable">Не удалось отключить модуль: %s</string>
<string name="module_empty">Нет установленных модулей</string>
@@ -43,7 +35,6 @@
<string name="reboot_download">Reboot to Download</string>
<string name="reboot_edl">Reboot to EDL</string>
<string name="about">О KernelSU</string>
<string name="require_kernel_version_8">Требуется KernelSU версии 8 и выше</string>
<string name="module_uninstall_confirm">Вы уверены, что хотите удалить модуль %s?</string>
<string name="module_uninstall_success">%s удален</string>
<string name="module_uninstall_failed">Не удалось удалить: %s</string>

View File

@@ -8,25 +8,17 @@
<string name="home_module_count">Modüller: %d</string>
<string name="home_unsupported">Desteklenmiyor</string>
<string name="home_unsupported_reason">KernelSU artık yalnızca GKI çekirdeklerini destekliyor</string>
<string name="home_copied_to_clipboard">Panoya kopyalandı</string>
<string name="home_support">Destek</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Arch</string>
<string name="home_manager_version">Yönetici Sürümü</string>
<string name="home_api">API Seviyesi</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Parmak izi</string>
<string name="home_securitypatch">Güvenlik Yaması</string>
<string name="home_fingerprint">Parmak İzi</string>
<string name="home_selinux_status">SELinux durumu</string>
<string name="home_selinux_status">SELinux Durumu</string>
<string name="selinux_status_disabled">Devre dışı</string>
<string name="selinux_status_enforcing">Zorunlu</string>
<string name="selinux_status_permissive">Serbest</string>
<string name="selinux_status_unknown">Bilinmiyor</string>
<string name="superuser">Süper kullanıcı</string>
<string name="superuser_failed_to_grant_root">%d için root erişimi verilemedi</string>
<string name="superuser_allow_root_confirm">%s için root erişimi vereceğinizden emin misiniz?</string>
<string name="module_failed_to_enable">Modül etkinleştirilemedi: %s</string>
<string name="module_failed_to_disable">Modül devre dışı bırakılamadı: %s</string>
<string name="module_empty">Yüklü modül yok</string>
@@ -43,7 +35,6 @@
<string name="reboot_download">İndirme modunda Başlat</string>
<string name="reboot_edl">EDL modunda Başlat</string>
<string name="about">Hakkında</string>
<string name="require_kernel_version_8">KernelSU sürüm 8+ gerektir</string>
<string name="module_uninstall_confirm">%s modülünü kaldırmak istediğinizden emin misiniz?</string>
<string name="module_uninstall_success">%s kaldırıldı</string>
<string name="module_uninstall_failed">Kaldırılamadı: %s</string>
@@ -63,4 +54,14 @@
<string name="home_support_title">Bizi destekle</string>
<string name="home_support_content">KernelSU ücretsiz ve açık kaynaktır ve her zaman öyle kalacaktır. Ancak bağış yaparak bize değer verdiğinizi gösterebilirsiniz.</string>
<string name="about_source_code"><![CDATA[%1$s kaynak kodunu görüntüle<br/>%2$s kanalımıza katılın]]></string>
<string name="profile">Uygulama profili</string>
<string name="profile_default">Varsayılan</string>
<string name="profile_template">Örnek</string>
<string name="profile_custom">Özel</string>
<string name="profile_name">Profil adı</string>
<string name="profile_namespace">Ad alanını bağla</string>
<string name="profile_namespace_inherited">Kalıtsal</string>
<string name="profile_namespace_global">Küresel</string>
<string name="profile_namespace_individual">Bireysel</string>
<string name="profile_umount_modules">Modüllerin bağlantısını kes</string>
</resources>

View File

@@ -1,4 +1,6 @@
<resources>
<string name="app_name" translatable="false">KernelSU</string>
<string name="home">Головна</string>
<string name="home_not_installed">Не встановлено</string>
<string name="home_click_to_install">Натисніть щоб встановити</string>
@@ -8,16 +10,10 @@
<string name="home_module_count">Модулі: %d</string>
<string name="home_unsupported">Не підтримується</string>
<string name="home_unsupported_reason">KernelSU підтримує лише ядра GKI</string>
<string name="home_copied_to_clipboard">Скопійовано в буфер обміну</string>
<string name="home_support">Підтримка</string>
<string name="home_kernel">Ядро</string>
<string name="home_arch">Архітектура</string>
<string name="home_manager_version">Версія менеджера</string>
<string name="home_api">Рівень API</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Відбиток</string>
<string name="home_securitypatch">Патч безпеки</string>
<string name="home_selinux_status">Статус SELinux</string>
<string name="selinux_status_disabled">Вимкнено</string>
@@ -25,8 +21,6 @@
<string name="selinux_status_permissive">Дозвільний</string>
<string name="selinux_status_unknown">Невідомо</string>
<string name="superuser">Суперкористувачі</string>
<string name="superuser_failed_to_grant_root">Не вдалося надати root-доступ для %d</string>
<string name="superuser_allow_root_confirm">Ви впевнені, що хочете надати root-доступ для %s?</string>
<string name="module_failed_to_enable">Не вдалося ввімкнути модуль: %s</string>
<string name="module_failed_to_disable">Не вдалося вимкнути модуль: %s</string>
<string name="module_empty">Немає встановлених модулів</string>
@@ -43,7 +37,6 @@
<string name="reboot_download">Перезавантажити до Download</string>
<string name="reboot_edl">Перезавантажити до EDL</string>
<string name="about">Про додаток</string>
<string name="require_kernel_version_8">Потрібна версія KernelSU 8+</string>
<string name="module_uninstall_confirm">Ви впевнені, що хочете видалити модуль %s?</string>
<string name="module_uninstall_success">%s видалено</string>
<string name="module_uninstall_failed">Не вдалося видалити: %s</string>
@@ -60,7 +53,22 @@
<string name="home_learn_kernelsu">Дізнайтеся про KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Дізнайтеся, як інсталювати KernelSU і використовувати модулі</string>
<string name="home_support_title">Підтримайте нас</string>
<string name="home_support_content">KernelSU є і завжди буде безкоштовним і з відкритим кодом. Однак Ви можете показати нам, що Вам не байдуже, зробивши пожертву.</string>
<string name="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">Профіль додатка</string>
<string name="profile_default">Типовий</string>
<string name="profile_template">Шаблон</string>
<string name="profile_custom">Власний</string>
<string name="profile_name">Назва профілю</string>
<string name="profile_namespace">Монтування простору імен</string>
<string name="profile_namespace_inherited">Наслідуваний</string>
<string name="profile_namespace_global">Глобальний</string>
<string name="profile_namespace_individual">Індивідуальний</string>
<string name="profile_umount_modules">Розмонтувати модулі</string>
<string name="failed_to_update_app_profile">Не вдалося оновити профіль додатка для %s</string>
<string name="require_kernel_version">Поточна версія ядра %d занизька для належної роботи менджера. Будь ласка, оновіть до версії %d або вище!</string>
<string name="settings_umount_modules_default">Розмонтувати модулі за замовчуванням</string>
<string name="settings_umount_modules_default_summary">Загальне значення за замовчуванням для \"Розмонтувати модулі\" у профілях додатків. Якщо ввімкнено, буде видалено всі модифікації модулів у системі для додатків, які не мають встановленого профілю.</string>
<string name="profile_umount_modules_summary">Увімкнення даної опції дозволить KernelSU відновити для цього додатка будь-які файли, змінені модулями.</string>
</resources>

View File

@@ -4,7 +4,6 @@
<string name="home_support_title">Hỗ trợ chúng tôi</string>
<string name="home_support_content">KernelSU sẽ luôn luôn miễn phi và mã nguồn mở. Tuy nhiên, bạn có thể cho chúng tôi thấy rằng bạn quan tâm bằng cách gửi một khoản đóng góp nhỏ.</string>
<string name="about_source_code"><![CDATA[Xem mã nguồn tại %1$s<br/>Tham gia kênh %2$s của chúng tôi]]></string>
<string name="superuser_allow_root_confirm">Bạn có chắc chắn muốn cấp quyền truy cập root cho %s?</string>
<string name="module_magisk_conflict">"Các mô-đun bị vô hiệu hóa vì nó xung đột với Magisk!"</string>
<string name="module_uninstall_confirm">Bạn có chắc chắn muốn gỡ cài đặt mô-đun %s?</string>
<string name="send_log">Gửi nhật ký</string>
@@ -15,22 +14,15 @@
<string name="home_working_version">Phiên bản: %d</string>
<string name="home_unsupported">Không hỗ trợ</string>
<string name="home_unsupported_reason">KernelSU hiện tại chỉ hỗ trợ kernel GKI</string>
<string name="home_copied_to_clipboard">Sao chép vào clipboard</string>
<string name="home_support">Ủng hộ</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Kiến trúc</string>
<string name="home_manager_version">Phiên bản</string>
<string name="home_api">Cấp độ API</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">Bản vá bảo mật</string>
<string name="home_selinux_status">Trạng thái SELinux</string>
<string name="selinux_status_disabled">Vô hiệu hóa</string>
<string name="selinux_status_enforcing">Thực thi</string>
<string name="selinux_status_permissive">Cho phép</string>
<string name="selinux_status_unknown">Không rõ</string>
<string name="superuser">Superuser</string>
<string name="superuser_failed_to_grant_root">Không thể cấp quyền root cho %d</string>
<string name="module_failed_to_enable">Không thể kích hoạt mô-đun: %s</string>
<string name="module_failed_to_disable">Không thể vô hiệu hóa mô-đun: %s</string>
<string name="module_empty">Chưa có mô-đun nào được cài đặt</string>
@@ -46,7 +38,6 @@
<string name="reboot_download">Khởi động lại vào Download Mode</string>
<string name="reboot_edl">Khởi động vào EDL</string>
<string name="about">Thông tin</string>
<string name="require_kernel_version_8">Yêu cầu KernelSU phiên bản 8+</string>
<string name="module_uninstall_success">%s đã được gỡ cài đặt</string>
<string name="module_uninstall_failed">Lỗi khi gỡ cài đặt: %s</string>
<string name="module_version">Phiên bản</string>

View File

@@ -8,23 +8,15 @@
<string name="home_superuser_count">超级用户数:%d</string>
<string name="home_unsupported">不支持</string>
<string name="home_unsupported_reason">KernelSU 现在只支持 GKI 内核</string>
<string name="home_copied_to_clipboard">已复制到剪贴板</string>
<string name="home_support">支持</string>
<string name="home_kernel">内核版本</string>
<string name="home_arch">设备架构</string>
<string name="home_manager_version">管理器版本</string>
<string name="home_api">API 版本</string>
<string name="home_abi">ABI 支持</string>
<string name="home_fingerprint">系统指纹</string>
<string name="home_securitypatch">安全补丁</string>
<string name="home_selinux_status">SELinux 状态</string>
<string name="selinux_status_disabled">被禁用</string>
<string name="selinux_status_enforcing">强制执行</string>
<string name="selinux_status_permissive">宽容模式</string>
<string name="selinux_status_unknown">未知</string>
<string name="superuser">超级用户</string>
<string name="superuser_failed_to_grant_root">无法为 %d 授予 Root</string>
<string name="superuser_allow_root_confirm">确定要授予 %s ROOT 权限吗?</string>
<string name="module_failed_to_enable">无法启用模块: %s</string>
<string name="module_failed_to_disable">无法禁用模块: %s</string>
<string name="module_empty">没有安装模块</string>
@@ -40,7 +32,6 @@
<string name="reboot_download">重启到 Download</string>
<string name="reboot_edl">重启到 EDL</string>
<string name="about">关于</string>
<string name="require_kernel_version_8">需要 KernelSU 版本 8+</string>
<string name="module_uninstall_confirm">确定要卸载模块 %s 吗?</string>
<string name="module_uninstall_success">%s 已卸载</string>
<string name="module_uninstall_failed">卸载失败: %s</string>
@@ -61,4 +52,10 @@
<string name="home_support_title">支持开发</string>
<string name="home_support_content">KernelSU 将保持免费和开源,向开发者捐赠以表示支持。</string>
<string name="about_source_code"><![CDATA[在 %1$s 查看源码<br/>加入我们的 %2$s 频道<br/>加入我们的 <b><a href="https://pd.qq.com/s/8lipl1brp">QQ 频道</a></b>]]></string>
<string name="profile_umount_modules">卸载模块</string>
<string name="failed_to_update_app_profile">为 %s 更新 App Profile 失败</string>
<string name="require_kernel_version">当前内核版本 %d 过低,管理器无法正常工作,请升级内核版本至 %d 或以上!</string>
<string name="settings_umount_modules_default">默认卸载模块</string>
<string name="settings_umount_modules_default_summary">App Profile 中\"卸载模块\"的全局默认值,如果启用,将会为没有设置 Profile 的应用移除所有模块针对系统的修改</string>
<string name="profile_umount_modules_summary">启用后将允许 KernelSU 为本应用还原被模块修改过的文件</string>
</resources>

View File

@@ -9,16 +9,10 @@
<string name="home_module_count">模組:%d 個</string>
<string name="home_unsupported">不支援</string>
<string name="home_unsupported_reason">KernelSU 現在僅支援 GKI 核心</string>
<string name="home_copied_to_clipboard">已複製到剪貼簿</string>
<string name="home_support">支援</string>
<string name="home_kernel">核心</string>
<string name="home_arch">架構</string>
<string name="home_manager_version">管理員版本</string>
<string name="home_api">API 層級</string>
<string name="home_abi">ABI 支援</string>
<string name="home_fingerprint">指紋</string>
<string name="home_securitypatch">安全性修補程式</string>
<string name="home_selinux_status">SELinux 狀態</string>
<string name="selinux_status_disabled">已停用</string>
@@ -26,8 +20,6 @@
<string name="selinux_status_permissive">寬鬆</string>
<string name="selinux_status_unknown">未知</string>
<string name="superuser">超級使用者</string>
<string name="superuser_failed_to_grant_root">無法為「%d」授予 Root 存取權</string>
<string name="superuser_allow_root_confirm">您確定要授予「%s」Root 存取權嗎?</string>
<string name="module_failed_to_enable">無法啟用模組:%s</string>
<string name="module_failed_to_disable">無法停用模組:%s</string>
<string name="module_empty">尚未安裝模組</string>
@@ -44,7 +36,6 @@
<string name="reboot_download">重新啟動至 Download</string>
<string name="reboot_edl">重新啟動至 EDL</string>
<string name="about">關於</string>
<string name="require_kernel_version_8">需要 KernelSU 8+ 版本</string>
<string name="module_uninstall_confirm">您確定要解除安裝模組「%s」嗎</string>
<string name="module_uninstall_success">「%s」已解除安裝</string>
<string name="module_uninstall_failed">無法解除安裝:%s</string>

View File

@@ -4,30 +4,21 @@
<string name="home_not_installed">未安裝</string>
<string name="home_click_to_install">按一下以安裝</string>
<string name="home_working">正在處理</string>
<string name="home_working_version">版本:%d</string>
<string name="home_superuser_count">超級使用者%d 個</string>
<string name="home_module_count">模組:%d 個</string>
<string name="home_working_version">KernelSU 版本:%d</string>
<string name="home_superuser_count">已授權 Root%d 個</string>
<string name="home_unsupported">不支援</string>
<string name="home_unsupported_reason">KernelSU 現在僅支援 GKI 核心</string>
<string name="home_copied_to_clipboard">已複製到剪貼簿</string>
<string name="home_support">支援</string>
<string name="home_kernel">核心</string>
<string name="home_arch">架構</string>
<string name="home_manager_version">管理員版本</string>
<string name="home_api">API 層級</string>
<string name="home_abi">ABI 支援</string>
<string name="home_fingerprint">指紋</string>
<string name="home_securitypatch">安全性修補程式</string>
<string name="home_manager_version">管理器版本</string>
<string name="home_fingerprint">設備指紋</string>
<string name="home_selinux_status">SELinux 狀態</string>
<string name="selinux_status_disabled">已停用</string>
<string name="selinux_status_enforcing">強制</string>
<string name="selinux_status_permissive">寬鬆</string>
<string name="selinux_status_unknown">未知</string>
<string name="superuser">超級使用者</string>
<string name="superuser_failed_to_grant_root">無法為「%d」授予 Root 存取權</string>
<string name="superuser_allow_root_confirm">您確定要授予「%s」Root 存取權嗎?</string>
<string name="superuser">Root 授權</string>
<string name="module_failed_to_enable">無法啟用模組:%s</string>
<string name="module_failed_to_disable">無法停用模組:%s</string>
<string name="module_empty">尚未安裝模組</string>
@@ -44,7 +35,6 @@
<string name="reboot_download">重新啟動至 Download</string>
<string name="reboot_edl">重新啟動至 EDL</string>
<string name="about">關於</string>
<string name="require_kernel_version_8">需要 KernelSU 8+ 版本</string>
<string name="module_uninstall_confirm">您確定要解除安裝模組「%s」嗎</string>
<string name="module_uninstall_success">「%s」已解除安裝</string>
<string name="module_uninstall_failed">無法解除安裝:%s</string>
@@ -58,10 +48,17 @@
<string name="safe_mode">安全模式</string>
<string name="reboot_to_apply">重新啟動以生效</string>
<string name="module_magisk_conflict">模組已停用,因其與 Magisk 的模組存在衝突!</string>
<string name="home_module_count">已安裝模組:%d 個</string>
<string name="home_learn_kernelsu">深入瞭解 KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">瞭解如何安裝 KernelSU 以及如何開發模組</string>
<string name="home_support_title">支持開發</string>
<string name="home_support_content">KernelSU 將保持免費和開源,您可以考慮向開發人員捐贈以表示支持。</string>
<string name="about_source_code"><![CDATA[在 %1$s 中檢視原始碼<br/>加入我們的 %2$s 頻道]]></string>
<string name="profile_umount_modules">解除安裝模組</string>
<string name="failed_to_update_app_profile">為 %s 更新 App Profile 失敗</string>
<string name="require_kernel_version">目前安裝的核心版本 %d 過低,管理器無法正常工作,請升級核心版本至 %d 或以上!</string>
<string name="settings_umount_modules_default">預設解除安裝模組</string>
<string name="settings_umount_modules_default_summary">App Profile 中\"解除安裝模組\"的全域性預設值,如果啟用,將會為沒有設定 Profile 的應用移除所有模組針對系統的修改</string>
<string name="profile_umount_modules_summary">啟用後將允許 KernelSU 為本應用還原被模組修改過的檔案</string>
</resources>

View File

@@ -10,16 +10,10 @@
<string name="home_module_count">Modules: %d</string>
<string name="home_unsupported">Unsupported</string>
<string name="home_unsupported_reason">KernelSU only supports GKI kernels now</string>
<string name="home_copied_to_clipboard">Copied to clipboard</string>
<string name="home_support">Support</string>
<string name="home_kernel">Kernel</string>
<string name="home_arch">Arch</string>
<string name="home_manager_version">Manager Version</string>
<string name="home_api">API Level</string>
<string name="home_abi">ABI</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_securitypatch">Security Patch</string>
<string name="home_selinux_status">SELinux status</string>
<string name="selinux_status_disabled">Disabled</string>
@@ -27,8 +21,6 @@
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">Unknown</string>
<string name="superuser">Superuser</string>
<string name="superuser_failed_to_grant_root">Failed to grant root for %d</string>
<string name="superuser_allow_root_confirm">Are you sure to grant root access to %s?</string>
<string name="module_failed_to_enable">Failed to enable module: %s</string>
<string name="module_failed_to_disable">Failed to disable module: %s</string>
<string name="module_empty">No module installed</string>
@@ -45,7 +37,6 @@
<string name="reboot_download">Reboot to Download</string>
<string name="reboot_edl">Reboot to EDL</string>
<string name="about">About</string>
<string name="require_kernel_version_8">Require KernelSU version 8+</string>
<string name="module_uninstall_confirm">Are you sure you want to uninstall module %s?</string>
<string name="module_uninstall_success">%s uninstalled</string>
<string name="module_uninstall_failed">Failed to uninstall: %s</string>
@@ -65,4 +56,19 @@
<string name="home_support_title">Support Us</string>
<string name="home_support_content">KernelSU is, and always will be, free, and open source. You can however show us that you care by making a donation.</string>
<string name="about_source_code"><![CDATA[View source code at %1$s<br/>Join our %2$s channel]]></string>
<string name="profile" translatable="false">App profile</string>
<string name="profile_default">Default</string>
<string name="profile_template">Template</string>
<string name="profile_custom">Custom</string>
<string name="profile_name">Profile name</string>
<string name="profile_namespace">Mount namespace</string>
<string name="profile_namespace_inherited">Inherited</string>
<string name="profile_namespace_global">Global</string>
<string name="profile_namespace_individual">Individual</string>
<string name="profile_umount_modules">Umoun modules</string>
<string name="failed_to_update_app_profile">Failed to update App Profile for %s</string>
<string name="require_kernel_version">The current kernel version %d is too low for the manager to function properly. Please upgrade to version %d or higher!</string>
<string name="settings_umount_modules_default">Umount modules by default</string>
<string name="settings_umount_modules_default_summary">The global default value for \"Umount modules\" in App Profiles. If enabled, it will remove all module modifications to the system for applications that do not have a Profile set.</string>
<string name="profile_umount_modules_summary">Enabling this option will allow KernelSU to restore any modified files by the modules for this application.</string>
</resources>

View File

@@ -1,13 +1,14 @@
[versions]
agp = "8.0.0"
agp = "8.0.1"
kotlin = "1.8.10"
ksp = "1.8.10-1.0.9"
compose-bom = "2023.04.01"
compose-bom = "2023.05.01"
lifecycle = "2.6.1"
accompanist = "0.30.0"
navigation = "2.5.3"
compose-destination = "1.9.40-beta"
compose-destination = "1.9.42-beta"
libsu = "5.0.5"
sheets-compose-dialogs = "1.1.1"
[plugins]
agp-app = { id = "com.android.application", version.ref = "agp" }
@@ -38,8 +39,6 @@ com-google-accompanist-drawablepainter = { group = "com.google.accompanist", nam
com-google-accompanist-navigation-animation = { group = "com.google.accompanist", name = "accompanist-navigation-animation", version.ref = "accompanist" }
com-google-accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanist" }
com-github-alorma-compose-settings-ui-m3 = { module = "com.github.alorma:compose-settings-ui-m3", version = "0.22.0" }
com-github-topjohnwu-libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref = "libsu" }
com-github-topjohnwu-libsu-service = { group = "com.github.topjohnwu.libsu", name = "service", version.ref = "libsu" }
@@ -47,9 +46,12 @@ dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:pa
io-coil-kt-coil-compose = { group = "io.coil-kt", name = "coil-compose", version = "2.3.0" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.6.4" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.7.1" }
me-zhanghai-android-appiconloader-coil = { group = "me.zhanghai.android.appiconloader", name = "appiconloader-coil", version = "1.5.0" }
compose-destinations-animations-core = { group = "io.github.raamcosta.compose-destinations", name = "animations-core", version.ref = "compose-destination" }
compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destination" }
sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets-compose-dialogs"}
sheet-compose-dialogs-list = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "list", version.ref = "sheets-compose-dialogs"}

View File

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

View File

@@ -6,6 +6,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdint.h>
#define MAIN

View File

@@ -82,7 +82,7 @@ async def main():
print("[-] File not exist: " + one)
continue
print("[+] Upload: " + one)
msg = await bot.send_document(CACHE_CHAT_ID, one)
msg = await bot.send_document(CACHE_CHAT_ID, one, write_timeout=60, connect_timeout=30)
if one == paths[-1]:
files.append(telegram.InputMediaDocument(msg.document,
caption=caption,

View File

@@ -58,11 +58,11 @@ fn print_usage(program: &str, opts: Options) {
print!("{}", opts.usage(&brief));
}
fn set_identity(uid: u32) {
fn set_identity(uid: u32, gid: u32) {
#[cfg(any(target_os = "linux", target_os = "android"))]
unsafe {
libc::seteuid(uid);
libc::setresgid(uid, uid, uid);
libc::setresgid(gid, gid, gid);
libc::setresuid(uid, uid, uid);
}
}
@@ -168,7 +168,9 @@ pub fn root_shell() -> Result<()> {
free_idx += 1;
}
let mut uid = 0; // default uid = 0(root)
// use current uid if no user specified, these has been done in kernel!
let mut uid = unsafe { libc::getuid() };
let gid = unsafe { libc::getgid() };
if free_idx < matches.free.len() {
let name = &matches.free[free_idx];
uid = unsafe {
@@ -234,7 +236,7 @@ pub fn root_shell() -> Result<()> {
let _ = utils::unshare_mnt_ns();
}
set_identity(uid);
set_identity(uid, gid);
std::result::Result::Ok(())
})

View File

@@ -23,7 +23,7 @@ export default defineConfig({
footer: {
message: 'Rilis Dibawah Lisensi GPL3.',
copyright: 'Copyright © 2022-present KernelSU Developers'
copyright: 'Copyright © 2022-Sekarang pengembang KernelSU '
},
editLink: {

View File

@@ -4,6 +4,7 @@ import zh_CN from './zh_CN'
import zh_TW from './zh_TW'
import vi_VN from './vi_VN'
import id_ID from './id_ID'
import ja_JP from './ja_JP'
export default defineConfig({
locales: {
@@ -25,6 +26,12 @@ export default defineConfig({
themeConfig: zh_TW.themeConfig,
description: zh_TW.description
},
ja_JP: {
label: '日本語',
lang: ja_JP.lang,
themeConfig: ja_JP.themeConfig,
description: ja_JP.description
},
vi_VN: {
label: 'Tiếng Việt',
lang: vi_VN.lang,

View File

@@ -0,0 +1,60 @@
import { createRequire } from 'module'
import { defineConfig } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export default defineConfig({
lang: 'ja-JP',
description: 'Android GKI デバイス向けのカーネルベースの root ソリューション',
themeConfig: {
nav: nav(),
lastUpdatedText: '最終更新',
sidebar: {
'/ja_JP/guide/': sidebarGuide()
},
socialLinks: [
{ icon: 'github', link: 'https://github.com/tiann/KernelSU' }
],
footer: {
message: 'GPL3 ライセンスでリリースされています。',
copyright: 'Copyright © 2022-現在 KernelSU 開発者'
},
editLink: {
pattern: 'https://github.com/tiann/KernelSU/edit/main/website/docs/:path',
text: 'GitHub でこのページを編集'
}
}
})
function nav() {
return [
{ text: 'ガイド', link: '/ja_JP/guide/what-is-kernelsu' },
{ text: 'Github', link: 'https://github.com/tiann/KernelSU' }
]
}
function sidebarGuide() {
return [
{
text: 'ガイド',
items: [
{ text: 'KernelSU とは?', link: '/ja_JP/guide/what-is-kernelsu' },
{ text: 'インストール', link: '/ja_JP/guide/installation' },
{ text: 'ビルドするには?', link: '/guide/how-to-build' },
{ text: '非 GKI デバイスでの実装', link: '/guide/how-to-integrate-for-non-gki' },
{ text: '非公式の対応デバイス', link: '/ja_JP/guide/unofficially-support-devices.md' },
{ text: 'モジュールのガイド', link: '/ja_JP/guide/module.md' },
{ text: 'ブートループからの復旧', link: '/ja_JP/guide/rescue-from-bootloop.md' },
{ text: 'よくある質問', link: '/ja_JP/guide/faq' },
{ text: '隠し機能', link: '/ja_JP/guide/hidden-features' },
]
}
]
}

View File

@@ -0,0 +1,26 @@
# Magisk との違い
KernelSU モジュールと Magisk モジュールには多くの共通点がありますが、実装の仕組みが全く異なるため、必然的にいくつかの相違点が存在します。Magisk と KernelSU の両方でモジュールを動作させたい場合、これらの違いを理解する必要があります。
## 似ているところ
- モジュールファイルの形式どちらもzip形式でモジュールを整理しており、モジュールの形式はほぼ同じです。
- モジュールのインストールディレクトリ:どちらも `/data/adb/modules` に配置されます。
- システムレス:どちらもモジュールによるシステムレスな方法で /system を変更できます。
- post-fs-data.sh: 実行時間と意味は全く同じです。
- service.sh: 実行時間と意味は全く同じです。
- system.prop全く同じです。
- sepolicy.rule全く同じです。
- BusyBoxスクリプトは BusyBox で実行され、どちらの場合も「スタンドアロンモード」が有効です。
## 違うところ
違いを理解する前に、モジュールが KernelSU で動作しているか Magisk で動作しているかを区別する方法を知っておく必要があります。環境変数 `KSU` を使うとモジュールスクリプトを実行できるすべての場所 (`customize.sh`, `post-fs-data.sh`, `service.sh`) で区別できます。KernelSU では、この環境変数に `true` が設定されます。
以下は違いです:
- KernelSU モジュールは、リカバリーモードではインストールできません。
- KernelSU モジュールには Zygisk のサポートが組み込まれていません(ただし[ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU)を使うと Zygisk モジュールを使用できます)。
- KernelSU モジュールにおけるファイルの置換や削除の方法は、Magisk とは全く異なります。KernelSU は `.replace` メソッドをサポートしていません。その代わり、`mknod filename c 0 0` で同名のファイルを作成し、対応するファイルを削除する必要があります。
- BusyBox 用のディレクトリが違います。KernelSU の組み込み BusyBox は `/data/adb/ksu/bin/busybox` に、Magisk では `/data/adb/magisk/busybox` に配置されます。**これは KernelSU の内部動作であり、将来的に変更される可能性があることに注意してください!**
- KernelSU は `.replace` ファイルをサポートしていません。しかし、KernelSU はファイルやフォルダを削除したり置き換えたりするための `REMOVE``REPLACE` 変数をサポートしています。

View File

@@ -0,0 +1,67 @@
# よくある質問
## 私のデバイスは KernelSU に対応していますか?
まず、お使いのデバイスがブートローダーのロックを解除できる必要があります。もしできないのであれば、サポート外です。
もし KernelSU アプリで「非対応」と表示されたら、そのデバイスは最初からサポートされていないことになりますが、カーネルソースをビルドして KernelSU を組み込むか、[非公式の対応デバイス](unofficially-support-devices)で動作させることが可能です。
## KernelSU を使うにはブートローダーのロックを解除する必要がありますか?
はい。
## KernelSU はモジュールに対応していますか?
はい。ただし初期バージョンであるためバグがある可能性があります。安定するのをお待ちください。
## KernelSU は Xposed に対応していますか?
はい。[Dreamland](https://github.com/canyie/Dreamland) や [TaiChi](https://taichi.cool) が動作します。LSPosed については、[Zygisk on KernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) を使うと動作するようにできます。
## KernelSU は Zygisk に対応していますか?
KernelSU は Zygisk サポートを内蔵していません。[Zygisk on KernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) を使ってください。
## KernelSU は Magisk と互換性がありますか?
KernelSU のモジュールシステムは Magisk のマジックマウントと競合しており、KernelSU で有効になっているモジュールがある場合、Magisk 全体が動作しなくなります。
しかし、KernelSU の `su` だけを使うのであれば、Magisk とうまく連携することができます。KernelSU は `kernel` を、Magisk は `ramdisk` を修正するため、両者は共存できます。
## KernelSU は Magisk の代わりになりますか?
私たちはそうは思っていませんし、それが目標でもありません。Magisk はユーザ空間の root ソリューションとして十分であり、長く使われ続けるでしょう。KernelSU の目標は、ユーザーにカーネルインターフェースを提供することであり、Magisk の代用ではありません。
## KernelSU は GKI 以外のデバイスに対応できますか?
可能です。ただしカーネルソースをダウンロードし、KernelSU をソースツリーに統合して、自分でカーネルをビルドする必要があります。
## KernelSU は Android 12 以下のデバイスに対応できますか?
KernelSU の互換性に影響を与えるのはデバイスのカーネルであり、Android のバージョンとは無関係です。唯一の制限は、Android 12 で発売されたデバイスはカーネル5.10以上GKI デバイス)でなければならないことです:
1. Android 12 をプリインストールして発売された端末は対応しているはずです。
2. カーネルが古い端末(一部の Android 12 端末はカーネルも古い)は対応可能ですが、カーネルは自分でビルドする必要があります。
## KernelSU は古いカーネルに対応できますか?
KernelSU は現在カーネル4.14にバックポートされていますが、それ以前のカーネルについては手動でバックポートする必要があります。プルリクエスト歓迎です!
## 古いカーネルに KernelSU を組み込むには?
[ガイド](../../guide/how-to-integrate-for-non-gki) を参考にしてください。
## Android のバージョンが13なのに、カーネルは「android12-5.10」と表示されるのはなぜ?
カーネルのバージョンは Android のバージョンと関係ありません。カーネルを書き込む必要がある場合は、常にカーネルのバージョンを使用してください。Android のバージョンはそれほど重要ではありません。
## KernelSU に-mount-master/global のマウント名前空間はありますか?
今はまだありませんが(将来的にはあるかもしれません)、グローバルマウントの名前空間に手動で切り替える方法は、以下のようにたくさんあります:
1. `nsenter -t 1 -m sh` でシェルをグローバル名前空間にします。
2. `nsenter --mount=/proc/1/ns/mnt` を実行したいコマンドに追加すればグローバル名前空間で実行されます。 KernelSU は [このような使い方](https://github.com/tiann/KernelSU/blob/77056a710073d7a5f7ee38f9e77c9fd0b3256576/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt#L115) もできます。
## GKI 1.0 なのですが、使えますか?
GKI1 は GKI2 と全く異なるため、カーネルは自分でビルドする必要があります。

View File

@@ -0,0 +1,7 @@
# 隠し機能
## .ksurc
デフォルトでは `/system/bin/sh``/system/etc/mkshrc` を読み込みます。
`/data/adb/ksu/.ksurc` ファイルを作成することで、カスタマイズした rc ファイルを su に読み込ませられます。

View File

@@ -0,0 +1,169 @@
# インストール
## デバイスが対応しているか確認する
[GitHub Releases](https://github.com/tiann/KernelSU/releases) または [Coolapk market](https://www.coolapk.com/apk/me.weishu.kernelsu) から KernelSU Manager アプリをダウンロードし、お使いのデバイスにインストールしてください。
- アプリが「非対応」と表示した場合は、**自分でカーネルをコンパイルする必要がある**という意味です。KernelSU は書き込むためのブートイメージを提供しません。
- アプリが「未インストール」と表示した場合、お使いのデバイスは KernelSU に対応しています。
::: info ヒント
非対応と表示されているデバイスについては、[非公式の対応デバイス](unofficially-support-devices.md)であればご自身でカーネルをビルドできます。
:::
## 純正の boot.img をバックアップ
書き込む前に、まず純正の boot.img をバックアップする必要があります。ブートループが発生した場合は、fastboot を使用して純正のブートイメージを書き込むことでいつでもシステムを復旧できます。
::: warning 警告
書き込みによりデータ損失を引き起こす可能性があります。次のステップに進む前に、このステップを必ず行うようにしてください!また、可能であればすべてのデータをバックアップしてください。
:::
## 必要な知識
### ADB と fastboot
このチュートリアルでは、デフォルトで ADB と fastboot のツールを使用します。ご存じない方は、まず検索エンジンを使って勉強されることをおすすめします。
### KMI
同じ Kernel Module Interface (KMI) のカーネルバージョンは**互換性があります**。これが GKI の「汎用」という意味です。逆に言えば KMI が異なればカーネルには互換性がなく、お使いのデバイスと異なる KMI のカーネルイメージを書き込むと、ブートループが発生する場合があります。
具体的には GKI デバイスの場合、カーネルバージョンの形式は以下のようになります:
```txt
KernelRelease :=
Version.PatchLevel.SubLevel-AndroidRelease-KmiGeneration-suffix
w .x .y -zzz -k -something
```
`w.x-zzz-k` は KMI のバージョンです。例えば、デバイスのカーネルバージョンが `5.10.101-android12-9-g30979850fc20` である場合、その KMIは `5.10-android12-9` であり、理論的には他の KMI カーネルでも正常に起動できます。
::: tip ヒント
カーネルバージョンの SubLevel は、KMI の一部ではないことに注意してください。`5.10.101-android12-9-g30979850fc20``5.10.137-android12-9-g30979850fc20` と同じ KMI を持っているということになります。
:::
### Kernel バージョンと Android バージョンの違い
注意: **カーネルバージョンと Android バージョンは必ずしも同じではありません**
カーネルのバージョンは「android12-5.10.101」なのに、Android システムのバージョンは「Android 13」などとなっている場合、驚かないでください。Linux カーネルのバージョン番号は、必ずしも**デバイスの出荷時**にプリインストールされている Android システムのバージョンと一致していません。Android システムが後でアップグレードされた場合、一般的にはカーネルのバージョンは変更されません。書き込む際は、**必ずカーネルバージョンを参照してください**!!!
## インストール方法
KernelSU のインストール方法はいくつかあり、それぞれ適したシーンが異なりますので、必要に応じて選択してください。
1. カスタムリカバリーTWRPなどでインストールする
2. Franco Kernel Manager などのカーネル管理アプリでインストールする
3. KernelSU が提供する boot.img を使用し、fastboot でインストールする
4. boot.img を手動でパッチしてインストールする
## カスタムリカバリーでインストール
前提条件:デバイスに TWRP などのカスタムリカバリーがあること。ない場合、または公式リカバリーしかない場合は他の方法を使用してください。
手順:
1. KernelSUの[リリースページ](https://github.com/tiann/KernelSU/releases)から、お使いのデバイスのバージョンにあった AnyKernel3 で始まる ZIP パッケージをダウンロードします。例えば、デバイスのカーネルのバージョンが`android12-5.10. 66`の場合、AnyKernel3-android12-5.10.66_yyyy-MM.zip`yyyy`は年、`MM`は月)のファイルをダウンロードします。
2. デバイスを TWRP へ再起動します。
3. adb を使用して AnyKernel3-*.zip をデバイスの /sdcard に入れ、TWRP GUI でインストールを選択します。または直接`adb sideload AnyKernel-*.zip` でインストールできます。
この方法は TWRP を使用できるならどのようなインストール(初期インストールやその後のアップグレード)にも適しています。
## カーネル管理アプリでインストール
前提条件:お使いのデバイスが root 化されている必要があります。例えば、Magisk をインストールして root を取得した場合、または古いバージョンの KernelSU をインストールしており、別のバージョンの KernelSU にアップグレードする必要がある場合などです。お使いのデバイスが root 化されていない場合、他の方法をお試しください。
手順:
1. AnyKernel3 ZIP をダウンロードします。ダウンロード方法は、「カスタムリカバリーでインストール」を参照してください。
2. カーネル管理アプリを開き、AnyKernel3 の ZIP をインストールします。
カーネル管理アプリは以下のようなものが人気です:
1. [Kernel Flasher](https://github.com/capntrips/KernelFlasher/releases)
2. [Franco Kernel Manager](https://play.google.com/store/apps/details?id=com.franco.kernel)
3. [Ex Kernel Manager](https://play.google.com/store/apps/details?id=flar2.exkernelmanager)
この方法は KernelSU をアップグレードするときに便利で、パソコンがなくてもできます。(まずはバックアップしてください!)
## KernelSU が提供する boot.img を使用してインストール
この方法は TWRP や root 権限を必要としないので、KernelSU を初めてインストールする場合に適しています。
### 正しい boot.img を見つける
KernelSU では、GKI デバイス用の汎用 boot.img を提供しています。デバイスの boot パーティションに boot.img をフラッシュする必要があります。
boot.img は、[GitHub Release](https://github.com/tiann/KernelSU/releases) からダウンロードできます。例えば、あなたのデバイスがカーネル `android12-5.10.101` の場合、`android-5.10.101_yyyy-MM.boot-<format>.img`をダウンロードする必要があります。KMI を同じにしてください!)。
`<format>`は純正 boot.img のカーネル圧縮形式を指します。純正の boot.img のカーネル圧縮形式を確認してください。間違った圧縮形式を使うと、ブートループするかもしれません。
::: info 情報
1. magiskboot を使えば、元のブートの圧縮形式を知ることができます。もちろん、あなたのデバイスと同じモデルを持つ、より経験豊富な他の人にも聞くこともできます。また、カーネルの圧縮形式は通常変更されないので、ある圧縮形式でうまく起動した場合、後でその形式を試すことも可能です。
2. Xiaomi デバイスでは通常 `gz` か**無圧縮**が使われます。
3. Pixel デバイスでは以下の手順に従ってください。
:::
### boot.img をデバイスに書き込む
`adb` でデバイスを接続し、`adb reboot bootloader` で fastboot モードにし、このコマンドで KernelSU を書き込んでください:
```sh
fastboot flash boot boot.img
```
::: info 情報
デバイスが `fastboot boot` をサポートしている場合、まず `fastboot boot.img` を使えば書き込みせずにシステムを起動できます。予期せぬことが起こった場合は、もう一度再起動して起動してください。
:::
### 再起動
書き込みが完了したら、デバイスを再起動します:
```sh
fastboot reboot
```
## boot.img を手動でパッチ
デバイスによっては、boot.img のフォーマットが `lz4` でない、`gz` である、無圧縮であるなど、あまり一般的でないことがあります。最も典型的なのは Pixel で、boot.img フォーマットは `lz4_legacy` 圧縮、RAM ディスクは `gz``lz4_legacy` 圧縮です。この時、KernelSU が提供した boot.img を直接書き込むとデバイスが起動できなくなる場合があります。その場合は手動で boot.img に対してパッチしてください。
パッチ方式は一般的に2種類あります
1. [Android-Image-Kitchen](https://forum.xda-developers.com/t/tool-android-image-kitchen-unpack-repack-kernel-ramdisk-win-android-linux-mac.2073775/)
2. [magiskboot](https://github.com/topjohnwu/Magisk/releases)
このうち、Android-Image-Kitchen は PC での操作に適しており、magiskboot はデバイスとの連携が必要です。
### 準備
1. お使いのデバイスの純正 boot.img を入手します。デバイスメーカーから入手できます。[payload-dumper-go](https://github.com/ssut/payload-dumper-go)が必要かもしれません。
2. お使いのデバイスの KMI バージョンに合った、KernelSU が提供する AnyKernel3 の ZIP ファイルをダウンロードします(*カスタムリカバリーでインストール*を参照してください)。
3. AnyKernel3 パッケージを展開し、KernelSU のカーネルファイルである `Image` ファイルを取得します。
### Android-Image-Kitchen を使う
1. Android-Image-Kitchen を PC にダウンロードします。
2. 純正 boot.img を Android-Image-Kitchen のルートフォルダに入れます。
3. Android-Image-Kitchen のルートディレクトリで `./unpackimg.sh boot.img` を実行して、boot.imgを展開します。
4. `split_img` ディレクトリの `boot.img-kernel` を AnyKernel3 から展開した `Image` に置き換えますboot.img-kernelに名前が変わっていることに注意してください
5. Android-Image-Kitchen のルートディレクトリで `./repackimg.sh` を実行すると、 `image-new.img` というファイルが生成されます。
### 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`
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` ファイルが純正カーネルです。
7. `kernel``Image` で置き換えます: `mv -f Image kernel`
8. `./magiskboot repack boot.img` を実行してブートイメージをリパックします。出来上がった `new-boot.img` を fastboot でデバイスに書き込んでください。
## その他の方法
実はこれらのインストール方法はすべて、**元のカーネルを KernelSU が提供するカーネルに置き換える**という主旨でしかなく、これが実現できれば他の方法でもインストール可能です:
1. まず Magisk をインストールし、Magisk を通じて root 権限を取得し、カーネル管理アプリで KernelSU の AnyKernel ZIPをインストールする
2. PC 上で何らかの書き込みツールを使用し、KernelSU が提供するカーネルを書き込む

View File

@@ -0,0 +1,255 @@
# モジュールのガイド
KernelSU はシステムパーティションの整合性を維持しながら、システムディレクトリを変更する効果を実現するモジュール機構を提供します。この機構は一般に「システムレス」と呼ばれています。
KernelSU のモジュール機構は、Magisk とほぼ同じです。Magisk のモジュール開発に慣れている方であれば、KernelSU のモジュール開発も簡単でしょう。その場合は以下のモジュールの紹介は読み飛ばして、[Magisk との違い](difference-with-magisk.md)の内容だけ読めばOKです。
## Busybox
KernelSU には、機能的に完全な Busybox バイナリ (SELinux の完全サポートを含む) が同梱されています。実行ファイルは `/data/adb/ksu/bin/busybox` に配置されています。KernelSU の Busybox はランタイムに切り替え可能な「ASH スタンドアローンシェルモード」をサポートしています。このスタンドアロンモードとは、Busybox の `ash` シェルで実行する場合 `PATH` として設定されているものに関係なく、すべてのコマンドが Busybox 内のアプレットを直接使用するというものです。たとえば、`ls``rm``chmod` などのコマンドは、`PATH` にあるものAndroid の場合、デフォルトではそれぞれ `/system/bin/ls`, `/system/bin/rm`, `/system/bin/chmod`)ではなく、直接 Busybox 内部のアプレットを呼び出すことになります。これにより、スクリプトは常に予測可能な環境で実行され、どの Android バージョンで実行されていても常にコマンドを利用できます。Busybox を使用しないコマンドを強制的に実行するには、フルパスで実行ファイルを呼び出す必要があります。
KernelSU のコンテキストで実行されるすべてのシェルスクリプトは、Busybox の `ash` シェルでスタンドアロンモードが有効な状態で実行されます。サードパーティの開発者に関係するものとしては、すべてのブートスクリプトとモジュールのインストールスクリプトが含まれます。
この「スタンドアロンモード」機能を KernelSU 以外で使用したい場合、2つの方法で有効にできます
1. 環境変数 `ASH_STANDALONE``1` にする<br>例: `ASH_STANDALONE=1 /data/adb/ksu/bin/busybox sh <script>`
2. コマンドラインのオプションで変更する:<br>`/data/adb/ksu/bin/busybox sh -o standalone <script>`
環境変数が子プロセスに継承されるため、その後に実行されるすべての `sh` シェルもスタンドアロンモードで実行されるようにするにはオプション 1 が望ましい方法ですKernelSU と KernelSU Managerが内部的に使用しているのもこちらです
::: tip Magisk との違い
KernelSU の Busybox は、Magisk プロジェクトから直接コンパイルされたバイナリファイルを使用するようになりました。Magisk と KernelSU の Busybox スクリプトはまったく同じものなので、互換性の問題を心配する必要はありません!
:::
## KernelSU モジュール
KernelSU モジュールは、`/data/adb/modules` に配置された以下の構造を持つフォルダーです:
```txt
/data/adb/modules
├── .
├── .
|
├── $MODID <--- フォルダの名前はモジュールの ID で付けます
│ │
│ │ *** モジュールの ID ***
│ │
│ ├── module.prop <--- このファイルにモジュールのメタデータを保存します
│ │
│ │ *** メインコンテンツ ***
│ │
│ ├── system <--- skip_mount が存在しない場合、このフォルダがマウントされます
│ │ ├── ...
│ │ ├── ...
│ │ └── ...
│ │
│ │ *** ステータスフラグ ***
│ │
│ ├── skip_mount <--- 存在する場合、KernelSU はシステムフォルダをマウントしません
│ ├── disable <--- 存在する場合、モジュールは無効化されます
│ ├── remove <--- 存在する場合、次の再起動時にモジュールが削除されます
│ │
│ │ *** 任意のファイル ***
│ │
│ ├── post-fs-data.sh <--- このスクリプトは post-fs-data で実行されます
│ ├── service.sh <--- このスクリプトは late_start サービスで実行されます
| ├── uninstall.sh <--- このスクリプトは KernelSU がモジュールを削除するときに実行されます
│ ├── system.prop <--- このファイルのプロパティは resetprop によってシステムプロパティとして読み込まれます
│ ├── sepolicy.rule <--- カスタム SEPolicy ルールを追加します
│ │
│ │ *** 自動生成されるため、手動で作成または変更しないでください ***
│ │
│ ├── vendor <--- $MODID/system/vendor へのシンボリックリンク
│ ├── product <--- $MODID/system/product へのシンボリックリンク
│ ├── system_ext <--- $MODID/system/system_ext へのシンボリックリンク
│ │
│ │ *** その他のファイル/フォルダの追加も可能です ***
│ │
│ ├── ...
│ └── ...
|
├── another_module
│ ├── .
│ └── .
├── .
├── .
```
::: tip Magisk との違い
KernelSU は Zygisk をビルトインでサポートしていないため、モジュール内に Zygisk に関連するコンテンツは存在しません。 しかし、[ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) をインストールすれば Zygisk モジュールを使えます。その場合の Zygisk モジュールのコンテンツは Magisk と同じです。
:::
### module.prop
module.prop はモジュールの設定ファイルです。KernelSU ではこのファイルを含まないモジュールは、モジュールとして認識されません。このファイルの形式は以下の通りです:
```txt
id=<string>
name=<string>
version=<string>
versionCode=<int>
author=<string>
description=<string>
```
- `id` はこの正規表現に一致していなければいけません: `^[a-zA-Z][a-zA-Z0-9._-]+$`<br>
例: ✓ `a_module`, ✓ `a.module`, ✓ `module-101`, ✗ `a module`, ✗ `1_module`, ✗ `-a-module`<br>
これはモジュールの**ユニークな ID** です。公開後は変更しないでください。
- `versionCode`**integer** です。バージョンの比較に使います。
- 他のものには**単一行** の文字であれば何でも使えます。
- 改行文字は `UNIX (LF)` を使ってください。`Windows (CR+LF)``Macintosh (CR)` は使ってはいけません。
### シェルスクリプト
`post-fs-data.sh``service.sh` の違いについては、[ブートスクリプト](#boot-scripts)のセクションを読んでください。ほとんどのモジュール開発者にとって、ブートスクリプトを実行するだけなら `service.sh` で十分なはずです。
モジュールのすべてのスクリプトでは、`MODDIR=${0%/*}`を使えばモジュールのベースディレクトリのパスを取得できます。スクリプト内でモジュールのパスをハードコードしないでください。
::: tip Magisk との違い
環境変数 `KSU` を使用すると、スクリプトが KernelSU と Magisk どちらで実行されているかを判断できます。KernelSU で実行されている場合、この値は `true` に設定されます。
:::
### `system` ディレクトリ
このディレクトリの内容は、システムの起動後に OverlayFS を使用してシステムの /system パーティションの上にオーバーレイされます:
1. システム内の対応するディレクトリにあるファイルと同名のファイルは、このディレクトリにあるファイルで上書きされます。
2. システム内の対応するディレクトリにあるフォルダと同じ名前のフォルダは、このディレクトリにあるフォルダと統合されます。
元のシステムディレクトリにあるファイルやフォルダを削除したい場合は、`mknod filename c 0 0` を使ってモジュールディレクトリにそのファイル/フォルダと同じ名前のファイルを作成する必要があります。こうすることで、OverlayFS システムはこのファイルを削除したかのように自動的に「ホワイトアウト」します(/system パーティションは実際には変更されません)。
また、`customize.sh` 内で `REMOVE` という変数に削除操作を実行するディレクトリのリストを宣言すると、KernelSU は自動的にそのモジュールの対応するディレクトリで `mknod <TARGET> c 0 0` を実行します。例えば
```sh
REMOVE="
/system/app/YouTube
/system/app/Bloatware
"
```
上記の場合は、`mknod $MODPATH/system/app/YouTuBe c 0 0``mknod $MODPATH/system/app/Bloatware c 0 0`を実行し、`/system/app/YouTube``/system/app/Bloatware`はモジュール有効化後に削除されます。
システム内のディレクトリを置き換えたい場合は、モジュールディレクトリに同じパスのディレクトリを作成し、このディレクトリに `setfattr -n trusted.overlay.opaque -v y <TARGET>` という属性を設定する必要があります。こうすることで、OverlayFS システムは(/system パーティションを変更することなく)システム内の対応するディレクトリを自動的に置き換えることができます。
`customize.sh` ファイル内に `REPLACE` という変数を宣言し、その中に置換するディレクトリのリストを入れておけば、KernelSU は自動的にモジュールディレクトリに対応した処理を行います。例えば:
REPLACE="
/system/app/YouTube
/system/app/Bloatware
"
このリストは、自動的に `$MODPATH/system/app/YouTube``$MODPATH/system/app/Bloatware` というディレクトリを作成し、 `setfattr -n trusted.overlay.opaque -v y $MODPATH/system/app/YouTube``setfattr -n trusted.overlay.opaque -v y $MODPATH/system/app/Bloatware` を実行します。モジュールが有効になると、`/system/app/YouTube``/system/app/Bloatware` は空のディレクトリに置き換えられます。
::: tip Magisk との違い
KernelSU のシステムレスメカニズムはカーネルの OverlayFS によって実装され、Magisk は現在マジックマウントbind mountを使用しています。この2つの実装方法には大きな違いがありますが最終的な目的は同じで、/system パーティションを物理的に変更することなく、/system のファイルを変更できます。
:::
OverlayFS に興味があれば、Linux カーネルの [OverlayFS のドキュメンテーション](https://docs.kernel.org/filesystems/overlayfs.html) を読んでみてください。
### system.prop
このファイルは `build.prop` と同じ形式をとっています。各行は `[key]=[value]` で構成されます。
### sepolicy.rule
もしあなたのモジュールが追加の SEPolicy パッチを必要とする場合は、それらのルールをこのファイルに追加してください。このファイルの各行は、ポリシーステートメントとして扱われます。
## モジュールのインストーラー
KernelSU モジュールインストーラーは、KernelSU Manager アプリでインストールできる、ZIP ファイルにパッケージされた KernelSU モジュールです。最もシンプルな KernelSU モジュールインストーラーは、KernelSU モジュールを ZIP ファイルとしてパックしただけのものです。
```txt
module.zip
├── customize.sh <--- (任意、詳細は後述)
│ このスクリプトは update-binary から読み込まれます
├── ...
├── ... /* 残りのモジュールのファイル */
```
::: warning 警告
KernelSU モジュールは、カスタムリカバリーからのインストールには非対応です!
:::
### カスタマイズ
モジュールのインストールプロセスをカスタマイズする必要がある場合、`customize.sh` という名前のスクリプトを作成してください。このスクリプトは、すべてのファイルが抽出され、デフォルトのパーミッションと secontext が適用された後、モジュールインストーラースクリプトによって読み込み (実行ではなく) されます。これは、モジュールがデバイスの ABI に基づいて追加設定を必要とする場合や、モジュールファイルの一部に特別なパーミッション/コンテキストを設定する必要がある場合に、非常に便利です。
インストールプロセスを完全に制御しカスタマイズしたい場合は、`customize.sh``SKIPUNZIP=1` と宣言すればデフォルトのインストールステップをすべてスキップできます。そうすることで、`customize.sh` が責任をもってすべてをインストールするようになります。
`customize.sh`スクリプトは、KernelSU の Busybox `ash` シェルで、「スタンドアロンモード」を有効にして実行します。以下の変数と関数が利用可能です:
#### 変数
- `KSU` (bool): スクリプトが KernelSU 環境で実行されていることを示すための変数で、この変数の値は常に true になります。KernelSU と Magisk を区別するために使用できます。
- `KSU_VER` (string): 現在インストールされている KernelSU のバージョン文字列 (例: `v0.4.0`)
- `KSU_VER_CODE` (int): ユーザー空間に現在インストールされているKernelSUのバージョンコード (例: `10672`)
- `KSU_KERNEL_VER_CODE` (int): 現在インストールされている KernelSU のカーネル空間でのバージョンコード(例:`10672`
- `BOOTMODE` (bool): KernelSU では常に `true`
- `MODPATH` (path): モジュールファイルがインストールされるパス
- `TMPDIR` (path): ファイルを一時的に保存しておく場所
- `ZIPFILE` (path): あなたのモジュールのインストールZIP
- `ARCH` (string): デバイスの CPU アーキテクチャ。値は `arm``arm64``x86``x64` のいずれか
- `IS64BIT` (bool): `ARCH``arm64` または `x64` のときは `true`
- `API` (int): 端末の API レベル・Android のバージョンAndroid 6.0 なら`23`
::: warning 警告
KernelSU では、MAGISK_VER_CODE は常に25200、MAGISK_VER は常にv25.2です。この2つの変数で KernelSU 上で動作しているかどうかを判断するのはやめてください。
:::
#### 機能
```txt
ui_print <msg>
コンソールに <msg> を表示します
カスタムリカバリーのコンソールでは表示されないため、「echo」の使用は避けてください
abort <msg>
エラーメッセージ<msg>をコンソールに出力し、インストールを終了させます
終了時のクリーンアップがスキップされてしまうため、「exit」の使用は避けてください
set_perm <target> <owner> <group> <permission> [context]
[context] が設定されていない場合、デフォルトは "u:object_r:system_file:s0" です。
この機能は、次のコマンドの略記です:
chown owner.group target
chmod permission target
chcon context target
set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
[context] が設定されていない場合、デフォルトは "u:object_r:system_file:s0" です。
<directory> 内のすべてのファイルに対しては以下が実行されます:
set_perm file owner group filepermission context
<directory> 内のすべてのディレクトリ(自身を含む)に対しては以下が実行されます:
set_perm dir owner group dirpermission context
```
## ブートスクリプト
KernelSU では、スクリプトは実行モードによって post-fs-data モードと late_start サービスモードの2種類に分けられます
- post-fs-data モード
- 同期処理です。実行が終わるか、10秒が経過するまでブートプロセスが一時停止されます。
- スクリプトはモジュールがマウントされる前に実行されます。モジュール開発者はモジュールがマウントされる前に、動的にモジュールを調整できます。
- このステージは Zygote が始まる前に起こるので、Android のほぼすべての処理の前に割り込めます
- **警告:** `setprop` を使うとブートプロセスのデッドロックを引き起こします! `resetprop -n <prop_name> <prop_value>` を使ってください。
- **本当に必要な場合だけこのモードでコマンド実行してください**
- late_start サービスモード
- 非同期処理です。スクリプトは、起動プロセスの残りの部分と並行して実行されます。
- **ほとんどのスクリプトにはこちらがおすすめです**
KernelSU では、起動スクリプトは保存場所によって一般スクリプトとモジュールスクリプトの2種類に分けられます
- 一般スクリプト
- `/data/adb/post-fs-data.d``/data/adb/service.d` に配置されます
- スクリプトが実行可能な状態に設定されている場合にのみ実行されます (`chmod +x script.sh`)
- `post-fs-data.d` のスクリプトは post-fs-data モードで実行され、`service.d` のスクリプトは late_start サービスモードで実行されます
- モジュールはインストール時に一般スクリプトを追加するべきではありません
- モジュールスクリプト
- モジュール独自のフォルダに配置されます
- モジュールが有効な場合のみ実行されます
- `post-fs-data.sh` は post-fs-data モードで実行され、`service.sh` は late_start サービスモードで実行されます
すべてのブートスクリプトは、KernelSU の Busybox `ash` シェルで「スタンドアロンモード」を有効にした状態で実行されます。

View File

@@ -0,0 +1,50 @@
# ブートループからの復旧
デバイスに書き込む際、デバイスが「文鎮化」状態になる場面に遭遇することがあります。理論的には、fastboot で boot パーティションを書き込んだだけだったり、不適切なモジュールをインストールしてデバイスが起動しなくなったりした場合なら、適切な操作で復旧できます。このページでは、「文鎮化」状態になったデバイスを復旧させるための緊急手段を紹介します。
## boot パーティションの書き込みによる文鎮化
KernelSU では、以下のような状況で boot パーティションを書き込んだときに文鎮化する場合があります:
1. 間違った形式の boot イメージを書き込んでしまった場合。例えばお使いのデバイスのパーティション形式が `gz` なのに `lz4` 形式のイメージを書き込んでしまうと、起動しなくなります。
2. お使いのデバイスが起動するために AVB 検証を無効にする必要がある場合(通常、無効にするにはすべてのデータを消去する必要があります)。
3. カーネルにバグがある、または書き込みに適していない場合。
どのような状況であっても、**純正の boot イメージを書き込む**ことで復旧できます。したがって、インストールする前にまずは純正の boot パーティションをバックアップすることを強くおすすめします。バックアップしていない場合は、あなたと同じデバイスを持つ他のユーザー、または公式ファームウェアから純正の boot イメージを入手できます。
## モジュールによる文鎮化
モジュールのインストールはデバイスを文鎮化させる一般的な原因です。**モジュールを未知のソースからインストールしないでください**!モジュールは root 権限を持つため、あなたのデバイスに不可逆的なダメージを与える可能性があります!
### 通常のモジュール
安全であることが確認されているモジュールをインストールしてデバイスが起動しなくなった場合、KernelSU では心配することなく簡単に復旧できます。KernelSU には、以下のようなデバイスを救出するための仕組みが組み込まれています:
1. AB アップデート
2. 音量下ボタンでの復旧
#### AB アップデート
KernelSU のモジュール更新は、OTA アップデートで使用される Android システムの AB アップデート機構からヒントを得ています。新しいモジュールをインストールしたり、既存のモジュールを更新したりする場合、現在使用されているモジュールファイルを直接変更することはありません。代わりに、すべてのモジュールが別のアップデートイメージに組み込まれます。システムが再起動された後、このアップデートイメージの使用を開始しようとします。Android システムが正常に起動した場合、モジュールは本当に更新されます。
そのため、デバイスを復旧する最もシンプルで一般的な方法は、**強制的に再起動すること**です。モジュールをインストールした後にシステムを起動できなくなった場合、電源ボタンを10秒以上長押しするとシステムが自動的に再起動します。再起動後はモジュールを更新する前の状態にロールバックされ、以前に更新したモジュールは自動的に無効化されます。
#### 音量下ボタンでの復旧
AB アップデートでも解決しない場合は、**セーフモード**を使用してみてください。セーフモードでは、すべてのモジュールが無効化されます。
セーフモードに入るには、2つの方法があります
1. 一部のシステムの内蔵セーフモード音量下ボタンの長押しでセーフモードに入れるシステムもあれば、リカバリーでセーフモードに入れるシステムMIUI など)もあります。システムのセーフモードに入ると KernelSU もセーフモードに入り、自動的にモジュールを無効化します。
2. KernelSU の内蔵セーフモード:最初の起動画面の後、**音量下キーを3回以上連続して押す**と入れます。なお、押す→離すを三回繰り返すのであって、長押しではありません。
セーフモードに入ると、KernelSU Manager のモジュールページにあるすべてのモジュールが無効になります。「アンインストール」操作を行うことで、問題を起こしている可能性のあるモジュールをアンインストールできます。
内蔵のセーフモードはカーネルに実装されているため、キーイベントを見逃す可能性はありません。ただし、GKI 以外のカーネルでは手動によるコードの統合が必要な場合があるため、公式ドキュメントを参考にしてください。
### 悪意のあるモジュール
上記の方法でデバイスを救出できない場合、インストールしたモジュールが悪意のある操作をしているか、他の手段でデバイスを損傷している可能性が高いです。この場合、2つの方法しかありません
1. データを消去して純正システムをインストールし直す
2. アフターセールスサービスに問い合わせする

View File

@@ -0,0 +1,30 @@
# 非公式の対応デバイス
::: warning 警告
このページでは他の開発者が管理している、KernelSU をサポートする GKI 以外のデバイス用のカーネルを紹介しています。
:::
::: warning 警告
このページはあなたのデバイスに対応するソースコードを見つけるためのものであり、そのソースコードが _KernelSU 開発者_ によってレビューされたことを意味するものではありません。ご自身の責任においてご利用ください。
:::
<script setup>
import data from '../../repos.json'
</script>
<table>
<thead>
<tr>
<th>メンテナー</th>
<th>リポジトリ</th>
<th>対応デバイス</th>
</tr>
</thead>
<tbody>
<tr v-for="repo in data" :key="repo.devices">
<td><a :href="repo.maintainer_link" target="_blank" rel="noreferrer">{{ repo.maintainer }}</a></td>
<td><a :href="repo.kernel_link" target="_blank" rel="noreferrer">{{ repo.kernel_name }}</a></td>
<td>{{ repo.devices }}</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,21 @@
# KernelSU とは?
KernelSU は Android GKI デバイスのための root ソリューションです。カーネルモードで動作し、カーネル空間で直接ユーザー空間アプリに root 権限を付与します。
## 機能
KernelSU の最大の特徴は、**カーネルベース**であることです。KernelSU はカーネルモードで動作するため、今までにないカーネルインターフェイスを提供できます。例えば、カーネルモードで任意のプロセスにハードウェアブレークポイントを追加できる、誰にも気づかれずに任意のプロセスの物理メモリにアクセスできる、カーネル空間で任意のシステムコールを傍受できる、などです。
また、KernelSU は OverlayFS によるモジュールシステムを提供しており、カスタムプラグインをシステムに読み込めます。`/system` パーティションを変更する仕組みも提供しています。
## 使用方法
こちらをご覧ください: [インストール方法](installation)
## ビルド方法
[ビルドするには](../../guide/how-to-build)
## ディスカッション
- Telegram: [@KernelSU](https://t.me/KernelSU)

View File

@@ -0,0 +1,29 @@
---
layout: home
title: Android 向けのカーネルベース root ソリューション
hero:
name: KernelSU
text: Android 向けのカーネルベース root ソリューション
tagline: ""
image:
src: /logo.png
alt: KernelSU
actions:
- theme: brand
text: はじめる
link: /ja_JP/guide/what-is-kernelsu
- theme: alt
text: GitHub で表示
link: https://github.com/tiann/KernelSU
features:
- title: カーネルベース
details: KernelSU は Linux カーネルモードで動作し、ユーザー空間よりも高度な制御が可能です。
- title: ホワイトリストの権限管理
details: root 権限を許可したアプリのみが su にアクセスでき、他のアプリは su を見つけられません。
- title: モジュール対応
details: KernelSU は OverlayFS により実際のシステムを改変せずに /system を変更できます。書き込み可能にすることさえできます。
- title: オープンソース
details: KernelSU は GPL-3 でライセンスされたオープンソースプロジェクトです。

View File

@@ -9,10 +9,17 @@
{
"maintainer": "diphons",
"maintainer_link": "https://github.com/diphons",
"kernel_name": "D8G_Kernel_ROG",
"kernel_link": "https://github.com/diphons/D8G_Kernel_Vayuasu/tree/main",
"kernel_name": "D8G_Kernel_SM8150",
"kernel_link": "https://github.com/diphons/D8G_Kernel_SM8150/tree/13",
"devices": "Poco X3 Pro: Vayu | Bhima"
},
{
"maintainer": "diphons",
"maintainer_link": "https://github.com/diphons",
"kernel_name": "D8G_Kernel_SDM845",
"kernel_link": "https://github.com/diphons/D8G_Kernel/tree/main",
"devices": "Poco F1 | MI8 | MiMix2S"
},
{
"maintainer": "SpectreDev-007",
"maintainer_link": "https://github.com/SpectreDev-007",
@@ -306,5 +313,33 @@
"kernel_name": "kernel_oneplus_msm8998",
"kernel_link": "https://github.com/TheNoFace/kernel_oneplus_msm8998/tree/pe-13-ksu",
"devices": "OnePlus 5/5T (cheeseburger/dumpling)"
},
{
"maintainer": "Nipin NA (Joker-V2)",
"maintainer_link": "https://github.com/Joker-V2",
"kernel_name": "Xcalibur kernel (violet)",
"kernel_link": "https://github.com/Joker-V2/kernel_xiaomi_violet/tree/kernelsu",
"devices": "Xiaomi Redmi Note 7 Pro (violet)"
},
{
"maintainer": "Sr-Han",
"maintainer_link": "https://github.com/Sr-Han",
"kernel_name": "kernel_xiaomi_mojito.git",
"kernel_link": "https://github.com/Sr-Han/kernel_xiaomi_mojito.git",
"devices": "Redmi Note 10 (Sunny/Mojito)"
},
{
"maintainer": "dabao1955",
"maintainer_link": "https://github.com/dabao1955",
"kernel_name": "android_kernel_OPPO_OP4ED5",
"kernel_link": "https://github.com/dabao1955/android_kernel_OPPO_OP4ED5",
"devices": "OPPO Reno6 on ColorOS11.x/ColorOS12.x\uff0ckernel version4.14.186+"
},
{
"maintainer": "rushiranpise",
"maintainer_link": "https://github.com/rushiranpise",
"kernel_name": "android_kernel_samsung_exynos9610_mint",
"kernel_link": "https://github.com/rushiranpise/android_kernel_samsung_exynos9610_mint",
"devices": "Kernel 4.14.194 exynos9610 Non-GKI Device, Added KernelSu using manual method"
}
]

View File

@@ -7,7 +7,7 @@
"author": "weishu",
"license": "MIT",
"devDependencies": {
"vitepress": "^1.0.0-alpha.40",
"vitepress": "^1.0.0-alpha.75",
"vue": "^3.2.45"
},
"scripts": {

View File

@@ -2,24 +2,24 @@
# yarn lockfile v1
"@algolia/autocomplete-core@1.7.4":
version "1.7.4"
resolved "https://registry.npmmirror.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz#85ff36b2673654a393c8c505345eaedd6eaa4f70"
integrity sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==
"@algolia/autocomplete-core@1.8.2":
version "1.8.2"
resolved "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.8.2.tgz#8d758c8652742e2761450d2b615a841fca24e10e"
integrity sha512-mTeshsyFhAqw/ebqNsQpMtbnjr+qVOSKXArEj4K0d7sqc8It1XD0gkASwecm9mF/jlOQ4Z9RNg1HbdA8JPdRwQ==
dependencies:
"@algolia/autocomplete-shared" "1.7.4"
"@algolia/autocomplete-shared" "1.8.2"
"@algolia/autocomplete-preset-algolia@1.7.4":
version "1.7.4"
resolved "https://registry.npmmirror.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz#610ee1d887962f230b987cba2fd6556478000bc3"
integrity sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==
"@algolia/autocomplete-preset-algolia@1.8.2":
version "1.8.2"
resolved "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.8.2.tgz#706e87f94c5f198c0e90502b97af09adeeddcc79"
integrity sha512-J0oTx4me6ZM9kIKPuL3lyU3aB8DEvpVvR6xWmHVROx5rOYJGQcZsdG4ozxwcOyiiu3qxMkIbzntnV1S1VWD8yA==
dependencies:
"@algolia/autocomplete-shared" "1.7.4"
"@algolia/autocomplete-shared" "1.8.2"
"@algolia/autocomplete-shared@1.7.4":
version "1.7.4"
resolved "https://registry.npmmirror.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz#78aea1140a50c4d193e1f06a13b7f12c5e2cbeea"
integrity sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==
"@algolia/autocomplete-shared@1.8.2":
version "1.8.2"
resolved "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.8.2.tgz#e6972df5c6935a241f16e4909aa82902338e029d"
integrity sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==
"@algolia/cache-browser-local-storage@4.14.3":
version "4.14.3"
@@ -130,148 +130,158 @@
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b"
integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==
"@docsearch/css@3.3.2", "@docsearch/css@^3.3.1":
version "3.3.2"
resolved "https://registry.npmmirror.com/@docsearch/css/-/css-3.3.2.tgz#2c49995e6fbc7834c75f317b277ed6e4019223a4"
integrity sha512-dctFYiwbvDZkksMlsmc7pj6W6By/EjnVXJq5TEPd05MwQe+dcdHJgaIn1c8wfsucxHpIsdrUcgSkACHCq6aIhw==
"@babel/parser@^7.20.15", "@babel/parser@^7.21.3":
version "7.21.8"
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz#642af7d0333eab9c0ad70b14ac5e76dbde7bfdf8"
integrity sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==
"@docsearch/js@^3.3.1":
version "3.3.2"
resolved "https://registry.npmmirror.com/@docsearch/js/-/js-3.3.2.tgz#fd7d5dfdd79abfe2bc8011b119215e0b08e33138"
integrity sha512-k2yiB9attFvKoiYswrRtKhIO+qHuzAj1FHYfFWrKz3wSzB2G6s/7EZL9Rf6iytUo1Ok00LUj2C6mWoOnsUTkxg==
"@docsearch/css@3.3.4", "@docsearch/css@^3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@docsearch/css/-/css-3.3.4.tgz#533719eac0aa3934318074e7e981e633727ad2fd"
integrity sha512-vDwCDoVXDgopw/hvr0zEADew2wWaGP8Qq0Bxhgii1Ewz2t4fQeyJwIRN/mWADeLFYPVkpz8TpEbxya/i6Tm0WA==
"@docsearch/js@^3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@docsearch/js/-/js-3.3.4.tgz#9ac4192f55535904a4c4235ee936ef11a109461c"
integrity sha512-Xd2saBziXJ1UuVpcDz94zAFEFAM6ap993agh0za2e3LDZLhaW993b1f9gyUL4e1CZLsR076tztG2un2gVncvpA==
dependencies:
"@docsearch/react" "3.3.2"
"@docsearch/react" "3.3.4"
preact "^10.0.0"
"@docsearch/react@3.3.2":
version "3.3.2"
resolved "https://registry.npmmirror.com/@docsearch/react/-/react-3.3.2.tgz#252b659c66682f24902bf6db257f63ee73ffe8fa"
integrity sha512-ugILab2TYKSh6IEHf6Z9xZbOovsYbsdfo60PBj+Bw+oMJ1MHJ7pBt1TTcmPki1hSgg8mysgKy2hDiVdPm7XWSQ==
"@docsearch/react@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@docsearch/react/-/react-3.3.4.tgz#d49cf9e5d939145c9fe688113c5bdf41975d8ae7"
integrity sha512-aeOf1WC5zMzBEi2SI6WWznOmIo9rnpN4p7a3zHXxowVciqlI4HsZGtOR9nFOufLeolv7HibwLlaM0oyUqJxasw==
dependencies:
"@algolia/autocomplete-core" "1.7.4"
"@algolia/autocomplete-preset-algolia" "1.7.4"
"@docsearch/css" "3.3.2"
"@algolia/autocomplete-core" "1.8.2"
"@algolia/autocomplete-preset-algolia" "1.8.2"
"@docsearch/css" "3.3.4"
algoliasearch "^4.0.0"
"@esbuild/android-arm64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.12.tgz#86c4fdd7c0d65fe9dcbe138fbe72720658ec3b88"
integrity sha512-0LacmiIW+X0/LOLMZqYtZ7d4uY9fxYABAYhSSOu+OGQVBqH4N5eIYgkT7bBFnR4Nm3qo6qS3RpHKVrDASqj/uQ==
"@esbuild/android-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==
"@esbuild/android-arm@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.12.tgz#15e33bb1c8c2f560fbb27cda227c0fa22d83d0ef"
integrity sha512-CTWgMJtpCyCltrvipZrrcjjRu+rzm6pf9V8muCsJqtKujR3kPmU4ffbckvugNNaRmhxAF1ZI3J+0FUIFLFg8KA==
"@esbuild/android-arm@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d"
integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==
"@esbuild/android-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.12.tgz#3b0ddaf59fdf94e8e9fcb2aa6537cbab93d5fe22"
integrity sha512-sS5CR3XBKQXYpSGMM28VuiUnbX83Z+aWPZzClW+OB2JquKqxoiwdqucJ5qvXS8pM6Up3RtJfDnRQZkz3en2z5g==
"@esbuild/android-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1"
integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==
"@esbuild/darwin-arm64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.12.tgz#ac6c5d85cabf20de5047b55eab7f3c252d9aae71"
integrity sha512-Dpe5hOAQiQRH20YkFAg+wOpcd4PEuXud+aGgKBQa/VriPJA8zuVlgCOSTwna1CgYl05lf6o5els4dtuyk1qJxQ==
"@esbuild/darwin-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz#584c34c5991b95d4d48d333300b1a4e2ff7be276"
integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==
"@esbuild/darwin-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.12.tgz#3433e6432dd474994302bcfe35c5420fae46a206"
integrity sha512-ApGRA6X5txIcxV0095X4e4KKv87HAEXfuDRcGTniDWUUN+qPia8sl/BqG/0IomytQWajnUn4C7TOwHduk/FXBQ==
"@esbuild/darwin-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb"
integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==
"@esbuild/freebsd-arm64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.12.tgz#b150587dc54dc2369cb826e6ee9f94fc5ec14635"
integrity sha512-AMdK2gA9EU83ccXCWS1B/KcWYZCj4P3vDofZZkl/F/sBv/fphi2oUqUTox/g5GMcIxk8CF1CVYTC82+iBSyiUg==
"@esbuild/freebsd-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2"
integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==
"@esbuild/freebsd-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.12.tgz#e682a61cde8d6332aaeb4c2b28fce0d833928903"
integrity sha512-KUKB9w8G/xaAbD39t6gnRBuhQ8vIYYlxGT2I+mT6UGRnCGRr1+ePFIGBQmf5V16nxylgUuuWVW1zU2ktKkf6WQ==
"@esbuild/freebsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4"
integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==
"@esbuild/linux-arm64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.12.tgz#d0d75e10796d4f1414ecaf16a8071ce05446cb9f"
integrity sha512-29HXMLpLklDfmw7T2buGqq3HImSUaZ1ArmrPOMaNiZZQptOSZs32SQtOHEl8xWX5vfdwZqrBfNf8Te4nArVzKQ==
"@esbuild/linux-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb"
integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==
"@esbuild/linux-arm@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.12.tgz#945ebcd99205fadea5ee22bff624189bd95c0484"
integrity sha512-vhDdIv6z4eL0FJyNVfdr3C/vdd/Wc6h1683GJsFoJzfKb92dU/v88FhWdigg0i6+3TsbSDeWbsPUXb4dif2abg==
"@esbuild/linux-arm@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a"
integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==
"@esbuild/linux-ia32@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.12.tgz#132e61b2124eee6033bf7f0d5b312c02524d39db"
integrity sha512-JFDuNDTTfgD1LJg7wHA42o2uAO/9VzHYK0leAVnCQE/FdMB599YMH73ux+nS0xGr79pv/BK+hrmdRin3iLgQjg==
"@esbuild/linux-ia32@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a"
integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==
"@esbuild/linux-loong64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.12.tgz#d27dc1e203c0d0516c1daadb7988f88b643f8ea2"
integrity sha512-xTGzVPqm6WKfCC0iuj1fryIWr1NWEM8DMhAIo+4rFgUtwy/lfHl+Obvus4oddzRDbBetLLmojfVZGmt/g/g+Rw==
"@esbuild/linux-loong64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72"
integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==
"@esbuild/linux-mips64el@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.12.tgz#9616c378ca76f12d06ffaf242da68a58be966a18"
integrity sha512-zI1cNgHa3Gol+vPYjIYHzKhU6qMyOQrvZ82REr5Fv7rlh5PG6SkkuCoH7IryPqR+BK2c/7oISGsvPJPGnO2bHQ==
"@esbuild/linux-mips64el@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289"
integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==
"@esbuild/linux-ppc64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.12.tgz#b033a248212249c05c162b64124744345a041f92"
integrity sha512-/C8OFXExoMmvTDIOAM54AhtmmuDHKoedUd0Otpfw3+AuuVGemA1nQK99oN909uZbLEU6Bi+7JheFMG3xGfZluQ==
"@esbuild/linux-ppc64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7"
integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==
"@esbuild/linux-riscv64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.12.tgz#b6476abff413b5b472e6cf093086b9d5be4553a8"
integrity sha512-qeouyyc8kAGV6Ni6Isz8hUsKMr00EHgVwUKWNp1r4l88fHEoNTDB8mmestvykW6MrstoGI7g2EAsgr0nxmuGYg==
"@esbuild/linux-riscv64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09"
integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==
"@esbuild/linux-s390x@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.12.tgz#981a639f8c2a2e0646f47eba0fae7c2c270b208b"
integrity sha512-s9AyI/5vz1U4NNqnacEGFElqwnHusWa81pskAf8JNDM2eb6b2E6PpBmT8RzeZv6/TxE6/TADn2g9bb0jOUmXwQ==
"@esbuild/linux-s390x@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829"
integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==
"@esbuild/linux-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.12.tgz#01b777229d8baf068eeeb7cd7c396aea4d1ebd36"
integrity sha512-e8YA7GQGLWhvakBecLptUiKxOk4E/EPtSckS1i0MGYctW8ouvNUoh7xnU15PGO2jz7BYl8q1R6g0gE5HFtzpqQ==
"@esbuild/linux-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
"@esbuild/netbsd-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.12.tgz#6d4b9de7dc3ac99bf04653fe640b3be63c57b1aa"
integrity sha512-z2+kUxmOqBS+6SRVd57iOLIHE8oGOoEnGVAmwjm2aENSP35HPS+5cK+FL1l+rhrsJOFIPrNHqDUNechpuG96Sg==
"@esbuild/netbsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462"
integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==
"@esbuild/openbsd-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.12.tgz#2a28010b1848466586d5e2189e9f1b8334b65708"
integrity sha512-PAonw4LqIybwn2/vJujhbg1N9W2W8lw9RtXIvvZoyzoA/4rA4CpiuahVbASmQohiytRsixbNoIOUSjRygKXpyA==
"@esbuild/openbsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691"
integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==
"@esbuild/sunos-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.12.tgz#3ee120008cc759d604825dd25501152071ef30f0"
integrity sha512-+wr1tkt1RERi+Zi/iQtkzmMH4nS8+7UIRxjcyRz7lur84wCkAITT50Olq/HiT4JN2X2bjtlOV6vt7ptW5Gw60Q==
"@esbuild/sunos-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273"
integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==
"@esbuild/win32-arm64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.12.tgz#8c599a91f1c55b3df304c450ac0613855c10502e"
integrity sha512-XEjeUSHmjsAOJk8+pXJu9pFY2O5KKQbHXZWQylJzQuIBeiGrpMeq9sTVrHefHxMOyxUgoKQTcaTS+VK/K5SviA==
"@esbuild/win32-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f"
integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==
"@esbuild/win32-ia32@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.12.tgz#102b5a44b514f8849a10cc4cc618c60c70a4c536"
integrity sha512-eRKPM7e0IecUAUYr2alW7JGDejrFJXmpjt4MlfonmQ5Rz9HWpKFGCjuuIRgKO7W9C/CWVFXdJ2GjddsBXqQI4A==
"@esbuild/win32-ia32@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03"
integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==
"@esbuild/win32-x64@0.16.12":
version "0.16.12"
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.12.tgz#31197bb509049b63c059c4808ac58e66fdff7479"
integrity sha512-iPYKN78t3op2+erv2frW568j1q0RpqX6JOLZ7oPPaAV1VaF7dDstOrNw37PVOYoTWE11pV4A1XUitpdEFNIsPg==
"@esbuild/win32-x64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061"
integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==
"@types/web-bluetooth@^0.0.16":
version "0.0.16"
resolved "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
"@jridgewell/sourcemap-codec@^1.4.13":
version "1.4.15"
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@vitejs/plugin-vue@^4.0.0":
version "4.0.0"
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz#93815beffd23db46288c787352a8ea31a0c03e5e"
integrity sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==
"@types/web-bluetooth@^0.0.17":
version "0.0.17"
resolved "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz#5c9f3c617f64a9735d7b72a7cc671e166d900c40"
integrity sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==
"@vitejs/plugin-vue@^4.2.1":
version "4.2.3"
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz#ee0b6dfcc62fe65364e6395bf38fa2ba10bb44b6"
integrity sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==
"@vue/compiler-core@3.2.45":
version "3.2.45"
@@ -283,6 +293,16 @@
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-core@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.2.tgz#39567bd15c7f97add97bfc4d44e814df36eb797b"
integrity sha512-CKZWo1dzsQYTNTft7whzjL0HsrEpMfiK7pjZ2WFE3bC1NA7caUjWioHSK+49y/LK7Bsm4poJZzAMnvZMQ7OTeg==
dependencies:
"@babel/parser" "^7.21.3"
"@vue/shared" "3.3.2"
estree-walker "^2.0.2"
source-map-js "^1.0.2"
"@vue/compiler-dom@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz#c43cc15e50da62ecc16a42f2622d25dc5fd97dce"
@@ -291,6 +311,14 @@
"@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-dom@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.2.tgz#2012ef4879375a4ca4ee68012a9256398b848af2"
integrity sha512-6gS3auANuKXLw0XH6QxkWqyPYPunziS2xb6VRenM3JY7gVfZcJvkCBHkb5RuNY1FCbBO3lkIi0CdXUCW1c7SXw==
dependencies:
"@vue/compiler-core" "3.3.2"
"@vue/shared" "3.3.2"
"@vue/compiler-sfc@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70"
@@ -307,6 +335,22 @@
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-sfc@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.2.tgz#d6467acba8446655bcee7e751441232e5ddebcbf"
integrity sha512-jG4jQy28H4BqzEKsQqqW65BZgmo3vzdLHTBjF+35RwtDdlFE+Fk1VWJYUnDMMqkFBo6Ye1ltSKVOMPgkzYj7SQ==
dependencies:
"@babel/parser" "^7.20.15"
"@vue/compiler-core" "3.3.2"
"@vue/compiler-dom" "3.3.2"
"@vue/compiler-ssr" "3.3.2"
"@vue/reactivity-transform" "3.3.2"
"@vue/shared" "3.3.2"
estree-walker "^2.0.2"
magic-string "^0.30.0"
postcss "^8.1.10"
source-map-js "^1.0.2"
"@vue/compiler-ssr@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz#bd20604b6e64ea15344d5b6278c4141191c983b2"
@@ -315,10 +359,18 @@
"@vue/compiler-dom" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/devtools-api@^6.4.5":
version "6.4.5"
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.4.5.tgz#d54e844c1adbb1e677c81c665ecef1a2b4bb8380"
integrity sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ==
"@vue/compiler-ssr@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.2.tgz#75ac4ccafa2d78c91d2e257ad243c86409493cc4"
integrity sha512-K8OfY5FQtZaSOJHHe8xhEfIfLrefL/Y9frv4k4NsyQL3+0lRKxr9QuJhfdBDjkl7Fhz8CzKh63mULvmOfx3l2w==
dependencies:
"@vue/compiler-dom" "3.3.2"
"@vue/shared" "3.3.2"
"@vue/devtools-api@^6.5.0":
version "6.5.0"
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
"@vue/reactivity-transform@3.2.45":
version "3.2.45"
@@ -331,6 +383,17 @@
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/reactivity-transform@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.2.tgz#e1991d52d7ecefb65b214d8a3385a9dbe2cca74c"
integrity sha512-iu2WaQvlJHdnONrsyv4ibIEnSsuKF+aHFngGj/y1lwpHQtalpVhKg9wsKMoiKXS9zPNjG9mNKzJS9vudvjzvyg==
dependencies:
"@babel/parser" "^7.20.15"
"@vue/compiler-core" "3.3.2"
"@vue/shared" "3.3.2"
estree-walker "^2.0.2"
magic-string "^0.30.0"
"@vue/reactivity@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz#412a45b574de601be5a4a5d9a8cbd4dee4662ff0"
@@ -338,6 +401,13 @@
dependencies:
"@vue/shared" "3.2.45"
"@vue/reactivity@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.2.tgz#c4ddc5087039070c0c11810f6bc1aa59c99f0cb5"
integrity sha512-yX8C4uTgg2Tdj+512EEMnMKbLveoITl7YdQX35AYgx8vBvQGszKiiCN46g4RY6/deeo/5DLbeUUGxCq1qWMf5g==
dependencies:
"@vue/shared" "3.3.2"
"@vue/runtime-core@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz#7ad7ef9b2519d41062a30c6fa001ec43ac549c7f"
@@ -346,6 +416,14 @@
"@vue/reactivity" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/runtime-core@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.2.tgz#7c89b30c44ad42a3256806a1e37c3cd18500d6d5"
integrity sha512-qSl95qj0BvKfcsO+hICqFEoLhJn6++HtsPxmTkkadFbuhe3uQfJ8HmQwvEr7xbxBd2rcJB6XOJg7nWAn/ymC5A==
dependencies:
"@vue/reactivity" "3.3.2"
"@vue/shared" "3.3.2"
"@vue/runtime-dom@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz#1a2ef6ee2ad876206fbbe2a884554bba2d0faf59"
@@ -355,6 +433,15 @@
"@vue/shared" "3.2.45"
csstype "^2.6.8"
"@vue/runtime-dom@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.2.tgz#b0bf7ce3fa9c181049ce783a0e13480a4f350c4b"
integrity sha512-+drStsJT+0mtgHdarT7cXZReCcTFfm6ptxMrz0kAW5hms6UNBd8Q1pi4JKlncAhu+Ld/TevsSp7pqAZxBBoGng==
dependencies:
"@vue/runtime-core" "3.3.2"
"@vue/shared" "3.3.2"
csstype "^3.1.1"
"@vue/server-renderer@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz#ca9306a0c12b0530a1a250e44f4a0abac6b81f3f"
@@ -363,32 +450,45 @@
"@vue/compiler-ssr" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/server-renderer@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.2.tgz#31dce9f76380762fc42df77f6f974c4098f179e6"
integrity sha512-QCwh6OGwJg6GDLE0fbQhRTR6tnU+XDJ1iCsTYHXBiezCXAhqMygFRij7BiLF4ytvvHcg5kX9joX5R5vP85++wg==
dependencies:
"@vue/compiler-ssr" "3.3.2"
"@vue/shared" "3.3.2"
"@vue/shared@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2"
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
"@vueuse/core@^9.9.0":
version "9.11.0"
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.11.0.tgz#4871e795567c142353c4ec62694c02bf7583e3bc"
integrity sha512-7yZJ8LNOssA8ZmeSjd4F+wbFBA4csiP4TiaXgruqg1H4PAtzSkv93PPwFLvQkSnfo3Bar+e+6QoRvWjhz7l2Xg==
dependencies:
"@types/web-bluetooth" "^0.0.16"
"@vueuse/metadata" "9.11.0"
"@vueuse/shared" "9.11.0"
vue-demi "*"
"@vue/shared@3.3.2":
version "3.3.2"
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.3.2.tgz#774cd9b4635ce801b70a3fc3713779a5ef5d77c3"
integrity sha512-0rFu3h8JbclbnvvKrs7Fe5FNGV9/5X2rPD7KmOzhLSUAiQH5//Hq437Gv0fR5Mev3u/nbtvmLl8XgwCU20/ZfQ==
"@vueuse/metadata@9.11.0":
version "9.11.0"
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.11.0.tgz#07133eb3d78cbea376b6ad216950b4bbfafd041c"
integrity sha512-HhtG2SWkcfZBLbamHdvLn7jKOCFpw/ifXjVTd5ilFkj98WVUk/3UTQ03wF1XIkuhSO4+b45hD2lfG9/GdKCF7w==
"@vueuse/shared@9.11.0":
version "9.11.0"
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.11.0.tgz#8cf7c64789040e90d0cb5c8ac73cc9d252f7306c"
integrity sha512-8lO7wD5abYxupKy2KynH1pSgP715ky6iCrWYb8aX2AuAVi9uHXj7qE1dw6BnmArSaLHci4x9iuzWPCpAzUkC/A==
"@vueuse/core@^10.1.0":
version "10.1.2"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-10.1.2.tgz#2499eadec36c5d7109338e3a2b73725040ae8011"
integrity sha512-roNn8WuerI56A5uiTyF/TEYX0Y+VKlhZAF94unUfdhbDUI+NfwQMn4FUnUscIRUhv3344qvAghopU4bzLPNFlA==
dependencies:
vue-demi "*"
"@types/web-bluetooth" "^0.0.17"
"@vueuse/metadata" "10.1.2"
"@vueuse/shared" "10.1.2"
vue-demi ">=0.14.0"
"@vueuse/metadata@10.1.2":
version "10.1.2"
resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.1.2.tgz#d8ffe557b1042efd03a0aa88540a00c25d193ee3"
integrity sha512-3mc5BqN9aU2SqBeBuWE7ne4OtXHoHKggNgxZR2K+zIW4YLsy6xoZ4/9vErQs6tvoKDX6QAqm3lvsrv0mczAwIQ==
"@vueuse/shared@10.1.2":
version "10.1.2"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-10.1.2.tgz#31d8733a217a6396eb67706319133bf62cdd8baa"
integrity sha512-1uoUTPBlgyscK9v6ScGeVYDDzlPSFXBlxuK7SfrDGyUTBiznb3mNceqhwvZHjtDRELZEN79V5uWPTF1VDV8svA==
dependencies:
vue-demi ">=0.14.0"
algoliasearch@^4.0.0:
version "4.14.3"
@@ -410,6 +510,11 @@ algoliasearch@^4.0.0:
"@algolia/requester-node-http" "4.14.3"
"@algolia/transporter" "4.14.3"
ansi-sequence-parser@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz#4d790f31236ac20366b23b3916b789e1bde39aed"
integrity sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==
body-scroll-lock@4.0.0-beta.0:
version "4.0.0-beta.0"
resolved "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-4.0.0-beta.0.tgz#4f78789d10e6388115c0460cd6d7d4dd2bbc4f7e"
@@ -420,33 +525,38 @@ csstype@^2.6.8:
resolved "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e"
integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
esbuild@^0.16.3:
version "0.16.12"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.16.12.tgz#60850b9ad2f103f1c4316be42c34d5023f27378d"
integrity sha512-eq5KcuXajf2OmivCl4e89AD3j8fbV+UTE9vczEzq5haA07U9oOTzBWlh3+6ZdjJR7Rz2QfWZ2uxZyhZxBgJ4+g==
csstype@^3.1.1:
version "3.1.2"
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
esbuild@^0.17.5:
version "0.17.19"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
optionalDependencies:
"@esbuild/android-arm" "0.16.12"
"@esbuild/android-arm64" "0.16.12"
"@esbuild/android-x64" "0.16.12"
"@esbuild/darwin-arm64" "0.16.12"
"@esbuild/darwin-x64" "0.16.12"
"@esbuild/freebsd-arm64" "0.16.12"
"@esbuild/freebsd-x64" "0.16.12"
"@esbuild/linux-arm" "0.16.12"
"@esbuild/linux-arm64" "0.16.12"
"@esbuild/linux-ia32" "0.16.12"
"@esbuild/linux-loong64" "0.16.12"
"@esbuild/linux-mips64el" "0.16.12"
"@esbuild/linux-ppc64" "0.16.12"
"@esbuild/linux-riscv64" "0.16.12"
"@esbuild/linux-s390x" "0.16.12"
"@esbuild/linux-x64" "0.16.12"
"@esbuild/netbsd-x64" "0.16.12"
"@esbuild/openbsd-x64" "0.16.12"
"@esbuild/sunos-x64" "0.16.12"
"@esbuild/win32-arm64" "0.16.12"
"@esbuild/win32-ia32" "0.16.12"
"@esbuild/win32-x64" "0.16.12"
"@esbuild/android-arm" "0.17.19"
"@esbuild/android-arm64" "0.17.19"
"@esbuild/android-x64" "0.17.19"
"@esbuild/darwin-arm64" "0.17.19"
"@esbuild/darwin-x64" "0.17.19"
"@esbuild/freebsd-arm64" "0.17.19"
"@esbuild/freebsd-x64" "0.17.19"
"@esbuild/linux-arm" "0.17.19"
"@esbuild/linux-arm64" "0.17.19"
"@esbuild/linux-ia32" "0.17.19"
"@esbuild/linux-loong64" "0.17.19"
"@esbuild/linux-mips64el" "0.17.19"
"@esbuild/linux-ppc64" "0.17.19"
"@esbuild/linux-riscv64" "0.17.19"
"@esbuild/linux-s390x" "0.17.19"
"@esbuild/linux-x64" "0.17.19"
"@esbuild/netbsd-x64" "0.17.19"
"@esbuild/openbsd-x64" "0.17.19"
"@esbuild/sunos-x64" "0.17.19"
"@esbuild/win32-arm64" "0.17.19"
"@esbuild/win32-ia32" "0.17.19"
"@esbuild/win32-x64" "0.17.19"
estree-walker@^2.0.2:
version "2.0.2"
@@ -458,25 +568,6 @@ fsevents@~2.3.2:
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
is-core-module@^2.9.0:
version "2.11.0"
resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
dependencies:
has "^1.0.3"
jsonc-parser@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
@@ -489,22 +580,39 @@ magic-string@^0.25.7:
dependencies:
sourcemap-codec "^1.4.8"
magic-string@^0.30.0:
version "0.30.0"
resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz#fd58a4748c5c4547338a424e90fa5dd17f4de529"
integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.13"
mark.js@8.11.1:
version "8.11.1"
resolved "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz#180f1f9ebef8b0e638e4166ad52db879beb2ffc5"
integrity sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==
minisearch@^6.0.1:
version "6.1.0"
resolved "https://registry.npmjs.org/minisearch/-/minisearch-6.1.0.tgz#6e74e743dbd0e88fa5ca52fef2391e0aa7055252"
integrity sha512-PNxA/X8pWk+TiqPbsoIYH0GQ5Di7m6326/lwU/S4mlo4wGQddIcf/V//1f9TB0V4j59b57b+HZxt8h3iMROGvg==
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
nanoid@^3.3.6:
version "3.3.6"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
postcss@^8.1.10, postcss@^8.4.20:
postcss@^8.1.10:
version "8.4.20"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56"
integrity sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==
@@ -513,32 +621,33 @@ postcss@^8.1.10, postcss@^8.4.20:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.4.23:
version "8.4.23"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab"
integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
preact@^10.0.0:
version "10.11.3"
resolved "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz#8a7e4ba19d3992c488b0785afcc0f8aa13c78d19"
integrity sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==
resolve@^1.22.1:
version "1.22.1"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
dependencies:
is-core-module "^2.9.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
rollup@^3.7.0:
version "3.9.0"
resolved "https://registry.npmjs.org/rollup/-/rollup-3.9.0.tgz#0ff7ab7cd71ce3a6ab140c5cf661f2b35eb6aab8"
integrity sha512-nGGylpmblyjTpF4lEUPgmOw6OVxRvnI6Iuuh6Lz4O/X66cVOX1XJSsqP1YamxQ+mPuFE7qJxLFDSCk8rNv5dDw==
rollup@^3.21.0:
version "3.21.8"
resolved "https://registry.npmjs.org/rollup/-/rollup-3.21.8.tgz#fc768008fe2c953f18210370fd70fe1ffff59e2c"
integrity sha512-SSFV2T2fWtQ/vvBip85u2Nr0GNKireabH9d7nXswBg+XSH+jbVDSYptRAEbCEsquhs503rpPA9POYAp0/Jhasw==
optionalDependencies:
fsevents "~2.3.2"
shiki@^0.12.1:
version "0.12.1"
resolved "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz#26fce51da12d055f479a091a5307470786f300cd"
integrity sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==
shiki@^0.14.2:
version "0.14.2"
resolved "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz#d51440800b701392b31ce2336036058e338247a1"
integrity sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==
dependencies:
ansi-sequence-parser "^1.1.0"
jsonc-parser "^3.2.0"
vscode-oniguruma "^1.7.0"
vscode-textmate "^8.0.0"
@@ -558,37 +667,33 @@ sourcemap-codec@^1.4.8:
resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
vite@^4.0.4:
version "4.0.4"
resolved "https://registry.npmmirror.com/vite/-/vite-4.0.4.tgz#4612ce0b47bbb233a887a54a4ae0c6e240a0da31"
integrity sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==
vite@^4.3.3:
version "4.3.6"
resolved "https://registry.npmjs.org/vite/-/vite-4.3.6.tgz#d129487dd9edf10ec79314e2e7891c60a2f86051"
integrity sha512-cqIyLSbA6gornMS659AXTVKF7cvSHMdKmJJwQ9DXq3lwsT1uZSdktuBRlpHQ8VnOWx0QHtjDwxPpGtyo9Fh/Qg==
dependencies:
esbuild "^0.16.3"
postcss "^8.4.20"
resolve "^1.22.1"
rollup "^3.7.0"
esbuild "^0.17.5"
postcss "^8.4.23"
rollup "^3.21.0"
optionalDependencies:
fsevents "~2.3.2"
vitepress@^1.0.0-alpha.40:
version "1.0.0-alpha.40"
resolved "https://registry.npmmirror.com/vitepress/-/vitepress-1.0.0-alpha.40.tgz#ef42de876c5b564c4cbf049415e8b03887da0f47"
integrity sha512-axhLI/wq/V9RjzFQZ00Ur0WhvoZXG7E1H88NxnglZm6wU/FAePP4bGaWPzU2WZwy3Nzpb9cbf1oXC+1DNgv9cQ==
vitepress@^1.0.0-alpha.75:
version "1.0.0-alpha.75"
resolved "https://registry.npmjs.org/vitepress/-/vitepress-1.0.0-alpha.75.tgz#fbd03ef80b3877d41d0abd369560b7ea1124c017"
integrity sha512-twpPZ/6UnDR8X0Nmj767KwKhXlTQQM9V/J1i2BP9ryO29/w4hpxBfEum6nvfpNhJ4H3h+cIhwzAK/e9crZ6HEQ==
dependencies:
"@docsearch/css" "^3.3.1"
"@docsearch/js" "^3.3.1"
"@vitejs/plugin-vue" "^4.0.0"
"@vue/devtools-api" "^6.4.5"
"@vueuse/core" "^9.9.0"
"@docsearch/css" "^3.3.4"
"@docsearch/js" "^3.3.4"
"@vitejs/plugin-vue" "^4.2.1"
"@vue/devtools-api" "^6.5.0"
"@vueuse/core" "^10.1.0"
body-scroll-lock "4.0.0-beta.0"
shiki "^0.12.1"
vite "^4.0.4"
vue "^3.2.45"
mark.js "8.11.1"
minisearch "^6.0.1"
shiki "^0.14.2"
vite "^4.3.3"
vue "^3.2.47"
vscode-oniguruma@^1.7.0:
version "1.7.0"
@@ -600,10 +705,10 @@ vscode-textmate@^8.0.0:
resolved "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d"
integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==
vue-demi@*:
version "0.13.11"
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
vue-demi@>=0.14.0:
version "0.14.1"
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.1.tgz#1ed9af03a27642762bfed83d8750805302d0398d"
integrity sha512-rt+yuCtXvscYot9SQQj3WKZJVSriPNqVkpVBNEHPzSgBv7QIYzsS410VqVgvx8f9AAPgjg+XPKvmV3vOqqkJQQ==
vue@^3.2.45:
version "3.2.45"
@@ -615,3 +720,14 @@ vue@^3.2.45:
"@vue/runtime-dom" "3.2.45"
"@vue/server-renderer" "3.2.45"
"@vue/shared" "3.2.45"
vue@^3.2.47:
version "3.3.2"
resolved "https://registry.npmjs.org/vue/-/vue-3.3.2.tgz#407f0057a7a154d836b66f94ce81779d0c2cafbc"
integrity sha512-98hJcAhyDwZoOo2flAQBSPVYG/o0HA9ivIy2ktHshjE+6/q8IMQ+kvDKQzOZTFPxvnNMcGM+zS2A00xeZMA7tA==
dependencies:
"@vue/compiler-dom" "3.3.2"
"@vue/compiler-sfc" "3.3.2"
"@vue/runtime-dom" "3.3.2"
"@vue/server-renderer" "3.3.2"
"@vue/shared" "3.3.2"