You've already forked KernelSU
mirror of
https://github.com/tiann/KernelSU.git
synced 2025-08-27 23:46:34 +00:00
Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ad27c5999 | ||
|
|
5b27f6c010 | ||
|
|
be44fad288 | ||
|
|
2a5fb76f95 | ||
|
|
5db7075432 | ||
|
|
1408175a35 | ||
|
|
ab1dc894e1 | ||
|
|
c5bc1c8b15 | ||
|
|
6d1ee60d67 | ||
|
|
a58e929205 | ||
|
|
53be8612c8 | ||
|
|
c7f6a7d11b | ||
|
|
e9011041c5 | ||
|
|
9803371fdb | ||
|
|
710edb72fa | ||
|
|
a4ddf59562 | ||
|
|
37dc9a27a7 | ||
|
|
27ccfa6395 | ||
|
|
116bc56cfe | ||
|
|
9ae0126be5 | ||
|
|
e8755f8ae0 | ||
|
|
6ba2bd3af9 | ||
|
|
4c5e485e76 | ||
|
|
05c6892f43 | ||
|
|
670a20c37f | ||
|
|
75509aba72 | ||
|
|
887f02e742 | ||
|
|
ef8da39d34 | ||
|
|
b7c759ece1 | ||
|
|
019da4a634 | ||
|
|
33aa6de50b | ||
|
|
0b3688c3b1 | ||
|
|
076e5d3655 | ||
|
|
c9608af0c8 | ||
|
|
908fbadaf5 | ||
|
|
ee97fdfc56 | ||
|
|
4ac137313f | ||
|
|
11d0029a4b | ||
|
|
8af5a9038b | ||
|
|
5d449988fb | ||
|
|
e969563df0 | ||
|
|
990626cf7d | ||
|
|
fc77ca989f | ||
|
|
2ce3976023 | ||
|
|
63ec531814 | ||
|
|
a4b55b30ca | ||
|
|
807556f361 | ||
|
|
2d854f2f37 | ||
|
|
5980c113fe | ||
|
|
1491465b55 | ||
|
|
728380222a | ||
|
|
005404f552 | ||
|
|
b55c229038 | ||
|
|
32538c9833 | ||
|
|
b31fc47197 | ||
|
|
5003824fa8 | ||
|
|
eea75b72a4 | ||
|
|
82d5ec3cc1 | ||
|
|
75721be8c0 | ||
|
|
de72eedb46 | ||
|
|
66827ab7de | ||
|
|
2a33433272 | ||
|
|
581dff8a5f | ||
|
|
fc425cbba2 | ||
|
|
87f55c1acb | ||
|
|
68d639e325 | ||
|
|
89f6cd044e | ||
|
|
bd3a1291da | ||
|
|
3abb7e4ca2 | ||
|
|
41265b0203 | ||
|
|
f2cb841b8a | ||
|
|
c69da29081 | ||
|
|
e304ef8cfb | ||
|
|
2ce76351da | ||
|
|
66cbd931a7 | ||
|
|
07bc28e386 | ||
|
|
2ef4ffe5eb | ||
|
|
128e7e394e | ||
|
|
998dc9b94b | ||
|
|
c6dafb1333 | ||
|
|
8ae7299d59 | ||
|
|
8f1b9c579b | ||
|
|
4b6573b521 | ||
|
|
325e843569 | ||
|
|
d014947a54 | ||
|
|
8858cc899e | ||
|
|
8f3e59803f | ||
|
|
95044bb551 | ||
|
|
b56448a929 | ||
|
|
c2b981dbdb | ||
|
|
28fb482720 | ||
|
|
d744a705a8 | ||
|
|
c62b89f02b | ||
|
|
f876b0114e | ||
|
|
9965988f26 | ||
|
|
828bb6fbb4 | ||
|
|
10d8d9efcd | ||
|
|
e59f3333cb | ||
|
|
31a9189d80 | ||
|
|
d162221fac | ||
|
|
0cdca0d053 | ||
|
|
4c934d460b | ||
|
|
76612b9cf7 | ||
|
|
9cf8ac9c51 | ||
|
|
b80e06256d | ||
|
|
08d9e5d6bc | ||
|
|
ed0cfd231e | ||
|
|
538d3f06f4 | ||
|
|
f5d3fb6217 | ||
|
|
ffa3579e6f | ||
|
|
c7adb8e3b1 | ||
|
|
c1427f658a | ||
|
|
eccce7b31f | ||
|
|
f81caf75a9 | ||
|
|
d4680c6de7 |
31
.github/workflows/build-debug-kernel.yml
vendored
Normal file
31
.github/workflows/build-debug-kernel.yml
vendored
Normal 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
|
||||
6
.github/workflows/build-kernel-a12.yml
vendored
6
.github/workflows/build-kernel-a12.yml
vendored
@@ -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"
|
||||
|
||||
23
.github/workflows/build-kernel-a13.yml
vendored
23
.github/workflows/build-kernel-a13.yml
vendored
@@ -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 }}
|
||||
|
||||
17
.github/workflows/build-kernel-wsa.yml
vendored
17
.github/workflows/build-kernel-wsa.yml
vendored
@@ -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"
|
||||
|
||||
|
||||
12
.github/workflows/gki-kernel.yml
vendored
12
.github/workflows/gki-kernel.yml
vendored
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
42
README_JP.md
Normal 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
47
README_PT-BR.md
Normal 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.
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
66
kernel/ksu.h
66
kernel/ksu.h
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define KSU_COMPAT_USE_SELINUX_STATE
|
||||
#endif
|
||||
|
||||
void setup_selinux();
|
||||
void setup_selinux(const char *);
|
||||
|
||||
void setenforce(bool);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.'
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
105
manager/app/src/main/java/me/weishu/kernelsu/Natives.kt
Normal file
105
manager/app/src/main/java/me/weishu/kernelsu/Natives.kt
Normal 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("")
|
||||
}
|
||||
}
|
||||
@@ -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", "Don’t clear set-user-ID and set-group-ID permission bits when a file is modified; set the set-group-ID bit for a file whose GID does not match the filesystem or any of the supplementary GIDs of the calling process"),
|
||||
CAP_KILL(5, "KILL", "Bypass permission checks for sending signals (see kill(2))."),
|
||||
CAP_SETGID(6, "SETGID", "Make arbitrary manipulations of process GIDs and supplementary GID list; allow setgid(2) manipulation of the caller’s effective and real group IDs"),
|
||||
CAP_SETUID(7, "SETUID", "Make arbitrary manipulations of process UIDs (setuid(2), setreuid(2), setresuid(2), setfsuid(2)); allow changing the current process user IDs; allow changing of the current process group ID to any value in the system’s range of legal group IDs"),
|
||||
CAP_SETPCAP(8, "SETPCAP", "If file capabilities are supported: grant or remove any capability in the caller’s permitted capability set to or from any other process. (This property supersedes the obsolete notion of giving a process all capabilities by granting all capabilities in its permitted set, and of removing all capabilities from a process by granting no capabilities in its permitted set. It does not permit any actions that were not permitted before.)"),
|
||||
CAP_LINUX_IMMUTABLE(9, "LINUX_IMMUTABLE", "Set the FS_APPEND_FL and FS_IMMUTABLE_FL inode flags (see chattr(1))."),
|
||||
CAP_NET_BIND_SERVICE(10, "NET_BIND_SERVICE", "Bind a socket to Internet domain"),
|
||||
CAP_NET_BROADCAST(11, "NET_BROADCAST", "Make socket broadcasts, and listen to multicasts"),
|
||||
CAP_NET_ADMIN(12, "NET_ADMIN", "Perform various network-related operations: interface configuration, administration of IP firewall, masquerading, and accounting, modify routing tables, bind to any address for transparent proxying, set type-of-service (TOS), clear driver statistics, set promiscuous mode, enabling multicasting, use setsockopt(2) to set the following socket options: SO_DEBUG, SO_MARK, SO_PRIORITY (for a priority outside the range 0 to 6), SO_RCVBUFFORCE, and SO_SNDBUFFORCE"),
|
||||
CAP_NET_RAW(13, "NET_RAW", "Use RAW and PACKET sockets"),
|
||||
CAP_IPC_LOCK(14, "IPC_LOCK", "Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2))"),
|
||||
CAP_IPC_OWNER(15, "IPC_OWNER", "Bypass permission checks for operations on System V IPC objects"),
|
||||
CAP_SYS_MODULE(16, "SYS_MODULE", "Load and unload kernel modules (see init_module(2) and delete_module(2)); in kernels before 2.6.25, this also granted rights for various other operations related to kernel modules"),
|
||||
CAP_SYS_RAWIO(17, "SYS_RAWIO", "Perform I/O port operations (iopl(2) and ioperm(2)); access /proc/kcore"),
|
||||
CAP_SYS_CHROOT(18, "SYS_CHROOT", "Use chroot(2)"),
|
||||
CAP_SYS_PTRACE(19, "SYS_PTRACE", "Trace arbitrary processes using ptrace(2)"),
|
||||
CAP_SYS_PACCT(20, "SYS_PACCT", "Use acct(2)"),
|
||||
CAP_SYS_ADMIN(21, "SYS_ADMIN", "Perform a range of system administration operations including: quotactl(2), mount(2), umount(2), swapon(2), swapoff(2), sethostname(2), and setdomainname(2); set and modify process resource limits (setrlimit(2)); perform various network-related operations (e.g., setting privileged socket options, enabling multicasting, interface configuration); perform various IPC operations (e.g., SysV semaphores, POSIX message queues, System V shared memory); allow reboot and kexec_load(2); override /proc/sys kernel tunables; perform ptrace(2) PTRACE_SECCOMP_GET_FILTER operation; perform some tracing and debugging operations (see ptrace(2)); administer the lifetime of kernel tracepoints (tracefs(5)); perform the KEYCTL_CHOWN and KEYCTL_SETPERM keyctl(2) operations; perform the following keyctl(2) operations: KEYCTL_CAPABILITIES, KEYCTL_CAPSQUASH, and KEYCTL_PKEY_ OPERATIONS; set state for the Extensible Authentication Protocol (EAP) kernel module; and override the RLIMIT_NPROC resource limit; allow ioperm/iopl access to I/O ports"),
|
||||
CAP_SYS_BOOT(22, "SYS_BOOT", "Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution"),
|
||||
CAP_SYS_NICE(23, "SYS_NICE", "Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes; set real-time scheduling policies for calling process, and set scheduling policies and priorities for arbitrary processes (sched_setscheduler(2), sched_setparam(2)"),
|
||||
CAP_SYS_RESOURCE(24, "SYS_RESOURCE", "Override resource Limits. Set resource limits (setrlimit(2), prlimit(2)), override quota limits (quota(2), quotactl(2)), override reserved space on ext2 filesystem (ext2_ioctl(2)), override size restrictions on IPC message queues (msg(2)) and system V shared memory segments (shmget(2)), and override the /proc/sys/fs/pipe-size-max limit"),
|
||||
CAP_SYS_TIME(25, "SYS_TIME", "Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock"),
|
||||
CAP_SYS_TTY_CONFIG(26, "SYS_TTY_CONFIG", "Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals"),
|
||||
CAP_MKNOD(27, "MKNOD", "Create special files using mknod(2)"),
|
||||
CAP_LEASE(28, "LEASE", "Establish leases on arbitrary files (see fcntl(2))"),
|
||||
CAP_AUDIT_WRITE(29, "AUDIT_WRITE", "Write records to kernel auditing log"),
|
||||
CAP_AUDIT_CONTROL(30, "AUDIT_CONTROL", "Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules"),
|
||||
CAP_SETFCAP(31, "SETFCAP", "If file capabilities are supported: grant or remove any capability in any capability set to any file"),
|
||||
CAP_MAC_OVERRIDE(32, "MAC_OVERRIDE", "Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM)"),
|
||||
CAP_MAC_ADMIN(33, "MAC_ADMIN", "Allow MAC configuration or state changes. Implemented for the Smack LSM"),
|
||||
CAP_SYSLOG(34, "SYSLOG", "Perform privileged syslog(2) operations. See syslog(2) for information on which operations require privilege"),
|
||||
CAP_WAKE_ALARM(35, "WAKE_ALARM", "Trigger something that will wake up the system"),
|
||||
CAP_BLOCK_SUSPEND(36, "BLOCK_SUSPEND", "Employ features that can block system suspend"),
|
||||
CAP_AUDIT_READ(37, "AUDIT_READ", "Allow reading the audit log via a multicast netlink socket"),
|
||||
CAP_PERFMON(38, "PERFMON", "Allow performance monitoring via perf_event_open(2)"),
|
||||
CAP_BPF(39, "BPF", "Allow BPF operations via bpf(2)"),
|
||||
CAP_CHECKPOINT_RESTORE(40, "CHECKPOINT_RESTORE", "Allow processes to be checkpointed via checkpoint/restore in user namespace(2)"),
|
||||
}
|
||||
@@ -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"),
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,7 +35,6 @@ import java.util.*
|
||||
* @author weishu
|
||||
* @date 2023/1/1.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@Destination
|
||||
fun InstallScreen(navigator: DestinationsNavigator, uri: Uri) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
67
manager/app/src/main/res/values-fa/strings.xml
Normal file
67
manager/app/src/main/res/values-fa/strings.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
74
manager/app/src/main/res/values-pt-rBR/strings.xml
Normal file
74
manager/app/src/main/res/values-pt-rBR/strings.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAIN
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
})
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
|
||||
60
website/docs/.vitepress/locales/ja_JP.ts
Normal file
60
website/docs/.vitepress/locales/ja_JP.ts
Normal 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' },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
26
website/docs/ja_JP/guide/difference-with-magisk.md
Normal file
26
website/docs/ja_JP/guide/difference-with-magisk.md
Normal 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` 変数をサポートしています。
|
||||
67
website/docs/ja_JP/guide/faq.md
Normal file
67
website/docs/ja_JP/guide/faq.md
Normal 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 と全く異なるため、カーネルは自分でビルドする必要があります。
|
||||
7
website/docs/ja_JP/guide/hidden-features.md
Normal file
7
website/docs/ja_JP/guide/hidden-features.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# 隠し機能
|
||||
|
||||
## .ksurc
|
||||
|
||||
デフォルトでは `/system/bin/sh` は `/system/etc/mkshrc` を読み込みます。
|
||||
|
||||
`/data/adb/ksu/.ksurc` ファイルを作成することで、カスタマイズした rc ファイルを su に読み込ませられます。
|
||||
169
website/docs/ja_JP/guide/installation.md
Normal file
169
website/docs/ja_JP/guide/installation.md
Normal 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 が提供するカーネルを書き込む
|
||||
255
website/docs/ja_JP/guide/module.md
Normal file
255
website/docs/ja_JP/guide/module.md
Normal 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` シェルで「スタンドアロンモード」を有効にした状態で実行されます。
|
||||
50
website/docs/ja_JP/guide/rescue-from-bootloop.md
Normal file
50
website/docs/ja_JP/guide/rescue-from-bootloop.md
Normal 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. アフターセールスサービスに問い合わせする
|
||||
30
website/docs/ja_JP/guide/unofficially-support-devices.md
Normal file
30
website/docs/ja_JP/guide/unofficially-support-devices.md
Normal 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>
|
||||
21
website/docs/ja_JP/guide/what-is-kernelsu.md
Normal file
21
website/docs/ja_JP/guide/what-is-kernelsu.md
Normal 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)
|
||||
29
website/docs/ja_JP/index.md
Normal file
29
website/docs/ja_JP/index.md
Normal 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 でライセンスされたオープンソースプロジェクトです。
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user