Compare commits

...

87 Commits

Author SHA1 Message Date
igor
4270fd8b1e update translations in docs and manager (#571)
Co-authored-by: Rifat Azad <33044977+rifsxd@users.noreply.github.com>
2025-06-27 22:51:05 +06:00
роизен
764dbc3782 Improve README_UA (#569)
* Improve README_UA

* Update README_UA.md
2025-06-27 22:48:49 +06:00
роизен
080ab9a952 Update Uk (#566) 2025-06-27 22:48:32 +06:00
AxelPLN(Axel Yinjia Huang)
a9cab5ccfd fix: complete the text of the module labels (#558)
- replace the string Resource ID of uninstalled & those can be updated modules
2025-06-27 22:48:18 +06:00
Rifat Azad
3d44602537 manager: check additional zygisk 64 libs instead of only 32 bit lib for zygisk detection 2025-06-27 21:13:25 +06:00
Eren
88eb2a2723 Improve README (#562)
* Improve README

* Update README.md
2025-06-27 18:39:33 +06:00
NkBe
e272e557b0 manger: fix lkm detection (#2654)
原因请看
https://github.com/SukiSU-Ultra/SukiSU-Ultra/pull/217#issuecomment-3004461174

文中介绍的是lkm的问题 但实测下来gki也有这样的问题 但修复方法通用
2025-06-27 18:02:42 +06:00
Rifat Azad
2a4794e422 manager: implemented zygisk required label for module card 2025-06-27 18:02:34 +06:00
mr_vokintos
818bdbead6 Update Russian (#557) 2025-06-27 14:37:54 +06:00
Nhật Minh
76249fa67d Update strings.xml (#553) 2025-06-27 14:37:39 +06:00
AxelPLN(Axel Yinjia Huang)
ed50b57b57 fix: update manager translation for zh-rCN & zh-rTW (#556)
* docs: complete text for README_CN & README_TW

* fix: update manager translation for zh-rCN & zh-rTW

also complete some text for module label and language switching functionality
2025-06-27 14:37:10 +06:00
Rifat Azad
f05f776a08 manager: fix Condition is always 'true' 2025-06-27 12:02:16 +06:00
Axel Yinjia Huang
c9b79c3016 manager: add basic language switching functionality 2025-06-27 11:37:12 +06:00
Rifat Azad
3ff10d6622 susfsd: remove deprecated CONFIG_KSU_SUSFS_SUS_OVERLAYFS and add CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT 2025-06-26 23:55:29 +06:00
Rifat Azad
b95d2b69b6 manager: add vendor_boot suggestion for LKM patch 2025-06-26 23:44:46 +06:00
Rifat Azad
2cd8453877 Revert "manager: move the wx platform init to the Application class so it starts as soon as the app process launches"
This reverts commit d5c4f85d73.
2025-06-26 23:25:37 +06:00
роизен
b7300b0525 Update translation for UK (#552) 2025-06-26 22:02:09 +06:00
kam821
3a278d560f Update Polish translation (#521)
* Update Polish translation

- Improve cosmetics / context-sensitive lines

* Update Polish translation - backup/restore

- Cosmetics, worth considering changing it in the future to keep option name in one line.

* Update Polish translation - homepage

- Shortened translation to work around broken formatting
2025-06-26 20:01:55 +06:00
igor
03fa2eddb2 Update portuguese translation (#518) 2025-06-26 17:43:27 +06:00
Rifat Azad
b74e953ad2 ksud: implement patching LKM vendor_ramdisk/ramdisk.cpio for compatibily needed for some pixel devices 2025-06-26 10:33:58 +06:00
Rifat Azad
39717b0a3f Revert "ksud: rust FMT"
This reverts commit 78eb3b0b22.
2025-06-25 17:58:52 +06:00
Rifat Azad
7f0eccd3d5 ksud: handle errors and non compatible ramdisk 2025-06-25 17:43:59 +06:00
Rifat Azad
78eb3b0b22 ksud: rust FMT 2025-06-25 13:25:28 +06:00
Rifat Azad
39f20bf573 manager: fix uneven spacing for empty label for superuser app section with DEFAULT label (fix #547) 2025-06-25 12:54:13 +06:00
Rifat Azad
092eb1b23d manager: use busybox for tar and du commands as not all devices has it most likely and if module size is 0 bytes then show null 2025-06-24 17:56:50 +06:00
Rifat Azad
30e2ed5db5 ksud: third test properly check if vendor is already patched or not for lkm restoration and also handle magisk patched vendor boot 2025-06-24 16:47:44 +06:00
Rifat Azad
dc7ae2db5f manager: fix status card startActivity intent fallback to not allow lkm install on non gki 2025-06-24 09:53:20 +06:00
Rifat Azad
b3b7ef1cb3 manager: dont show developer options and banner toggle when ksuversion is null 2025-06-24 09:26:14 +06:00
Rifat Azad
4de4d1e091 ksud: second test of vendor_boot patching now handling vendor_boot partition and restore partition 2025-06-24 09:17:24 +06:00
Rifat Azad
0beea57ab7 ksud: test vendor_boot patching for some newer devices 2025-06-23 18:17:46 +06:00
Rifat Azad
49aee1ff4c manager: remove susfs info from status card and merge it to info card 2025-06-21 17:01:21 +06:00
Rifat Azad
f7a3699fe3 manager: show module update count as badge in bottom bar instead of status card 2025-06-21 12:44:29 +06:00
5ec1cff
66d42de599 app: persist show system app settings 2025-06-20 00:54:23 +06:00
Kaorun
d562594ae1 Update Module.kt 2025-06-19 13:35:05 +06:00
Rifat Azad
02afc6710c manager: show sucmpat when both sucompat is disabled and sus_su enabled 2025-06-18 20:23:35 +06:00
Caner Karaca
9d9f9ed5d5 Update 2025-06-16 06:00:17 +06:00
kam821
b3b6320946 Update Polish translation
- Added missing strings
2025-06-16 05:56:46 +06:00
Rifat Azad
d43b8320ad manager: minor improvements 2025-06-16 05:55:14 +06:00
dependabot[bot]
a2260ae330 build(deps): bump the crates group across 1 directory with 27 updates
Bumps the crates group with 22 updates in the /userspace/ksud_overlayfs directory:

| Package | From | To |
| --- | --- | --- |
| [clap](https://github.com/clap-rs/clap) | `4.5.38` | `4.5.40` |
| [which](https://github.com/harryfei/which-rs) | `7.0.3` | `8.0.0` |
| [getopts](https://github.com/rust-lang/getopts) | `0.2.21` | `0.2.23` |
| [adler2](https://github.com/oyvindln/adler2) | `2.0.0` | `2.0.1` |
| [anstream](https://github.com/rust-cli/anstyle) | `0.6.18` | `0.6.19` |
| [anstyle](https://github.com/rust-cli/anstyle) | `1.0.10` | `1.0.11` |
| [anstyle-parse](https://github.com/rust-cli/anstyle) | `0.2.6` | `0.2.7` |
| [anstyle-query](https://github.com/rust-cli/anstyle) | `1.1.2` | `1.1.3` |
| [anstyle-wincon](https://github.com/rust-cli/anstyle) | `3.0.8` | `3.0.9` |
| [bumpalo](https://github.com/fitzgen/bumpalo) | `3.17.0` | `3.18.1` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.23` | `1.2.26` |
| [clap_lex](https://github.com/clap-rs/clap) | `0.7.4` | `0.7.5` |
| [colorchoice](https://github.com/rust-cli/anstyle) | `1.0.3` | `1.0.4` |
| [flate2](https://github.com/rust-lang/flate2-rs) | `1.1.1` | `1.1.2` |
| [memchr](https://github.com/BurntSushi/memchr) | `2.7.4` | `2.7.5` |
| [miniz_oxide](https://github.com/Frommi/miniz_oxide) | `0.8.8` | `0.8.9` |
| [once_cell_polyfill](https://github.com/polyfill-rs/once_cell_polyfill) | `1.70.0` | `1.70.1` |
| [rustc-demangle](https://github.com/rust-lang/rustc-demangle) | `0.1.24` | `0.1.25` |
| [rustversion](https://github.com/dtolnay/rustversion) | `1.0.20` | `1.0.21` |
| [syn](https://github.com/dtolnay/syn) | `2.0.101` | `2.0.102` |
| [tokio](https://github.com/tokio-rs/tokio) | `1.45.0` | `1.45.1` |
| [windows-link](https://github.com/microsoft/windows-rs) | `0.1.1` | `0.1.2` |



Updates `clap` from 4.5.38 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.38...clap_complete-v4.5.40)

Updates `which` from 7.0.3 to 8.0.0
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/harryfei/which-rs/compare/7.0.3...8.0.0)

Updates `getopts` from 0.2.21 to 0.2.23
- [Release notes](https://github.com/rust-lang/getopts/releases)
- [Changelog](https://github.com/rust-lang/getopts/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/getopts/compare/v0.2.21...v0.2.23)

Updates `adler2` from 2.0.0 to 2.0.1
- [Changelog](https://github.com/oyvindln/adler2/blob/main/CHANGELOG.md)
- [Commits](https://github.com/oyvindln/adler2/commits)

Updates `anstream` from 0.6.18 to 0.6.19
- [Commits](https://github.com/rust-cli/anstyle/compare/anstream-v0.6.18...anstream-v0.6.19)

Updates `anstyle` from 1.0.10 to 1.0.11
- [Commits](https://github.com/rust-cli/anstyle/compare/v1.0.10...v1.0.11)

Updates `anstyle-parse` from 0.2.6 to 0.2.7
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-parse-v0.2.6...anstyle-parse-v0.2.7)

Updates `anstyle-query` from 1.1.2 to 1.1.3
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-query-v1.1.2...anstyle-query-v1.1.3)

Updates `anstyle-wincon` from 3.0.8 to 3.0.9
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-wincon-v3.0.8...anstyle-wincon-v3.0.9)

Updates `bumpalo` from 3.17.0 to 3.18.1
- [Changelog](https://github.com/fitzgen/bumpalo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fitzgen/bumpalo/compare/3.17.0...v3.18.1)

Updates `cc` from 1.2.23 to 1.2.26
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.23...cc-v1.2.26)

Updates `clap_builder` from 4.5.38 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.38...v4.5.40)

Updates `clap_derive` from 4.5.32 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.32...v4.5.40)

Updates `clap_lex` from 0.7.4 to 0.7.5
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.7.4...clap_lex-v0.7.5)

Updates `colorchoice` from 1.0.3 to 1.0.4
- [Commits](https://github.com/rust-cli/anstyle/compare/colorchoice-v1.0.3...colorchoice-v1.0.4)

Updates `flate2` from 1.1.1 to 1.1.2
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.1...1.1.2)

Updates `libz-rs-sys` from 0.5.0 to 0.5.1
- [Release notes](https://github.com/trifectatechfoundation/zlib-rs/releases)
- [Changelog](https://github.com/trifectatechfoundation/zlib-rs/blob/main/docs/release.md)
- [Commits](https://github.com/trifectatechfoundation/zlib-rs/compare/v0.5.0...v0.5.1)

Updates `memchr` from 2.7.4 to 2.7.5
- [Commits](https://github.com/BurntSushi/memchr/compare/2.7.4...2.7.5)

Updates `miniz_oxide` from 0.8.8 to 0.8.9
- [Changelog](https://github.com/Frommi/miniz_oxide/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Frommi/miniz_oxide/commits)

Updates `once_cell_polyfill` from 1.70.0 to 1.70.1
- [Changelog](https://github.com/polyfill-rs/once_cell_polyfill/blob/v1.70.1/CHANGELOG.md)
- [Commits](https://github.com/polyfill-rs/once_cell_polyfill/compare/v1.70.0...v1.70.1)

Updates `rustc-demangle` from 0.1.24 to 0.1.25
- [Commits](https://github.com/rust-lang/rustc-demangle/commits)

Updates `rustversion` from 1.0.20 to 1.0.21
- [Release notes](https://github.com/dtolnay/rustversion/releases)
- [Commits](https://github.com/dtolnay/rustversion/compare/1.0.20...1.0.21)

Updates `syn` from 2.0.101 to 2.0.102
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.101...2.0.102)

Updates `tokio` from 1.45.0 to 1.45.1
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.0...tokio-1.45.1)

Updates `unicode-width` from 0.1.14 to 0.2.1
- [Commits](https://github.com/unicode-rs/unicode-width/compare/v0.1.14...v0.2.1)

Updates `windows-link` from 0.1.1 to 0.1.2
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

Updates `zlib-rs` from 0.5.0 to 0.5.1
- [Release notes](https://github.com/trifectatechfoundation/zlib-rs/releases)
- [Changelog](https://github.com/trifectatechfoundation/zlib-rs/blob/main/docs/release.md)
- [Commits](https://github.com/trifectatechfoundation/zlib-rs/compare/v0.5.0...v0.5.1)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.40
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: which
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: crates
- dependency-name: getopts
  dependency-version: 0.2.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: adler2
  dependency-version: 2.0.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstream
  dependency-version: 0.6.19
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle
  dependency-version: 1.0.11
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle-parse
  dependency-version: 0.2.7
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle-query
  dependency-version: 1.1.3
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle-wincon
  dependency-version: 3.0.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: bumpalo
  dependency-version: 3.18.1
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: crates
- dependency-name: cc
  dependency-version: 1.2.26
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: clap_builder
  dependency-version: 4.5.40
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: clap_derive
  dependency-version: 4.5.40
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: clap_lex
  dependency-version: 0.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: colorchoice
  dependency-version: 1.0.4
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: flate2
  dependency-version: 1.1.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: libz-rs-sys
  dependency-version: 0.5.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: memchr
  dependency-version: 2.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: miniz_oxide
  dependency-version: 0.8.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: once_cell_polyfill
  dependency-version: 1.70.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: rustc-demangle
  dependency-version: 0.1.25
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: rustversion
  dependency-version: 1.0.21
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: syn
  dependency-version: 2.0.102
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: tokio
  dependency-version: 1.45.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: unicode-width
  dependency-version: 0.2.1
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: crates
- dependency-name: windows-link
  dependency-version: 0.1.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: zlib-rs
  dependency-version: 0.5.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-15 23:31:53 +06:00
dependabot[bot]
aa221acad1 build(deps): bump the crates group across 1 directory with 28 updates
Bumps the crates group with 23 updates in the /userspace/ksud_magic directory:

| Package | From | To |
| --- | --- | --- |
| [clap](https://github.com/clap-rs/clap) | `4.5.38` | `4.5.40` |
| [which](https://github.com/harryfei/which-rs) | `7.0.3` | `8.0.0` |
| [getopts](https://github.com/rust-lang/getopts) | `0.2.21` | `0.2.23` |
| [adler2](https://github.com/oyvindln/adler2) | `2.0.0` | `2.0.1` |
| [anstream](https://github.com/rust-cli/anstyle) | `0.6.18` | `0.6.19` |
| [anstyle](https://github.com/rust-cli/anstyle) | `1.0.10` | `1.0.11` |
| [anstyle-parse](https://github.com/rust-cli/anstyle) | `0.2.6` | `0.2.7` |
| [anstyle-query](https://github.com/rust-cli/anstyle) | `1.1.2` | `1.1.3` |
| [anstyle-wincon](https://github.com/rust-cli/anstyle) | `3.0.8` | `3.0.9` |
| [bumpalo](https://github.com/fitzgen/bumpalo) | `3.17.0` | `3.18.1` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.23` | `1.2.26` |
| [cfg-if](https://github.com/rust-lang/cfg-if) | `1.0.0` | `1.0.1` |
| [clap_lex](https://github.com/clap-rs/clap) | `0.7.4` | `0.7.5` |
| [colorchoice](https://github.com/rust-cli/anstyle) | `1.0.3` | `1.0.4` |
| [flate2](https://github.com/rust-lang/flate2-rs) | `1.1.1` | `1.1.2` |
| [memchr](https://github.com/BurntSushi/memchr) | `2.7.4` | `2.7.5` |
| [miniz_oxide](https://github.com/Frommi/miniz_oxide) | `0.8.8` | `0.8.9` |
| [once_cell_polyfill](https://github.com/polyfill-rs/once_cell_polyfill) | `1.70.0` | `1.70.1` |
| [rustc-demangle](https://github.com/rust-lang/rustc-demangle) | `0.1.24` | `0.1.25` |
| [rustversion](https://github.com/dtolnay/rustversion) | `1.0.20` | `1.0.21` |
| [syn](https://github.com/dtolnay/syn) | `2.0.101` | `2.0.102` |
| [tokio](https://github.com/tokio-rs/tokio) | `1.45.0` | `1.45.1` |
| [windows-link](https://github.com/microsoft/windows-rs) | `0.1.1` | `0.1.2` |



Updates `clap` from 4.5.38 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.38...clap_complete-v4.5.40)

Updates `which` from 7.0.3 to 8.0.0
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/harryfei/which-rs/compare/7.0.3...8.0.0)

Updates `getopts` from 0.2.21 to 0.2.23
- [Release notes](https://github.com/rust-lang/getopts/releases)
- [Changelog](https://github.com/rust-lang/getopts/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/getopts/compare/v0.2.21...v0.2.23)

Updates `adler2` from 2.0.0 to 2.0.1
- [Changelog](https://github.com/oyvindln/adler2/blob/main/CHANGELOG.md)
- [Commits](https://github.com/oyvindln/adler2/commits)

Updates `anstream` from 0.6.18 to 0.6.19
- [Commits](https://github.com/rust-cli/anstyle/compare/anstream-v0.6.18...anstream-v0.6.19)

Updates `anstyle` from 1.0.10 to 1.0.11
- [Commits](https://github.com/rust-cli/anstyle/compare/v1.0.10...v1.0.11)

Updates `anstyle-parse` from 0.2.6 to 0.2.7
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-parse-v0.2.6...anstyle-parse-v0.2.7)

Updates `anstyle-query` from 1.1.2 to 1.1.3
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-query-v1.1.2...anstyle-query-v1.1.3)

Updates `anstyle-wincon` from 3.0.8 to 3.0.9
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-wincon-v3.0.8...anstyle-wincon-v3.0.9)

Updates `bumpalo` from 3.17.0 to 3.18.1
- [Changelog](https://github.com/fitzgen/bumpalo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fitzgen/bumpalo/compare/3.17.0...v3.18.1)

Updates `cc` from 1.2.23 to 1.2.26
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.23...cc-v1.2.26)

Updates `cfg-if` from 1.0.0 to 1.0.1
- [Release notes](https://github.com/rust-lang/cfg-if/releases)
- [Changelog](https://github.com/rust-lang/cfg-if/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cfg-if/compare/1.0.0...v1.0.1)

Updates `clap_builder` from 4.5.38 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.38...v4.5.40)

Updates `clap_derive` from 4.5.32 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.32...v4.5.40)

Updates `clap_lex` from 0.7.4 to 0.7.5
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.7.4...clap_lex-v0.7.5)

Updates `colorchoice` from 1.0.3 to 1.0.4
- [Commits](https://github.com/rust-cli/anstyle/compare/colorchoice-v1.0.3...colorchoice-v1.0.4)

Updates `flate2` from 1.1.1 to 1.1.2
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.1...1.1.2)

Updates `libz-rs-sys` from 0.5.0 to 0.5.1
- [Release notes](https://github.com/trifectatechfoundation/zlib-rs/releases)
- [Changelog](https://github.com/trifectatechfoundation/zlib-rs/blob/main/docs/release.md)
- [Commits](https://github.com/trifectatechfoundation/zlib-rs/compare/v0.5.0...v0.5.1)

Updates `memchr` from 2.7.4 to 2.7.5
- [Commits](https://github.com/BurntSushi/memchr/compare/2.7.4...2.7.5)

Updates `miniz_oxide` from 0.8.8 to 0.8.9
- [Changelog](https://github.com/Frommi/miniz_oxide/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Frommi/miniz_oxide/commits)

Updates `once_cell_polyfill` from 1.70.0 to 1.70.1
- [Changelog](https://github.com/polyfill-rs/once_cell_polyfill/blob/v1.70.1/CHANGELOG.md)
- [Commits](https://github.com/polyfill-rs/once_cell_polyfill/compare/v1.70.0...v1.70.1)

Updates `rustc-demangle` from 0.1.24 to 0.1.25
- [Commits](https://github.com/rust-lang/rustc-demangle/commits)

Updates `rustversion` from 1.0.20 to 1.0.21
- [Release notes](https://github.com/dtolnay/rustversion/releases)
- [Commits](https://github.com/dtolnay/rustversion/compare/1.0.20...1.0.21)

Updates `syn` from 2.0.101 to 2.0.102
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.101...2.0.102)

Updates `tokio` from 1.45.0 to 1.45.1
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.0...tokio-1.45.1)

Updates `unicode-width` from 0.1.14 to 0.2.1
- [Commits](https://github.com/unicode-rs/unicode-width/compare/v0.1.14...v0.2.1)

Updates `windows-link` from 0.1.1 to 0.1.2
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

Updates `zlib-rs` from 0.5.0 to 0.5.1
- [Release notes](https://github.com/trifectatechfoundation/zlib-rs/releases)
- [Changelog](https://github.com/trifectatechfoundation/zlib-rs/blob/main/docs/release.md)
- [Commits](https://github.com/trifectatechfoundation/zlib-rs/compare/v0.5.0...v0.5.1)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.40
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: which
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: crates
- dependency-name: getopts
  dependency-version: 0.2.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: adler2
  dependency-version: 2.0.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstream
  dependency-version: 0.6.19
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle
  dependency-version: 1.0.11
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle-parse
  dependency-version: 0.2.7
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle-query
  dependency-version: 1.1.3
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: anstyle-wincon
  dependency-version: 3.0.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: bumpalo
  dependency-version: 3.18.1
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: crates
- dependency-name: cc
  dependency-version: 1.2.26
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: cfg-if
  dependency-version: 1.0.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: clap_builder
  dependency-version: 4.5.40
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: clap_derive
  dependency-version: 4.5.40
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: clap_lex
  dependency-version: 0.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: colorchoice
  dependency-version: 1.0.4
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: flate2
  dependency-version: 1.1.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: libz-rs-sys
  dependency-version: 0.5.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: memchr
  dependency-version: 2.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: miniz_oxide
  dependency-version: 0.8.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: once_cell_polyfill
  dependency-version: 1.70.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: rustc-demangle
  dependency-version: 0.1.25
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: rustversion
  dependency-version: 1.0.21
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: syn
  dependency-version: 2.0.102
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: tokio
  dependency-version: 1.45.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: unicode-width
  dependency-version: 0.2.1
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: crates
- dependency-name: windows-link
  dependency-version: 0.1.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
- dependency-name: zlib-rs
  dependency-version: 0.5.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: crates
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-15 23:31:36 +06:00
dependabot[bot]
c41d35db62 build(deps): bump the maven group across 1 directory with 9 updates
Bumps the maven group with 9 updates in the /manager directory:

| Package | From | To |
| --- | --- | --- |
| androidx.compose:compose-bom | `2025.05.01` | `2025.06.00` |
| androidx.lifecycle:lifecycle-runtime-ktx | `2.9.0` | `2.9.1` |
| androidx.lifecycle:lifecycle-runtime-compose | `2.9.0` | `2.9.1` |
| androidx.lifecycle:lifecycle-viewmodel-compose | `2.9.0` | `2.9.1` |
| androidx.webkit:webkit | `1.13.0` | `1.14.0` |
| [org.lsposed.libcxx:libcxx](https://github.com/LSPosed/prefab-libcxx) | `27.0.12077973` | `28.1.13356709` |
| com.android.application | `8.10.0` | `8.10.1` |
| com.android.library | `8.10.0` | `8.10.1` |
| [com.google.devtools.ksp](https://github.com/google/ksp) | `2.1.21-2.0.1` | `2.1.21-2.0.2` |



Updates `androidx.compose:compose-bom` from 2025.05.01 to 2025.06.00

Updates `androidx.lifecycle:lifecycle-runtime-ktx` from 2.9.0 to 2.9.1

Updates `androidx.lifecycle:lifecycle-runtime-compose` from 2.9.0 to 2.9.1

Updates `androidx.lifecycle:lifecycle-viewmodel-compose` from 2.9.0 to 2.9.1

Updates `androidx.lifecycle:lifecycle-runtime-compose` from 2.9.0 to 2.9.1

Updates `androidx.lifecycle:lifecycle-viewmodel-compose` from 2.9.0 to 2.9.1

Updates `androidx.webkit:webkit` from 1.13.0 to 1.14.0

Updates `org.lsposed.libcxx:libcxx` from 27.0.12077973 to 28.1.13356709
- [Commits](https://github.com/LSPosed/prefab-libcxx/compare/27.0.12077973...28.1.13356709)

Updates `com.android.application` from 8.10.0 to 8.10.1

Updates `com.android.library` from 8.10.0 to 8.10.1

Updates `com.android.library` from 8.10.0 to 8.10.1

Updates `com.google.devtools.ksp` from 2.1.21-2.0.1 to 2.1.21-2.0.2
- [Release notes](https://github.com/google/ksp/releases)
- [Commits](https://github.com/google/ksp/compare/2.1.21-2.0.1...2.1.21-2.0.2)

---
updated-dependencies:
- dependency-name: androidx.compose:compose-bom
  dependency-version: 2025.06.00
  dependency-type: direct:production
  dependency-group: maven
- dependency-name: androidx.lifecycle:lifecycle-runtime-ktx
  dependency-version: 2.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: androidx.lifecycle:lifecycle-runtime-compose
  dependency-version: 2.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: androidx.lifecycle:lifecycle-viewmodel-compose
  dependency-version: 2.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: androidx.lifecycle:lifecycle-runtime-compose
  dependency-version: 2.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: androidx.lifecycle:lifecycle-viewmodel-compose
  dependency-version: 2.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: androidx.webkit:webkit
  dependency-version: 1.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven
- dependency-name: org.lsposed.libcxx:libcxx
  dependency-version: 28.1.13356709
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: maven
- dependency-name: com.android.application
  dependency-version: 8.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: com.android.library
  dependency-version: 8.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: com.android.library
  dependency-version: 8.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
- dependency-name: com.google.devtools.ksp
  dependency-version: 2.1.21-2.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-15 23:31:19 +06:00
luigimak
e5f0c733b8 Update italian translation
add developer translation, values-it/strings.xml
2025-06-15 23:26:29 +06:00
kam821
70b52f85e9 Update Polish translation
- Added missing strings
- Updated translations for refreshed strings
2025-06-15 23:26:17 +06:00
роизен
303b5192ec Update strings.xml 2025-06-15 23:26:05 +06:00
роизен
443d3a6abe Update strings.xml 2025-06-15 23:26:05 +06:00
роизен
a2a7383343 Update strings.xml 2025-06-15 23:26:05 +06:00
роизен
ed64f933f5 Update strings.xml 2025-06-15 23:26:05 +06:00
роизен
4c7ad8eac4 Update strings.xml 2025-06-15 23:26:05 +06:00
роизен
6a922febcd Update ukranian 2025-06-15 23:26:05 +06:00
Rifat Azad
71eba5df8b manager: disable module and superuser navigation if sucompat is disabled and also show an indicator in status card 2025-06-15 22:07:15 +06:00
Rifat Azad
f1ef0afc20 manager: finish activity after flashing module intent is completed 2025-06-15 21:09:31 +06:00
Rifat Azad
844c9f94e9 manager: fix flashing lkm duplication 2025-06-15 20:13:32 +06:00
Rifat Azad
07a4d3457c manager: add separate developer menu 2025-06-15 13:00:30 +06:00
Rifat Azad
8c9728df95 manager: fix zip not flashing from content:// uri 2025-06-15 12:09:32 +06:00
Rifat Azad
14ec1194e4 manager: add support for opening zip file and directly flash module 2025-06-15 07:09:13 +06:00
Rifat Azad
a37f398cc7 kernel/Makefile: check kernelsu driver version from online git repo first, if fails then check local .git and if that also fails then use hardcoded fallback 2025-06-14 22:52:10 +06:00
backslashxx
80bd797737 kernel: ksud: remove remove read_iter requirement
nothing uses this on old kernels, so even backporting this to file_operations
is not really needed

https://elixir.bootlin.com/linux/v3.16.85/source/include/linux/fs.h#L1487

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:14:12 +06:00
backslashxx
600d9ce5d2 kernel: throne_tracker: resolve s_magic for < 3.9
throne_tracker, cross-fs avoidance:
f_inode is f_path.dentry->d_inode
so file->f_inode->i_sb->s_magic is file->f_path.dentry->d_inode->i_sb->s_magic

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:14:03 +06:00
backslashxx
f15d9b18e9 kernel: ksud: d_is_reg to IS_REG
d_is_reg requires 4.0
 - e36cb0b89c
IS_REG is still there on 6.15 so I do NOT see any issues forcing it for all.

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:13:13 +06:00
backslashxx
aa19e8c609 kernel: throne_tracker: add strscpy/strlcpy compat
strscpy requires 4.3
strscpy on this usage can be replaced with strncpy + null term.
kernel gives us an option though.
strlcpy is fast af, hotrod fast. It’s just memcpy + null term, so lets go with that.
it got dropped in 6.8 due to risk concerns, so for those, lets use og strscpy.

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:13:06 +06:00
backslashxx
2b2320000c kernel: throne_tracker: remove unneeded check here
come to think of it, this part is only about folders
2025-06-14 20:12:51 +06:00
backslashxx
06135cc827 kernel: apk_sign: loop file open on is_manager_apk
lets loop on this and wait for installation to finish

this is the third race.
2025-06-14 20:12:14 +06:00
backslashxx
fc58bdf0e2 kernel: throne_tracker: harden packages.list checker further 2025-06-14 20:08:53 +06:00
backslashxx
9b5e60912d kernel: throne_tracker, apk_sign: functionify d_lock spinlock check 2025-06-14 20:08:23 +06:00
backslashxx
c108a8ed32 kernel: throne_tracker: harden track_throne_function file read
this probably wont happen, but just to make sure, we dont block the rename now
so there is really a chance that this does not exist yet when the kthread runs.

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:07:24 +06:00
F-19-F
adce657583 kernel: ksud: provide is_ksu_transition check v2
context: this is known by many as `selinux hook`, `4.9 hook`

add is_ksu_transition check which allows ksud execution under nosuid.
it also eases up integration on 3.X kernels that does not have check_nnp_nosuid.

Usage:
	if (is_ksu_transition(old_tsec, new_tsec))
		return 0;

on either check_nnp_nosuid or selinux_bprm_set_creds (after execve sid reset)

reference: dfe003c9fd

taken from:
`allow init exec ksud under nosuid`
- 3df9df42a6
- https://github.com/tiann/KernelSU/pull/166#issue-1565872173

250611-edit:
- remove ksu_execveat_hook entry check
- turns out some devices needs the transition for multiple times

Reported-by: edenadversary <143865198+edenadversary@users.noreply.github.com>
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:07:16 +06:00
rsuntk
d6601e1e54 kernel: core_hook: fix refcount leaks on try_umount (#2635)
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:03:30 +06:00
backslashxx
0d4efa649f kernel: throne_tracker: avoid cross-fs traversal using s_magic check (#2633)
Skip directories that does NOT have the same magic as /data/app.
This is to avoid scanning incfs and any other stacked filesystems.

While this is way dumber, it's way cheaper.
no kern_path(), no missable path_put(), no ref handling.

This supercedes
`throne_tracker: avoid cross fs access
(https://github.com/tiann/KernelSU/pull/2626)`
- upstream
0b6998b474

Signed-off-by: backslashxx
<118538522+backslashxx@users.noreply.github.com>
2025-06-14 20:03:04 +06:00
Wang Han
85f4e6ac27 Switch to prepare_creds/commit_creds (#2631)
Update API as per kernel doc recommends, also fix setup_groups refcount
leak while at it.
2025-06-14 20:01:36 +06:00
Rifat Azad
c91f9c18ec Revert "kernel: ksud, throne_tracker: small changes for UL"
This reverts commit c4deee1e49.
2025-06-14 19:54:59 +06:00
Rifat Azad
bf35f73430 Revert "kernel: throne_tracker: move throne_tracker to kthread"
This reverts commit 6a6fc07cd4.
2025-06-14 19:54:36 +06:00
Rifat Azad
ad290a51a0 manager: fully polish and refactor module card ui 2025-06-12 23:40:14 +06:00
Rifat Azad
d218346613 manager: keep mount system preference persistent without breaking rootAvailable() checks 2025-06-12 21:50:16 +06:00
Rifat Azad
502e5599fe manager: improve module card ui 2025-06-12 21:05:40 +06:00
Rifat Azad
11fb52b929 manager: merge legacy and revamped module card ui, also tapping the card open webui when available and actions when available but if both are available then prefer webui 2025-06-12 13:03:41 +06:00
Rifat Azad
057388ccef manager: do not go at the start of the superuser list and stay where you were after app profile changes (resolves #491) 2025-06-12 10:42:53 +06:00
Rifat Azad
67759ad723 manager: update app state upon app profile changes
properly update the superuser app list state after changes have been made to app profile
2025-06-12 10:18:51 +06:00
Rifat Azad
f231cbdba7 Revert "manager: refresh superuser applist on appprofile exit"
This reverts commit fcbb02a115.
2025-06-12 08:46:38 +06:00
Suraj J Pai
7abc9bc821 [BUGFIX] manager: Fix Module Flashing fails when orientation changes (#503)
The issue is caused by re-rendering of Activity when orientation changes.
All states are reset when it is re-rendered. Using ViewModel to manage zipUri fixes the issue.

Fixes issue: https://github.com/KernelSU-Next/KernelSU-Next/issues/488
2025-06-12 04:44:45 +06:00
GMárton
e7697d86fe Update hungarian translation (#489)
* Update hungarian translation

* Fix typo

---------

Co-authored-by: Marty <marton.garamszegi@mptrdev.com>
2025-06-11 04:30:29 +06:00
1alessandro1
68394fddd5 Update doc (#485) 2025-06-11 04:30:14 +06:00
cvnertnc
90d34bf511 Manager: update values-tr/strings.xml (#469) 2025-06-11 04:29:47 +06:00
luigimak
236fbc7615 Update Italian Translation (#461)
* Update Italian Translation

values-it/strings.xml

* fix use_webuix_summary

Update values-it/strings.xml

* Update values-it/strings.xml

* Add module_size values-it/strings.xml

* Add settings_banner values-it/strings.xml

* fix settings_banner
2025-06-11 04:29:31 +06:00
mr_vokintos
6871cbdba7 Update Russian (#466)
* Update strings.xml

Update Russian

* Update strings.xml

* Update strings.xml
2025-06-11 04:29:15 +06:00
AxelPLN(Axel Yinjia Huang)
38a9949211 Update manager translations for zh-rCN & zh-rTW (#456)
* Update translations for zh-rCN &zh-rTW to 0a42dbf

* Add zh-rCN & zh-rTW translations for functions as legacyUI & module banner and so on.

Improve translations.
2025-06-11 04:27:58 +06:00
igor
9fba0faa43 Update portuguese translation (#453)
* Update portuguese translation

* Update strings.xml

* Update strings.xml

* Update README.md

* Update README_PT-BR.md

* Update strings.xml

* Update strings.xml
2025-06-11 04:26:43 +06:00
Caner Karaca
b1250b002e Workflow Updates (#481)
* Update

* Use ubuntu-22.04

* Revert some renamings

* Create renovate.json

* oops
2025-06-11 04:23:22 +06:00
62 changed files with 2727 additions and 1236 deletions

View File

@@ -37,7 +37,7 @@ on:
jobs:
build:
name: Build ${{ inputs.version_name }}
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@master

View File

@@ -7,9 +7,9 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.233
tag: android12-5.10-2025-02
os_patch_level: 2025-02
version_name: android12-5.10.236
tag: android12-5.10-2025-05
os_patch_level: 2025-05
patch_path: "5.10"
debug: true
build-debug-kernel-a13:
@@ -17,11 +17,11 @@ jobs:
matrix:
include:
- version: "5.10"
sub_level: 234
os_patch_level: 2025-03
sub_level: 236
os_patch_level: 2025-05
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 180
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
@@ -34,11 +34,11 @@ jobs:
matrix:
include:
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 180
os_patch_level: 2025-05
- version: "6.1"
sub_level: 129
os_patch_level: 2025-04
sub_level: 138
os_patch_level: 2025-06
uses: ./.github/workflows/gki-kernel.yml
with:
version: android14-${{ matrix.version }}
@@ -51,8 +51,8 @@ jobs:
matrix:
include:
- version: "6.6"
sub_level: 82
os_patch_level: 2025-04
sub_level: 89
os_patch_level: 2025-06
uses: ./.github/workflows/gki-kernel.yml
with:
version: android15-${{ matrix.version }}

View File

@@ -21,14 +21,14 @@ jobs:
strategy:
matrix:
include:
- sub_level: 209
os_patch_level: 2024-05
- sub_level: 218
os_patch_level: 2024-08
- sub_level: 226
os_patch_level: 2024-11
- sub_level: 233
os_patch_level: 2025-02
- sub_level: 236
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -114,7 +114,7 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.223
tag: android12-5.10-2024-11
os_patch_level: 2024-11
version_name: android12-5.10.236
tag: android12-5.10-2025-05
os_patch_level: 2025-05
patch_path: "5.10"

View File

@@ -21,9 +21,6 @@ jobs:
strategy:
matrix:
include:
- version: "5.10"
sub_level: 209
os_patch_level: 2024-05
- version: "5.10"
sub_level: 210
os_patch_level: 2024-06
@@ -42,9 +39,9 @@ jobs:
- version: "5.10"
sub_level: 234
os_patch_level: 2025-03
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.10"
sub_level: 236
os_patch_level: 2025-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-07
@@ -63,6 +60,9 @@ jobs:
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "5.15"
sub_level: 180
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -149,11 +149,11 @@ jobs:
matrix:
include:
- version: "5.10"
sub_level: 234
os_patch_level: 2025-03
sub_level: 236
os_patch_level: 2025-05
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 180
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}

View File

@@ -21,9 +21,6 @@ jobs:
strategy:
matrix:
include:
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-06
@@ -45,9 +42,9 @@ jobs:
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "6.1"
sub_level: 75
os_patch_level: 2024-05
- version: "5.15"
sub_level: 180
os_patch_level: 2025-05
- version: "6.1"
sub_level: 78
os_patch_level: 2024-06
@@ -81,6 +78,12 @@ jobs:
- version: "6.1"
sub_level: 129
os_patch_level: 2025-04
- version: "6.1"
sub_level: 134
os_patch_level: 2025-05
- version: "6.1"
sub_level: 138
os_patch_level: 2025-06
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -167,11 +170,11 @@ jobs:
matrix:
include:
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 180
os_patch_level: 2025-05
- version: "6.1"
sub_level: 129
os_patch_level: 2025-04
sub_level: 138
os_patch_level: 2025-06
uses: ./.github/workflows/gki-kernel.yml
with:
version: android14-${{ matrix.version }}

View File

@@ -48,6 +48,12 @@ jobs:
- version: "6.6"
sub_level: 82
os_patch_level: 2025-04
- version: "6.6"
sub_level: 87
os_patch_level: 2025-05
- version: "6.6"
sub_level: 89
os_patch_level: 2025-06
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -134,8 +140,8 @@ jobs:
matrix:
include:
- version: "6.6"
sub_level: 82
os_patch_level: 2025-04
sub_level: 89
os_patch_level: 2025-06
uses: ./.github/workflows/gki-kernel.yml
with:
version: android15-${{ matrix.version }}

137
.github/workflows/build-kernel-arcvm.yml vendored Normal file
View File

@@ -0,0 +1,137 @@
name: Build Kernel - ChromeOS ARCVM
on:
push:
branches: ["next"]
paths:
- ".github/workflows/build-kernel-arcvm.yml"
- "kernel/**"
pull_request:
branches: ["next"]
paths:
- ".github/workflows/build-kernel-arcvm.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
env:
git_tag: chromeos-5.10-arcvm
jobs:
build:
if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && !github.event.pull_request.draft)
strategy:
matrix:
include:
- arch: x86_64
kernel_image_name: bzImage
build_config: build.config.gki.x86_64
defconfig: x86_64_arcvm_defconfig
- arch: arm64
kernel_image_name: Image
build_config: build.config.gki.aarch64
defconfig: arm64_arcvm_defconfig
name: Build ChromeOS ARCVM kernel
runs-on: ubuntu-22.04
env:
LTO: thin
ROOT_DIR: /
KERNEL_DIR: ${{ github.workspace }}/kernel
steps:
- name: Install Build Tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends bc \
bison build-essential ca-certificates flex git gnupg \
libelf-dev libssl-dev lsb-release software-properties-common wget \
libncurses-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu nuget gzip \
rsync python3 device-tree-compiler
sudo ln -s --force python3 /usr/bin/python
export LLVM_VERSION=14
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
rm ./llvm.sh
sudo ln -s --force /usr/bin/clang-$LLVM_VERSION /usr/bin/clang
sudo ln -s --force /usr/bin/ld.lld-$LLVM_VERSION /usr/bin/ld.lld
sudo ln -s --force /usr/bin/llvm-objdump-$LLVM_VERSION /usr/bin/llvm-objdump
sudo ln -s --force /usr/bin/llvm-ar-$LLVM_VERSION /usr/bin/llvm-ar
sudo ln -s --force /usr/bin/llvm-nm-$LLVM_VERSION /usr/bin/llvm-nm
sudo ln -s --force /usr/bin/llvm-strip-$LLVM_VERSION /usr/bin/llvm-strip
sudo ln -s --force /usr/bin/llvm-objcopy-$LLVM_VERSION /usr/bin/llvm-objcopy
sudo ln -s --force /usr/bin/llvm-readelf-$LLVM_VERSION /usr/bin/llvm-readelf
sudo ln -s --force /usr/bin/clang++-$LLVM_VERSION /usr/bin/clang++
- name: Checkout KernelSU-Next
uses: actions/checkout@v4
with:
path: KernelSU-Next
fetch-depth: 0
- name: Setup kernel source
run: git clone https://chromium.googlesource.com/chromiumos/third_party/kernel.git -b ${{ env.git_tag }} --depth=1
- name: Extract version from Makefile
working-directory: kernel
run: |
VERSION=$(grep -E '^VERSION = ' Makefile | awk '{print $3}')
PATCHLEVEL=$(grep -E '^PATCHLEVEL = ' Makefile | awk '{print $3}')
SUBLEVEL=$(grep -E '^SUBLEVEL = ' Makefile | awk '{print $3}')
echo "ChromeOS ARCVM Linux kernel version: $VERSION.$PATCHLEVEL.$SUBLEVEL"
echo "version=$VERSION.$PATCHLEVEL.$SUBLEVEL" >> $GITHUB_ENV
- name: Setup KernelSU-Next
working-directory: kernel
run: |
echo "[+] KernelSU-Next setup"
KERNEL_ROOT=$GITHUB_WORKSPACE/kernel
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
echo "[+] Copy KernelSU-Next driver to $KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU-Next/kernel $KERNEL_ROOT/drivers/kernelsu-next
echo "[+] Add KernelSU-Next driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
DRIVER_KCONFIG=$KERNEL_ROOT/drivers/Kconfig
grep -q "kernelsu-next" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu-next/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu-next" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu-next/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU-Next/.github/patches/5.10/*.patch || echo "[-] No patch found"
echo "[+] Patch script/setlocalversion"
sed -i 's/-dirty//g' $KERNEL_ROOT/scripts/setlocalversion
echo "[+] KernelSU-Next setup done."
cd $GITHUB_WORKSPACE/KernelSU-Next
KSU_VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "KernelSU-Next version: $KSU_VERSION"
echo "kernelsu-next_version=$KSU_VERSION" >> $GITHUB_ENV
- name: Build Kernel
working-directory: kernel
env:
KERNEL_IMAGE_NAME: ${{ matrix.kernel_image_name }}
ARCH: ${{ matrix.arch }}
run: |
set -a && . ${{ matrix.build_config }}; set +a
export DEFCONFIG=${{ matrix.defconfig }}
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
fi
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} mrproper
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} ${DEFCONFIG} < /dev/null
scripts/config --file .config -e LTO_CLANG -d LTO_NONE -e LTO_CLANG_THIN -d LTO_CLANG_FULL -e THINLTO
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} -j$(nproc) ${KERNEL_IMAGE_NAME} modules prepare-objtool
ls -l -h ${PWD}/arch/${ARCH}/boot
echo "file_path=${PWD}/arch/${ARCH}/boot/${KERNEL_IMAGE_NAME}" >> $GITHUB_ENV
- name: Upload kernel-ARCVM-${{ matrix.arch }}-${{ env.version }}
uses: actions/upload-artifact@v4
with:
name: kernel-ARCVM-${{ matrix.arch }}-${{ env.version }}
path: "${{ env.file_path }}"

39
.github/workflows/build-kernel-avd.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Build Kernel - AVD
on:
push:
branches: ["next"]
paths:
- ".github/workflows/build-kernel-avd.yml"
- ".github/workflows/avd-kernel.yml"
- "kernel/**"
pull_request:
branches: ["next"]
paths:
- ".github/workflows/build-kernel-avd.yml"
- ".github/workflows/avd-kernel.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
uses: ./.github/workflows/avd-kernel.yml
secrets: inherit
strategy:
matrix:
include:
- version: "android-14-avd_x86_64"
manifest: "android-14-avd_x86_64.xml"
arch: "x86_64"
- version: "android-15-avd_aarch64"
manifest: "android-15-avd_aarch64.xml"
arch: "aarch64"
- version: "android-15-avd_x86_64"
manifest: "android-15-avd_x86_64.xml"
arch: "x86_64"
with:
version_name: ${{ matrix.version }}
manifest_name: ${{ matrix.manifest }}
arch: ${{ matrix.arch }}
debug: true

View File

@@ -15,23 +15,23 @@ jobs:
matrix:
include:
- version: "android12-5.10"
sub_level: 233
os_patch_level: 2025-02
sub_level: 236
os_patch_level: 2025-05
- version: "android13-5.10"
sub_level: 234
os_patch_level: 2025-03
sub_level: 236
os_patch_level: 2025-05
- version: "android13-5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 180
os_patch_level: 2025-05
- version: "android14-5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 180
os_patch_level: 2025-05
- version: "android14-6.1"
sub_level: 129
os_patch_level: 2025-04
sub_level: 138
os_patch_level: 2025-06
- version: "android15-6.6"
sub_level: 82
os_patch_level: 2025-04
sub_level: 89
os_patch_level: 2025-06
uses: ./.github/workflows/gki-kernel.yml
with:
version: ${{ matrix.version }}

View File

@@ -3,14 +3,14 @@ name: Clippy check
on:
push:
branches:
- x86
- next
paths:
- '.github/workflows/clippy.yml'
- 'userspace/ksud_magic/**'
- 'userspace/ksud_overlayfs/**'
pull_request:
branches:
- x86
- next
paths:
- '.github/workflows/clippy.yml'
- 'userspace/ksud_magic/**'

View File

@@ -21,6 +21,12 @@ jobs:
build-a15-kernel:
uses: ./.github/workflows/build-kernel-a15.yml
secrets: inherit
build-wsa-kernel:
uses: ./.github/workflows/build-kernel-wsa.yml
secrets: inherit
build-arcvm-kernel:
uses: ./.github/workflows/build-kernel-arcvm.yml
secrets: inherit
release:
needs:
- build-manager
@@ -29,6 +35,7 @@ jobs:
- build-a14-kernel
- build-a15-kernel
- build-wsa-kernel
- build-arcvm-kernel
runs-on: ubuntu-latest
steps:
- name: Download artifacts
@@ -42,6 +49,24 @@ jobs:
fi
done
- name: Zip WSA kernel
run: |
for dir in kernel-WSA-*; do
if [ -d "$dir" ]; then
echo "------ Zip $dir ----------"
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
fi
done
- name: Zip ChromeOS ARCVM kernel
run: |
for dir in kernel-ARCVM-*; do
if [ -d "$dir" ]; then
echo "------ Zip $dir ----------"
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
fi
done
- name: Display structure of downloaded files
run: ls -R
@@ -54,6 +79,7 @@ jobs:
AnyKernel3-*.zip
boot-images-*/Image-*/*.img.gz
kernel-WSA*.zip
kernel-ARCVM*.zip
ksud_magic*.zip
ksud_overlayfs*.zip
susfsd*.zip
susfsd*.zip

View File

@@ -43,10 +43,10 @@ jobs:
ubuntu-version: "16.04"
cached: ${{ steps.cache-llvm.outputs.cache-hit }}
- name: Checkout KernelSU
- name: Checkout KernelSU-Next
uses: actions/checkout@v4
with:
path: KernelSU
path: KernelSU-Next
fetch-depth: 0
- name: Setup kernel source
@@ -63,23 +63,23 @@ jobs:
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
max-size: 2G
- name: Setup KernelSU
- name: Setup KernelSU-Next
working-directory: WSA-Linux-Kernel
run: |
echo "[+] KernelSU setup"
echo "[+] KernelSU-Next setup"
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
echo "[+] Copy KernelSU-Next driver to $KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU-Next/kernel $KERNEL_ROOT/drivers/kernelsu
echo "[+] Add KernelSU-Next driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
DRIVER_KCONFIG=$KERNEL_ROOT/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch || echo "[-] No patch found"
echo "[+] KernelSU setup done."
cd $GITHUB_WORKSPACE/KernelSU
echo "[+] Apply KernelSU-Next patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU-Next/.github/patches/5.15/*.patch || echo "[-] No patch found"
echo "[+] KernelSU-Next setup done."
cd $GITHUB_WORKSPACE/KernelSU-Next
VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "VERSION: $VERSION"
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
@@ -103,4 +103,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: kernel-WSA-${{ inputs.arch }}-${{ inputs.version }}
path: "${{ env.file_path }}"
path: "${{ env.file_path }}"

View File

@@ -1,63 +1,89 @@
**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md) | [Українська](README_UA.md)
**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Українська](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
# KernelSU Next
---
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
<div align="center">
<img src="/assets/kernelsu_next.png" width="96" alt="KernelSU Next Logo">
A kernel-based root solution for Android devices.
<h2>KernelSU Next</h2>
<p><strong>A kernel-based root solution for Android devices.</strong></p>
[![Latest Release](https://img.shields.io/github/v/release/KernelSU-Next/KernelSU-Next?label=Release&logo=github)](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
[![Nightly Release](https://img.shields.io/badge/Nightly%20Release-gray?logo=hackthebox&logoColor=fff)](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/KernelSU-Next/KernelSU-Next?logo=gnu)](/LICENSE)
<p>
<a href="https://github.com/KernelSU-Next/KernelSU-Next/releases/latest">
<img src="https://img.shields.io/github/v/release/KernelSU-Next/KernelSU-Next?label=Release&logo=github" alt="Latest Release">
</a>
<a href="https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager">
<img src="https://img.shields.io/badge/Nightly%20Release-gray?logo=hackthebox&logoColor=fff" alt="Nightly Build">
</a>
<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">
<img src="https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu" alt="License: GPL v2">
</a>
<a href="/LICENSE">
<img src="https://img.shields.io/github/license/KernelSU-Next/KernelSU-Next?logo=gnu" alt="GitHub License">
</a>
</p>
</div>
## Features
---
1. Kernel-based `su` and root access management.
2. Module system based on dynamic mount system [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Lock up the root power in a cage.
## 🚀 Features
## Compatibility state
- Kernel-based `su` and root access management.
- Module system based on [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) and [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
- [App Profile](https://kernelsu.org/guide/app-profile.html): Limit root privileges per app.
KernelSU Next officially supports most Android kernels starting from 4.4 up to 6.6.
- GKI 2.0 (5.10+) kernels can run pre-built images and LKM/KMI.
- GKI 1.0 (4.19 - 5.4) kernels need to rebuilt with KernelSU driver.
- EOL (<4.14) kernels also need to be rebuilt with KernelSU driver (3.18+ is experimental and may need some function backports).
---
Currently, only the `arm64-v8a`, `armeabi-v7a` & `x86_64` architecture is supported.
## ✅ Compatibility
## Usage
KernelSU Next supports Android kernels from **4.4 up to 6.6**:
- [Installation instruction](https://ksunext.org/pages/installation.html)
| Kernel version | Support notes |
|----------------------|-------------------------------------------------------------------------|
| 5.10+ (GKI 2.0) | Supports pre-built images and LKM/KMI |
| 4.19 5.4 (GKI 1.0) | Requires KernelSU driver built-in |
| < 4.14 (EOL) | Requires KernelSU driver (3.18+ is experimental and may need backports) |
## Security
**Supported architectures:** `arm64-v8a`, `armeabi-v7a` and `x86_64`
For information on reporting security vulnerabilities in KernelSU, see [SECURITY.md](/SECURITY.md).
---
## License
## 📦 Installation
- Files under the `kernel` directory are [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- All other parts except the `kernel` directory are [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
Please refer to the [Installation](https://kernelsu-next.github.io/webpage/pages/installation.html) guide for setup instructions.
## Donations
---
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
## 🔐 Security
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
To report security issues, please see [SECURITY.md](/SECURITY.md).
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
---
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
## 📜 License
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
- **`/kernel` directory:** [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- **All other files:** [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
---
## Credits
## 💸 Donations
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): The KernelSU idea.
- [Magisk](https://github.com/topjohnwu/Magisk): The powerful root tool.
- [genuine](https://github.com/brevent/genuine/): APK v2 signature validation.
- [Diamorphine](https://github.com/m0nad/Diamorphine): Some rootkit skills.
- [KernelSU](https://github.com/tiann/KernelSU): Thanks to tiann, or else KernelSU Next wouldn't even exist.
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff for saving KernelSU!
If youd like to support the project:
- **USDT (BEP20, ERC20)**: `0x12b5224b7aca0121c2f003240a901e1d064371c1`
- **USDT (TRC20)**: `TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh`
- **ETH (ERC20)**: `0x12b5224b7aca0121c2f003240a901e1d064371c1`
- **LTC**: `Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL`
- **BTC**: `19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6`
---
## 🙏 Credits
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/) Concept inspiration
- [Magisk](https://github.com/topjohnwu/Magisk) Core root implementation
- [Genuine](https://github.com/brevent/genuine/) APK v2 signature validation
- [Diamorphine](https://github.com/m0nad/Diamorphine) Rootkit techniques
- [KernelSU](https://github.com/tiann/KernelSU) The original base that made KernelSU Next possible
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs) 💜 to 5ec1cff for keeping KernelSU alive

View File

@@ -13,7 +13,7 @@
## 特性
1. 基于内核的 `SU` 和权限管理
1. 基于内核的 `su`超级用户权限管理
2. 基于动态挂载系统 [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模块系统。
3. [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html):把 Root 权限关进笼子里
@@ -46,4 +46,4 @@ KernelSU Next 支持从 4.4 到 6.6 的大多数安卓内核
- [genuine](https://github.com/brevent/genuine/): APK v2 签名验证。
- [Diamorphine](https://github.com/m0nad/Diamorphine): 一些 Rootkit 技巧。
- [KernelSU](https://github.com/tiann/KernelSU): 感谢 tiann否则 KernelSU Next 根本不会存在。
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff 了拯救 KernelSU
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff 了拯救 KernelSU

View File

@@ -1,63 +1,89 @@
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | **Português (Brasil)** | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
# KernelSU Next
---
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
<div align="center">
<img src="/assets/kernelsu_next.png" width="96" alt="KernelSU Next Logo">
Uma solução root baseada em kernel para dispositivos Android.
<h2>KernelSU Next</h2>
<p><strong>Uma solução root baseada em kernel para dispositivos Android.</strong></p>
[![Latest Release](https://img.shields.io/github/v/release/KernelSU-Next/KernelSU-Next?label=Release&logo=github)](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
[![Nightly Release](https://img.shields.io/badge/Nightly%20Release-gray?logo=hackthebox&logoColor=fff)](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/KernelSU-Next/KernelSU-Next?logo=gnu)](/LICENSE)
<p>
<a href="https://github.com/KernelSU-Next/KernelSU-Next/releases/latest">
<img src="https://img.shields.io/github/v/release/KernelSU-Next/KernelSU-Next?label=Release&logo=github" alt="Latest Release">
</a>
<a href="https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager">
<img src="https://img.shields.io/badge/Nightly%20Release-gray?logo=hackthebox&logoColor=fff" alt="Nightly Build">
</a>
<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">
<img src="https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu" alt="License: GPL v2">
</a>
<a href="/LICENSE">
<img src="https://img.shields.io/github/license/KernelSU-Next/KernelSU-Next?logo=gnu" alt="GitHub License">
</a>
</p>
</div>
## Características
---
1. `su` e gerenciamento de acesso root baseado em kernel.
2. Sistema de módulos baseado em sistema de montagem dinâmica [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [Perfil do Aplicativo](https://kernelsu.org/pt_BR/guide/app-profile.html): Tranque o poder root em uma gaiola.
## 🚀 Características
## Estado de compatibilidade
- `su` e gerenciamento de acesso root baseado em kernel.
- Sistema de módulos baseado em [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) e [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
- [Perfil do app](https://kernelsu.org/pt_BR/guide/app-profile.html): Limitar privilégios root por app.
KernelSU Next suporta oficialmente a maioria dos kernels Android a partir de 4.4 até 6.6.
- Os kernels GKI 2.0 (5.10+) podem executar imagens pré-construídas e LKM/KMI.
- Os kernels GKI 1.0 (4.19 - 5.4) precisam ser reconstruídos com o driver KernelSU.
- Os kernels EOL (<4.14) também precisam ser reconstruídos com o driver KernelSU (3.18+ é experimental e pode precisar portar algumas funções).
---
Atualmente, apenas a arquitetura `arm64-v8a`, `armeabi-v7a` & `x86_64` é compatível.
## ✅ Compatibilidade
## Uso
O KernelSU Next oferece suporte a kernels Android **4.4 até 6.6**:
- [Instruções de instalação](https://ksunext.org/pages/installation.html)
| Versão do kernel | Notas de suporte |
|----------------------|-------------------------------------------------------------------------------|
| 5.10+ (GKI 2.0) | Suporta imagens pré-compiladas e LKM/KMI |
| 4.19 5.4 (GKI 1.0) | Requer driver do KernelSU integrado |
| < 4.14 (EOL) | Requer driver do KernelSU (3.18+ é experimental e pode precisar de backports) |
## Segurança
**Arquiteturas suportadas:** `arm64-v8a`, `armeabi-v7a` e `x86_64`
Para obter informações sobre como relatar vulnerabilidades de segurança do KernelSU, consulte [SECURITY.md](/SECURITY.md).
---
## Licença
## 📦 Instalação
- Os arquivos no diretório `kernel` são [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Todas as outras partes, exceto o diretório `kernel` são [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
Consulte o guia de [Instalação](https://kernelsu-next.github.io/webpage/pt_BR/pages/installation.html) para obter instruções de configuração.
## Doações
---
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
## 🔐 Segurança
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
Para relatar problemas de segurança, consulte [SECURITY.md](/SECURITY.md).
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
---
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
## 📜 Licença
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
- **Diretório `/kernel`:** [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- **Todos os outros arquivos:** [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
---
## Créditos
## 💸 Doações
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): A ideia do KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): A poderosa ferramenta root.
- [genuine](https://github.com/brevent/genuine/): Validação de assinatura APK v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): Algumas habilidades de rootkit.
- [KernelSU](https://github.com/tiann/KernelSU): Obrigado ao tiann, ou então o KernelSU Next nem existiria.
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff por salvar o KernelSU!
Se você quiser apoiar o projeto:
- **USDT (BEP20, ERC20)**: `0x12b5224b7aca0121c2f003240a901e1d064371c1`
- **USDT (TRC20)**: `TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh`
- **ETH (ERC20)**: `0x12b5224b7aca0121c2f003240a901e1d064371c1`
- **LTC**: `Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL`
- **BTC**: `19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6`
---
## 🙏 Créditos
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/) Inspiração do conceito
- [Magisk](https://github.com/topjohnwu/Magisk) Implementação root principal
- [Genuine](https://github.com/brevent/genuine/) Validação de assinatura APK v2
- [Diamorphine](https://github.com/m0nad/Diamorphine) Técnicas de rootkit
- [KernelSU](https://github.com/tiann/KernelSU) A base original que tornou o KernelSU Next possível
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs) 💜 para 5ec1cff por manter o KernelSU vivo

View File

@@ -47,4 +47,3 @@ KernelSU Next 正式支持大多數從 4.4 到 6.6 的 Android 內核
- [Diamorphine](https://github.com/m0nad/Diamorphine): 一些 Rootkit 技巧。
- [KernelSU](https://github.com/tiann/KernelSU): 感謝 tiann否則 KernelSU Next 根本不會存在。
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff 為了拯救 KernelSU

View File

@@ -1,63 +1,91 @@
**Languages**:
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md) | **Українська**
# KernelSU Next
---
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
<div align="center">
<img src="/assets/kernelsu_next.png" width="96" alt="KernelSU Next Logo">
<h2>KernelSU Next</h2>
<p><strong>Рішення для root-прав на основі ядра для пристроїв Android.</strong></p>
Рут-рішення на основі ядра для пристроїв Android.
<p>
<a href="https://github.com/KernelSU-Next/KernelSU-Next/releases/latest">
<img src="https://img.shields.io/github/v/release/KernelSU-Next/KernelSU-Next?label=Release&logo=github" alt="Latest Release">
</a>
<a href="https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager">
<img src="https://img.shields.io/badge/Nightly%20Release-gray?logo=hackthebox&logoColor=fff" alt="Nightly Build">
</a>
<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">
<img src="https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu" alt="License: GPL v2">
</a>
<a href="/LICENSE">
<img src="https://img.shields.io/github/license/KernelSU-Next/KernelSU-Next?logo=gnu" alt="GitHub License">
</a>
</p>
</div>
[![Останній реліз](https://img.shields.io/github/v/release/KernelSU-Next/KernelSU-Next?label=Release&logo=github)](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
[![Нічний реліз (Нестабільний)](https://img.shields.io/badge/Nightly%20Release-gray?logo=hackthebox&logoColor=fff)](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
[![Ліцензія: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub Ліцензія](https://img.shields.io/github/license/KernelSU-Next/KernelSU-Next?logo=gnu)](/LICENSE)
---
## Можливості
## 🚀 Особливості
1. `su` на основі ядра та можливість контролювати дозволи руту.
2. Module system based on dynamic mount system [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [Профілі додатків](https://kernelsu.org/guide/app-profile.html): Обмеж права руту для додатків.
- Керування `su` та root-доступом на основі ядра
- Модульна система на основі **[Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount)** та **[OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)**
- [Профілі програм](https://kernelsu.org/guide/app-profile.html): Обмеження root-прав для кожної програми
## Compatibility state
---
KernelSU Next офіційно підтримує більшість Android ядер починаючи з 4.4 і до 6.6.
- Користувачі GKI 2.0 (5.10+) ядра можуть використовувати готові образи та LKM/KMI.
- Користувачі GKI 1.0 (4.19 - 5.4) ядра мають бути перезібрані з драйвером KernelSU.
- Користувачі EOL (<4.14) ядра також мають бути перезібрані з драйвером KernelSU (Підтримка 3.18+ експерементальна і потребує бекпортів деяких функцій в ядрі).
## ✅ Сумісність
На даний момент підтримується лише архітектура `arm64-v8a`, `armeabi-v7a` & `x86_64`.
KernelSU Next підтримує ядра Android від **4.4 до 6.6**:
## Спосіб використання
| Версія ядра | Примітки підтримки |
|----------------|---------------|
| 5.10+ (GKI 2.0) | Підтримує попередньо створені образи та LKM/KMI |
| 4.19 5.4 (GKI 1.0) | Потрібен вбудований драйвер KernelSU |
| <4.14 (EOL) | Потрібен драйвер KernelSU (версія 3.18+ є експериментальною, може знадобитися портування) |
- [Інструкція для встановлення/інтеграції](https://ksunext.org/pages/installation.html)
**Підтримувані архітектури:**
`arm64-v8a`, `armeabi-v7a`, `x86_64`
## Безпека
---
Для інформації зв'язаною з безпекою дивіться [SECURITY.md](/SECURITY.md).
## 📦 Встановлення
## Ліцензія
Будь ласка, зверніться до [Посібника з встановлення](https://kernelsu-next.github.io/webpage/pages/installation.html) для отримання інструкцій з налаштування.
- Всі файли в директорії `kernel` мають ліцензію [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Всі інші файли виключаючи директорію `kernel` мають ліцензію [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
---
## Підтримка розробника
## 🔐 Безпека
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
Щоб повідомити про проблеми безпеки, див. [SECURITY.md](/SECURITY.md).
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
---
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
## 📜 Ліцензія
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
- **Каталог `/kernel`:** [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- **Усі інші файли:** [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
---
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
## 💸 Пожертви
## Подяки
Якщо ви хочете підтримати проєкт:
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): Ідея KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): Потужний засіб руту.
- [genuine](https://github.com/brevent/genuine/): Перевірка підпису APK v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): Деякі руткіт скіли.
- [KernelSU](https://github.com/tiann/KernelSU): Дякую tiann, інакше KernelSU Next ніколи б не існував.
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): Дякую 💜 5ec1cff за збереження KernelSU!
- **USDT (BEP20, ERC20)**: `0x12b5224b7aca0121c2f003240a901e1d064371c1`
- **USDT (TRC20)**: `TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh`
- **ETH (ERC20)**: `0x12b5224b7aca0121c2f003240a901e1d064371c1`
- **LTC**: `Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL`
- **BTC**: `19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6`
---
## 🙏 Подяки
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/) Натхнення для концепції
- [Magisk](https://github.com/topjohnwu/Magisk) Топовий інструмент для root
- [Genuine](https://github.com/brevent/genuine/) Перевірка підпису APK версії 2
- [Diamorphine](https://github.com/m0nad/Diamorphine) Деякі навики RootKit
- [KernelSU](https://github.com/tiann/KernelSU) Основа для KernelSU Next
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs) 💜 до 5ec1cff за збереження KernelSU

View File

@@ -16,18 +16,32 @@ ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-
obj-$(CONFIG_KSU) += kernelsu.o
# .git is a text file while the module is imported by 'git submodule add'.
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
$(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin [ -f ../.git/shallow ] && git fetch --unshallow)
KSU_GIT_VERSION := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git rev-list --count HEAD)
# ksu_version: major * 10000 + git version + 200 for historical reasons
$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 200))
REPO_OWNER := KernelSU-Next
REPO_NAME := KernelSU-Next
REPO_BRANCH := next
GIT_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git
CURL_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin curl
KSU_GITHUB_VERSION := $(shell $(CURL_BIN) -sI "https://api.github.com/repos/$(REPO_OWNER)/$(REPO_NAME)/commits?sha=$(REPO_BRANCH)&per_page=1" | grep -i "link:" | sed -n 's/.*page=\([0-9]*\)>; rel="last".*/\1/p')
ifeq ($(KSU_GITHUB_VERSION),)
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
$(shell cd $(srctree)/$(src); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
KSU_LOCAL_VERSION := $(shell cd $(srctree)/$(src); $(GIT_BIN) rev-list --count HEAD)
$(eval KSU_VERSION := $(shell expr 10000 + $(KSU_LOCAL_VERSION) + 200))
$(info -- KernelSU-Next version (local .git): $(KSU_VERSION))
else
$(eval KSU_VERSION := 11998)
$(warning -- Could not fetch version online or via local .git! Using fallback version: $(KSU_VERSION))
endif
else
$(eval KSU_VERSION := $(shell expr 10000 + $(KSU_GITHUB_VERSION) + 200))
$(info -- KernelSU-Next version (GitHub): $(KSU_VERSION))
endif
$(info -- KernelSU-Next version: $(KSU_VERSION))
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
else # If there is no .git file, the default version will be passed.
$(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU-Next a git submodule!")
ccflags-y += -DKSU_VERSION=11998
endif
ifeq ($(shell grep -q " current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID

View File

@@ -17,6 +17,7 @@
#include "apk_sign.h"
#include "klog.h" // IWYU pragma: keep
#include "kernel_compat.h"
#include "throne_tracker.h"
struct sdesc {
@@ -316,5 +317,21 @@ module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
bool is_manager_apk(char *path)
{
int tries = 0;
while (tries++ < 10) {
if (!is_lock_held(path))
break;
pr_info("%s: waiting for %s\n", __func__, path);
msleep(100);
}
// let it go, if retry fails, check_v2_signature will fail to open it anyway
if (tries == 10) {
pr_info("%s: timeout for %s\n", __func__, path);
return false;
}
return check_v2_signature(path, EXPECTED_NEXT_SIZE, EXPECTED_NEXT_HASH);
}
}

View File

@@ -118,6 +118,7 @@ static void setup_groups(struct root_profile *profile, struct cred *cred)
groups_sort(group_info);
set_groups(cred, group_info);
put_group_info(group_info);
}
static void disable_seccomp(void)
@@ -142,27 +143,17 @@ void escape_to_root(void)
{
struct cred *cred;
#ifdef KSU_GET_CRED_RCU
rcu_read_lock();
do {
cred = (struct cred *)__task_cred((current));
BUG_ON(!cred);
} while (!get_cred_rcu(cred));
cred = prepare_creds();
if (!cred) {
pr_warn("prepare_creds failed!\n");
return;
}
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
rcu_read_unlock();
abort_creds(cred);
return;
}
#else
cred = (struct cred *)__task_cred(current);
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
return;
}
#endif
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
@@ -198,9 +189,7 @@ void escape_to_root(void)
setup_groups(profile, cred);
#ifdef KSU_GET_CRED_RCU
rcu_read_unlock();
#endif
commit_creds(cred);
// Refer to kernel/seccomp.c: seccomp_set_mode_strict
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
@@ -267,7 +256,7 @@ static void nuke_ext4_sysfs() {
}
ext4_unregister_sysfs(sb);
path_put(&path);
path_put(&path);
}
int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
@@ -580,11 +569,13 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
if (path.dentry != path.mnt->mnt_root) {
// it is not root mountpoint, maybe umounted by others already.
path_put(&path);
return;
}
// we are only interest in some specific mounts
if (check_mnt && !should_umount(&path)) {
path_put(&path);
return;
}

View File

@@ -396,10 +396,12 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
if (orig_read) {
fops_proxy.read = read_proxy;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
orig_read_iter = file->f_op->read_iter;
if (orig_read_iter) {
fops_proxy.read_iter = read_iter_proxy;
}
#endif
// replace the file_operations
file->f_op = &fops_proxy;
read_count_append = rc_count;
@@ -632,6 +634,29 @@ static void do_stop_input_hook(struct work_struct *work)
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
#include "objsec.h" // task_security_struct
bool is_ksu_transition(const struct task_security_struct *old_tsec,
const struct task_security_struct *new_tsec)
{
static u32 ksu_sid;
char *secdata;
u32 seclen;
bool allowed = false;
if (!ksu_sid)
security_secctx_to_secid("u:r:su:s0", strlen("u:r:su:s0"), &ksu_sid);
if (security_secid_to_secctx(old_tsec->sid, &secdata, &seclen))
return false;
allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid);
security_release_secctx(secdata, seclen);
return allowed;
}
#endif
static void stop_vfs_read_hook()
{
#ifdef CONFIG_KSU_KPROBES_HOOK

View File

@@ -5,7 +5,6 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/namei.h>
#include "allowlist.h"
#include "klog.h" // IWYU pragma: keep
@@ -14,13 +13,9 @@
#include "throne_tracker.h"
#include "kernel_compat.h"
#include <linux/kthread.h>
#include <linux/sched.h>
uid_t ksu_manager_uid = KSU_INVALID_UID;
static struct task_struct *throne_thread;
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list.tmp"
struct uid_data {
struct list_head list;
@@ -120,7 +115,6 @@ struct my_dir_context {
void *private_data;
int depth;
int *stop;
struct super_block* root_sb;
};
// https://docs.kernel.org/filesystems/porting.html
// filldir_t (readdir callbacks) calling conventions have changed. Instead of returning 0 or -E... it returns bool now. false means "no more" (as -E... used to) and true - "keep going" (as 0 in old calling conventions). Rationale: callers never looked at specific -E... values anyway. -> iterate_shared() instances require no changes at all, all filldir_t ones in the tree converted.
@@ -141,8 +135,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
struct my_dir_context *my_ctx =
container_of(ctx, struct my_dir_context, ctx);
char dirpath[DATA_PATH_LEN];
int err;
struct path path;
if (!my_ctx) {
pr_err("Invalid context\n");
@@ -169,18 +161,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
return FILLDIR_ACTOR_CONTINUE;
}
err = kern_path(dirpath, 0, &path);
if (err) {
pr_err("get dirpath %s err: %d\n", dirpath, err);
return FILLDIR_ACTOR_CONTINUE;
}
if (my_ctx->root_sb != path.dentry->d_inode->i_sb) {
pr_info("skip cross fs: %s", dirpath);
return FILLDIR_ACTOR_CONTINUE;
}
if (d_type == DT_DIR && my_ctx->depth > 0 &&
(my_ctx->stop && !*my_ctx->stop)) {
struct data_path *data = kmalloc(sizeof(struct data_path), GFP_ATOMIC);
@@ -236,21 +216,53 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
return FILLDIR_ACTOR_CONTINUE;
}
void search_manager(const char *path, int depth, struct list_head *uid_data)
/*
* small helper to check if lock is held
* false - file is stable
* true - file is being deleted/renamed
* possibly optional
*
*/
bool is_lock_held(const char *path)
{
int i, stop = 0, err;
struct list_head data_path_list;
struct path kpath;
struct super_block* root_sb;
INIT_LIST_HEAD(&data_path_list);
err = kern_path(path, 0, &kpath);
// kern_path returns 0 on success
if (kern_path(path, 0, &kpath))
return true;
if (err) {
pr_err("get search root %s err: %d\n", path, err);
return;
// just being defensive
if (!kpath.dentry) {
path_put(&kpath);
return true;
}
if (!spin_trylock(&kpath.dentry->d_lock)) {
pr_info("%s: lock held, bail out!\n", __func__);
path_put(&kpath);
return true;
}
// we hold it ourselves here!
spin_unlock(&kpath.dentry->d_lock);
path_put(&kpath);
return false;
}
// compat: https://elixir.bootlin.com/linux/v3.9/source/include/linux/fs.h#L771
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
#define S_MAGIC_COMPAT(x) ((x)->f_inode->i_sb->s_magic)
#else
#define S_MAGIC_COMPAT(x) ((x)->f_path.dentry->d_inode->i_sb->s_magic)
#endif
void search_manager(const char *path, int depth, struct list_head *uid_data)
{
int i, stop = 0;
struct list_head data_path_list;
INIT_LIST_HEAD(&data_path_list);
unsigned long data_app_magic = 0;
// Initialize APK cache list
struct apk_path_hash *pos, *n;
list_for_each_entry(pos, &apk_path_hash_list, list) {
@@ -267,8 +279,6 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
data.depth = depth;
list_add_tail(&data.list, &data_path_list);
root_sb = kpath.dentry->d_inode->i_sb;
for (i = depth; i >= 0; i--) {
struct data_path *pos, *n;
@@ -278,8 +288,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
.parent_dir = pos->dirpath,
.private_data = uid_data,
.depth = pos->depth,
.stop = &stop,
.root_sb = root_sb };
.stop = &stop };
struct file *file;
if (!stop) {
@@ -288,6 +297,24 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file));
goto skip_iterate;
}
// grab magic on first folder, which is /data/app
if (!data_app_magic) {
if (S_MAGIC_COMPAT(file)) {
data_app_magic = S_MAGIC_COMPAT(file);
pr_info("%s: dir: %s got magic! 0x%lx\n", __func__, pos->dirpath, data_app_magic);
} else {
filp_close(file, NULL);
goto skip_iterate;
}
}
if (S_MAGIC_COMPAT(file) != data_app_magic) {
pr_info("%s: skip: %s magic: 0x%lx expected: 0x%lx\n", __func__, pos->dirpath,
S_MAGIC_COMPAT(file), data_app_magic);
filp_close(file, NULL);
goto skip_iterate;
}
iterate_dir(file, &ctx.ctx);
filp_close(file, NULL);
@@ -324,15 +351,27 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
return exist;
}
static void track_throne_function()
void track_throne()
{
struct file *fp =
ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
struct file *fp;
int tries = 0;
while (tries++ < 10) {
if (!is_lock_held(SYSTEM_PACKAGES_LIST_PATH)) {
fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
if (!IS_ERR(fp))
break;
}
pr_info("%s: waiting for %s\n", __func__, SYSTEM_PACKAGES_LIST_PATH);
msleep(100); // migth as well add a delay
};
if (IS_ERR(fp)) {
pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n",
__func__, PTR_ERR(fp));
pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp));
return;
}
} else
pr_info("%s: %s found!\n", __func__, SYSTEM_PACKAGES_LIST_PATH);
struct list_head uid_list;
INIT_LIST_HEAD(&uid_list);
@@ -419,23 +458,6 @@ out:
}
}
static int throne_tracker_thread(void *data)
{
pr_info("%s: pid: %d started\n", __func__, current->pid);
track_throne_function();
throne_thread = NULL;
pr_info("%s: pid: %d exit!\n", __func__, current->pid);
return 0;
}
void track_throne()
{
throne_thread = kthread_run(throne_tracker_thread, NULL, "throne_tracker");
if (IS_ERR(throne_thread)) {
throne_thread = NULL;
}
}
void ksu_throne_tracker_init()
{
// nothing to do

View File

@@ -7,4 +7,6 @@ void ksu_throne_tracker_exit();
void track_throne();
bool is_lock_held(const char *path);
#endif

View File

@@ -24,6 +24,15 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/zip" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:pathPattern=".*\\.zip" />
</intent-filter>
</activity>
<activity

View File

@@ -51,12 +51,13 @@ bool become_manager(const char* pkg) {
}
// cache the result to avoid unnecessary syscall
static bool is_lkm;
int get_version() {
static bool is_lkm = false;
int get_version(void) {
int32_t version = -1;
int32_t lkm = 0;
ksuctl(CMD_GET_VERSION, &version, &lkm);
if (!is_lkm && lkm != 0) {
int32_t flags = 0;
ksuctl(CMD_GET_VERSION, &version, &flags);
if (!is_lkm && (flags & 0x1)) {
is_lkm = true;
}
return version;
@@ -103,4 +104,4 @@ bool is_su_enabled() {
// if ksuctl failed, we assume su is enabled, and it cannot be disabled.
ksuctl(CMD_IS_SU_ENABLED, &enabled, nullptr);
return enabled;
}
}

View File

@@ -11,10 +11,6 @@ import okhttp3.Cache
import okhttp3.OkHttpClient
import java.io.File
import java.util.Locale
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import com.rifsxd.ksunext.ui.webui.initPlatform
lateinit var ksuApp: KernelSUApplication
@@ -28,9 +24,6 @@ class KernelSUApplication : Application() {
Platform.setHiddenApiExemptions()
// Pre-initialize WX Platform as early as possible
launchPlatformInit()
val context = this
val iconSize = resources.getDimensionPixelSize(android.R.dimen.app_icon_size)
Coil.setImageLoader(
@@ -61,11 +54,5 @@ class KernelSUApplication : Application() {
}.build()
}
private fun launchPlatformInit() {
// Use a coroutine to avoid blocking the main thread
GlobalScope.launch(Dispatchers.IO) {
initPlatform()
}
}
}

View File

@@ -1,5 +1,7 @@
package com.rifsxd.ksunext.ui
import android.content.Intent
import android.net.Uri
import android.content.Context
import android.os.Build
import android.os.Bundle
@@ -22,6 +24,8 @@ import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.union
import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
@@ -36,6 +40,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
@@ -51,12 +56,22 @@ import com.rifsxd.ksunext.Natives
import com.rifsxd.ksunext.ksuApp
import com.rifsxd.ksunext.ui.screen.BottomBarDestination
import com.rifsxd.ksunext.ui.theme.KernelSUTheme
import com.rifsxd.ksunext.ui.util.*
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
import com.rifsxd.ksunext.ui.util.LocaleHelper
import com.rifsxd.ksunext.ui.util.rootAvailable
import com.rifsxd.ksunext.ui.util.install
import com.rifsxd.ksunext.ui.util.isSuCompatDisabled
import com.rifsxd.ksunext.ui.screen.FlashIt
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
import com.rifsxd.ksunext.ui.webui.initPlatform
class MainActivity : ComponentActivity() {
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase?.let { LocaleHelper.applyLanguage(it) })
}
override fun onCreate(savedInstanceState: Bundle?) {
// Enable edge to edge
@@ -70,11 +85,40 @@ class MainActivity : ComponentActivity() {
val isManager = Natives.becomeManager(ksuApp.packageName)
if (isManager) install()
val zipUri: Uri? = when (intent?.action) {
Intent.ACTION_VIEW, Intent.ACTION_SEND -> {
val uri = intent.data ?: intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
uri?.let {
val name = when (it.scheme) {
"file" -> it.lastPathSegment ?: ""
"content" -> {
contentResolver.query(it, null, null, null, null)?.use { cursor ->
val nameIndex = cursor.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)
if (cursor.moveToFirst() && nameIndex != -1) {
cursor.getString(nameIndex)
} else {
it.lastPathSegment ?: ""
}
} ?: (it.lastPathSegment ?: "")
}
else -> it.lastPathSegment ?: ""
}
if (name.lowercase().endsWith(".zip")) it else null
}
}
else -> null
}
setContent {
// Read AMOLED mode preference
val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
val amoledMode = prefs.getBoolean("enable_amoled", false)
val moduleViewModel: ModuleViewModel = viewModel()
val moduleUpdateCount = moduleViewModel.moduleList.count {
moduleViewModel.checkUpdate(it).first.isNotEmpty()
}
KernelSUTheme (
amoledMode = amoledMode
) {
@@ -82,12 +126,30 @@ class MainActivity : ComponentActivity() {
val snackBarHostState = remember { SnackbarHostState() }
val currentDestination = navController.currentBackStackEntryAsState()?.value?.destination
val navigator = navController.rememberDestinationsNavigator()
LaunchedEffect(zipUri) {
if (zipUri != null) {
navigator.navigate(
FlashScreenDestination(
FlashIt.FlashModules(listOf(zipUri)),
finishIntent = true
)
)
}
}
val showBottomBar = when (currentDestination?.route) {
FlashScreenDestination.route -> false // Hide for FlashScreenDestination
ExecuteModuleActionScreenDestination.route -> false // Hide for ExecuteModuleActionScreen
else -> true
}
// pre-init platform to faster start WebUI X activities
LaunchedEffect(Unit) {
initPlatform()
}
Scaffold(
bottomBar = {
AnimatedVisibility(
@@ -95,7 +157,7 @@ class MainActivity : ComponentActivity() {
enter = slideInVertically(initialOffsetY = { it }) + fadeIn(),
exit = slideOutVertically(targetOffsetY = { it }) + fadeOut()
) {
BottomBar(navController)
BottomBar(navController, moduleUpdateCount)
}
},
contentWindowInsets = WindowInsets(0, 0, 0, 0)
@@ -122,43 +184,70 @@ class MainActivity : ComponentActivity() {
}
@Composable
private fun BottomBar(navController: NavHostController) {
private fun BottomBar(navController: NavHostController, moduleUpdateCount: Int) {
val navigator = navController.rememberDestinationsNavigator()
val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
val suCompatDisabled = isSuCompatDisabled()
val suSFS = getSuSFS()
val susSUMode = susfsSUS_SU_Mode()
NavigationBar(
tonalElevation = 8.dp,
windowInsets = WindowInsets.systemBars.union(WindowInsets.displayCutout).only(
WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
)
) {
BottomBarDestination.entries.forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
NavigationBarItem(
selected = isCurrentDestOnBackStack,
onClick = {
if (isCurrentDestOnBackStack) {
navigator.popBackStack(destination.direction, false)
}
navigator.navigate(destination.direction) {
popUpTo(NavGraphs.root) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
},
icon = {
if (isCurrentDestOnBackStack) {
Icon(destination.iconSelected, stringResource(destination.label))
BottomBarDestination.entries
.filter {
// Hide SuperUser and Module when su compat is disabled
if (suCompatDisabled) {
if (suSFS == "Supported" && susSUMode == "2") {
true
} else {
Icon(destination.iconNotSelected, stringResource(destination.label))
// hide SuperUser and Module
it != BottomBarDestination.SuperUser && it != BottomBarDestination.Module
}
},
label = { Text(stringResource(destination.label)) },
alwaysShowLabel = true
)
}
} else true
}
.forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
NavigationBarItem(
selected = isCurrentDestOnBackStack,
onClick = {
if (isCurrentDestOnBackStack) {
navigator.popBackStack(destination.direction, false)
}
navigator.navigate(destination.direction) {
popUpTo(NavGraphs.root) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
},
icon = {
// Show badge for Module icon if moduleUpdateCount > 0
if (destination == BottomBarDestination.Module && moduleUpdateCount > 0) {
BadgedBox(badge = { Badge { Text(moduleUpdateCount.toString()) } }) {
if (isCurrentDestOnBackStack) {
Icon(destination.iconSelected, stringResource(destination.label))
} else {
Icon(destination.iconNotSelected, stringResource(destination.label))
}
}
} else {
if (isCurrentDestOnBackStack) {
Icon(destination.iconSelected, stringResource(destination.label))
} else {
Icon(destination.iconNotSelected, stringResource(destination.label))
}
}
},
label = { Text(stringResource(destination.label)) },
alwaysShowLabel = true
)
}
}
}

View File

@@ -56,6 +56,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.dropUnlessResumed
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
@@ -94,6 +95,7 @@ fun AppProfileScreen(
val snackBarHost = LocalSnackbarHost.current
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
val scope = rememberCoroutineScope()
val viewModel: SuperUserViewModel = viewModel()
val failToUpdateAppProfile = stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
val failToUpdateSepolicy = stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
val suNotAllowed = stringResource(R.string.su_not_allowed).format(appInfo.label)
@@ -160,6 +162,7 @@ fun AppProfileScreen(
snackBarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
} else {
profile = it
viewModel.updateAppProfile(packageName, it)
}
}
},

View File

@@ -165,9 +165,7 @@ fun BackupRestoreScreen(navigator: DestinationsNavigator) {
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var useOverlayFs by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_overlay_fs", false)
)
mutableStateOf(readMountSystemFile())
}
val moduleRestore = stringResource(id = R.string.module_restore)

View File

@@ -3,6 +3,7 @@ package com.rifsxd.ksunext.ui.screen
import android.content.Context
import android.content.Intent
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
@@ -17,6 +18,7 @@ import androidx.compose.material.icons.filled.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
@@ -28,7 +30,9 @@ import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
@@ -39,6 +43,11 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.dropUnlessResumed
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -46,10 +55,12 @@ import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import com.rifsxd.ksunext.Natives
import com.rifsxd.ksunext.ksuApp
import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ui.component.rememberCustomDialog
import com.rifsxd.ksunext.ui.component.SwitchItem
import com.rifsxd.ksunext.ui.util.LocaleHelper
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
import com.rifsxd.ksunext.ui.util.*
import java.util.Locale
/**
* @author rifsxd
@@ -90,35 +101,177 @@ fun CustomizationScreen(navigator: DestinationsNavigator) {
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var useLagacyUI by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_legacyui", false)
)
// Track language state with current app locale
var currentAppLocale by remember { mutableStateOf(LocaleHelper.getCurrentAppLocale(context)) }
// Listen for preference changes
LaunchedEffect(Unit) {
currentAppLocale = LocaleHelper.getCurrentAppLocale(context)
}
SwitchItem(
icon = Icons.Filled.Dashboard,
title = stringResource(id = R.string.settings_legacyui),
summary = stringResource(id = R.string.settings_legacyui_summary),
checked = useLagacyUI
) {
prefs.edit().putBoolean("use_legacyui", it).apply()
useLagacyUI = it
// Language setting with selection dialog
val languageDialog = rememberCustomDialog { dismiss ->
// Check if should use system language settings
if (LocaleHelper.useSystemLanguageSettings) {
// Android 13+ - Jump to system settings
LocaleHelper.launchSystemLanguageSettings(context)
dismiss()
} else {
// Android < 13 - Show app language selector
// Dynamically detect supported locales from resources
val supportedLocales = remember {
val locales = mutableListOf<java.util.Locale>()
// Add system default first
locales.add(java.util.Locale.ROOT) // This will represent "System Default"
// Dynamically detect available locales by checking resource directories
val resourceDirs = listOf(
"ar", "bg", "de", "fa", "fr", "hu", "in", "it",
"ja", "ko", "pl", "pt-rBR", "ru", "th", "tr",
"uk", "vi", "zh-rCN", "zh-rTW"
)
resourceDirs.forEach { dir ->
try {
val locale = when {
dir.contains("-r") -> {
val parts = dir.split("-r")
java.util.Locale.Builder()
.setLanguage(parts[0])
.setRegion(parts[1])
.build()
}
else -> java.util.Locale.Builder()
.setLanguage(dir)
.build()
}
// Test if this locale has translated resources
val config = android.content.res.Configuration()
config.setLocale(locale)
val localizedContext = context.createConfigurationContext(config)
// Try to get a translated string to verify the locale is supported
val testString = localizedContext.getString(R.string.settings_language)
val defaultString = context.getString(R.string.settings_language)
// If the string is different or it's English, it's supported
if (testString != defaultString || locale.language == "en") {
locales.add(locale)
}
} catch (e: Exception) {
// Skip unsupported locales
}
}
// Sort by display name
val sortedLocales = locales.drop(1).sortedBy { it.getDisplayName(it) }
mutableListOf<java.util.Locale>().apply {
add(locales.first()) // System default first
addAll(sortedLocales)
}
}
val allOptions = supportedLocales.map { locale ->
val tag = if (locale == java.util.Locale.ROOT) {
"system"
} else if (locale.country.isEmpty()) {
locale.language
} else {
"${locale.language}_${locale.country}"
}
val displayName = if (locale == java.util.Locale.ROOT) {
context.getString(R.string.system_default)
} else {
locale.getDisplayName(locale)
}
tag to displayName
}
val currentLocale = prefs.getString("app_locale", "system") ?: "system"
val options = allOptions.map { (tag, displayName) ->
ListOption(
titleText = displayName,
selected = currentLocale == tag
)
}
var selectedIndex by remember {
mutableIntStateOf(allOptions.indexOfFirst { (tag, _) -> currentLocale == tag })
}
ListDialog(
state = rememberUseCaseState(
visible = true,
onFinishedRequest = {
if (selectedIndex >= 0 && selectedIndex < allOptions.size) {
val newLocale = allOptions[selectedIndex].first
prefs.edit().putString("app_locale", newLocale).apply()
// Update local state immediately
currentAppLocale = LocaleHelper.getCurrentAppLocale(context)
// Apply locale change immediately for Android < 13
LocaleHelper.restartActivity(context)
}
dismiss()
},
onCloseRequest = {
dismiss()
}
),
header = Header.Default(
title = stringResource(R.string.settings_language),
),
selection = ListSelection.Single(
showRadioButtons = true,
options = options
) { index, _ ->
selectedIndex = index
}
)
}
}
val language = stringResource(id = R.string.settings_language)
// Compute display name based on current app locale (similar to the reference implementation)
val currentLanguageDisplay = remember(currentAppLocale) {
val locale = currentAppLocale
if (locale != null) {
locale.getDisplayName(locale)
} else {
context.getString(R.string.system_default)
}
}
ListItem(
leadingContent = { Icon(Icons.Filled.Translate, language) },
headlineContent = { Text(language) },
supportingContent = { Text(currentLanguageDisplay) },
modifier = Modifier.clickable {
languageDialog.show()
}
)
var useBanner by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_banner", true)
)
}
SwitchItem(
enabled = !useLagacyUI,
icon = Icons.Filled.ViewCarousel,
title = stringResource(id = R.string.settings_banner),
summary = stringResource(id = R.string.settings_banner_summary),
checked = useBanner
) {
prefs.edit().putBoolean("use_banner", it).apply()
useBanner = it
if (ksuVersion != null) {
SwitchItem(
icon = Icons.Filled.ViewCarousel,
title = stringResource(id = R.string.settings_banner),
summary = stringResource(id = R.string.settings_banner_summary),
checked = useBanner
) {
prefs.edit().putBoolean("use_banner", it).apply()
useBanner = it
}
}
var enableAmoled by rememberSaveable {

View File

@@ -0,0 +1,185 @@
package com.rifsxd.ksunext.ui.screen
import android.content.Context
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.*
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
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.input.nestedscroll.nestedScroll
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 com.dergoogler.mmrl.platform.Platform
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.launch
import com.rifsxd.ksunext.Natives
import com.rifsxd.ksunext.ksuApp
import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ui.component.SwitchItem
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
import com.rifsxd.ksunext.ui.util.*
/**
* @author rifsxd
* @date 2025/6/15.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@Composable
fun DeveloperScreen(navigator: DestinationsNavigator) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val snackBarHost = LocalSnackbarHost.current
val isManager = Natives.becomeManager(ksuApp.packageName)
val ksuVersion = if (isManager) Natives.version else null
Scaffold(
topBar = {
TopBar(
onBack = { navigator.popBackStack() },
scrollBehavior = scrollBehavior
)
},
snackbarHost = { SnackbarHost(snackBarHost) },
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { paddingValues ->
Column(
modifier = Modifier
.padding(paddingValues)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
// --- Developer Options Switch ---
var developerOptionsEnabled by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_developer_options", false)
)
}
if (ksuVersion != null) {
SwitchItem(
icon = Icons.Filled.DeveloperMode,
title = stringResource(id = R.string.enable_developer_options),
summary = stringResource(id = R.string.enable_developer_options_summary),
checked = developerOptionsEnabled
) {
prefs.edit().putBoolean("enable_developer_options", it).apply()
developerOptionsEnabled = it
}
}
var useWebUIX by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_webuix", true)
)
}
if (ksuVersion != null) {
SwitchItem(
beta = false,
enabled = Platform.isAlive && developerOptionsEnabled,
icon = Icons.Filled.WebAsset,
title = stringResource(id = R.string.use_webuix),
summary = stringResource(id = R.string.use_webuix_summary),
checked = useWebUIX
) {
prefs.edit().putBoolean("use_webuix", it).apply()
useWebUIX = it
}
}
var enableWebDebugging by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_web_debugging", false)
)
}
if (ksuVersion != null) {
SwitchItem(
enabled = developerOptionsEnabled,
icon = Icons.Filled.Web,
title = stringResource(id = R.string.enable_web_debugging),
summary = stringResource(id = R.string.enable_web_debugging_summary),
checked = enableWebDebugging
) {
prefs.edit().putBoolean("enable_web_debugging", it).apply()
enableWebDebugging = it
}
}
var useWebUIXEruda by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_webuix_eruda", false)
)
}
if (ksuVersion != null) {
SwitchItem(
beta = false,
enabled = Platform.isAlive && useWebUIX && enableWebDebugging,
icon = Icons.Filled.FormatListNumbered,
title = stringResource(id = R.string.use_webuix_eruda),
summary = stringResource(id = R.string.use_webuix_eruda_summary),
checked = useWebUIXEruda
) {
prefs.edit().putBoolean("use_webuix_eruda", it).apply()
useWebUIXEruda = it
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
onBack: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
) {
TopAppBar(
title = { Text(stringResource(R.string.developer)) }, navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
)
}
@Preview
@Composable
private fun DeveloperPreview() {
DeveloperScreen(EmptyDestinationsNavigator)
}

View File

@@ -63,6 +63,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ui.component.rememberConfirmDialog
import com.rifsxd.ksunext.ui.component.ConfirmResult
import com.rifsxd.ksunext.ui.component.KeyEventBlocker
import com.rifsxd.ksunext.ui.util.FlashResult
import com.rifsxd.ksunext.ui.util.LkmSelection
@@ -77,12 +79,21 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import androidx.compose.ui.platform.LocalContext
import android.app.Activity
enum class FlashingStatus {
FLASHING,
SUCCESS,
FAILED
}
fun Context.findActivity(): Activity? = when (this) {
is Activity -> this
is android.content.ContextWrapper -> baseContext.findActivity()
else -> null
}
// Lets you flash modules sequentially when mutiple zipUris are selected
fun flashModulesSequentially(
uris: List<Uri>,
@@ -106,7 +117,11 @@ fun flashModulesSequentially(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@Destination<RootGraph>
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
fun FlashScreen(
navigator: DestinationsNavigator,
flashIt: FlashIt,
finishIntent: Boolean = false
) {
var text by rememberSaveable { mutableStateOf("") }
var tempText: String
@@ -126,6 +141,8 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val developerOptionsEnabled = prefs.getBoolean("enable_developer_options", false)
val activity = context.findActivity()
val view = LocalView.current
DisposableEffect(flashing) {
view.keepScreenOn = flashing == FlashingStatus.FLASHING
@@ -134,16 +151,49 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
}
}
BackHandler(enabled = flashing == FlashingStatus.FLASHING) {
// Disable back button if flashing is running
BackHandler(enabled = flashing != FlashingStatus.FLASHING) {
navigator.popBackStack()
if (finishIntent) activity?.finish()
}
LaunchedEffect(Unit) {
if (text.isNotEmpty()) {
return@LaunchedEffect
val confirmDialog = rememberConfirmDialog()
var confirmed by rememberSaveable { mutableStateOf(flashIt !is FlashIt.FlashModules) }
var pendingFlashIt by rememberSaveable { mutableStateOf<FlashIt?>(null) }
var hasFlashed by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(flashIt) {
if (flashIt is FlashIt.FlashModules && !confirmed) {
val uris = flashIt.uris
val moduleNames =
uris.mapIndexed { index, uri -> "\n${index + 1}. ${uri.getFileName(context)}" }
.joinToString("")
val confirmContent =
context.getString(R.string.module_install_prompt_with_name, moduleNames)
val confirmTitle = context.getString(R.string.module)
val result = confirmDialog.awaitConfirm(
title = confirmTitle,
content = confirmContent,
markdown = true
)
if (result == ConfirmResult.Confirmed) {
confirmed = true
pendingFlashIt = flashIt
} else {
// User cancelled, go back
navigator.popBackStack()
if (finishIntent) activity?.finish()
}
} else {
confirmed = true
pendingFlashIt = flashIt
}
}
LaunchedEffect(confirmed, pendingFlashIt) {
if (!confirmed || pendingFlashIt == null || text.isNotEmpty() || hasFlashed) return@LaunchedEffect
hasFlashed = true
withContext(Dispatchers.IO) {
flashIt(flashIt, onStdout = {
flashIt(pendingFlashIt!!, onStdout = {
tempText = "$it\n"
if (tempText.startsWith("")) { // clear command
text = tempText.substring(6)
@@ -172,6 +222,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
flashing,
onBack = dropUnlessResumed {
navigator.popBackStack()
if (finishIntent) activity?.finish()
},
onSave = {
scope.launch {
@@ -211,6 +262,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
icon = { Icon(Icons.Filled.Close, contentDescription = null) },
onClick = {
navigator.popBackStack()
if (finishIntent) activity?.finish()
}
)
}
@@ -282,6 +334,19 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
}
}
fun Uri.getFileName(context: Context): String {
val contentResolver = context.contentResolver
val cursor = contentResolver.query(this, null, null, null, null)
return cursor?.use {
val nameIndex = it.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)
if (it.moveToFirst() && nameIndex != -1) {
it.getString(nameIndex)
} else {
this.lastPathSegment ?: "unknown.zip"
}
} ?: (this.lastPathSegment ?: "unknown.zip")
}
@Parcelize
sealed class FlashIt : Parcelable {
data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean) :

View File

@@ -8,8 +8,12 @@ import android.os.Looper
import android.system.Os
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.animation.*
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@@ -107,11 +111,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
}
}
val moduleUpdateCount = moduleViewModel.moduleList.count {
moduleViewModel.checkUpdate(it).first.isNotEmpty()
}
StatusCard(kernelVersion, ksuVersion, lkmMode, moduleUpdateCount) {
StatusCard(kernelVersion, ksuVersion, lkmMode) {
navigator.navigate(InstallScreenDestination)
}
if (isManager && Natives.requireNewKernel()) {
@@ -193,6 +193,19 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
})
}
@Composable
fun getSeasonalIcon(): ImageVector {
val month = Calendar.getInstance().get(Calendar.MONTH) // 0-11 for January-December
return when (month) {
Calendar.DECEMBER, Calendar.JANUARY, Calendar.FEBRUARY -> Icons.Filled.AcUnit // Winter
Calendar.MARCH, Calendar.APRIL, Calendar.MAY -> Icons.Filled.Spa // Spring
Calendar.JUNE, Calendar.JULY, Calendar.AUGUST -> Icons.Filled.WbSunny // Summer
Calendar.SEPTEMBER, Calendar.OCTOBER, Calendar.NOVEMBER -> Icons.Filled.Forest // Fall
else -> Icons.Filled.Whatshot // Fallback icon
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
@@ -201,8 +214,42 @@ private fun TopBar(
onInstallClick: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior? = null
) {
var isSpinning by remember { mutableStateOf(false) }
val rotation by animateFloatAsState(
targetValue = if (isSpinning) 360f else 0f,
animationSpec = tween(durationMillis = 800),
finishedListener = {
isSpinning = false
}
)
LaunchedEffect(Unit) {
isSpinning = true
}
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
title = {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
if (!isSpinning) isSpinning = true
}
) {
Icon(
imageVector = getSeasonalIcon(),
contentDescription = null,
modifier = Modifier
.padding(end = 8.dp)
.graphicsLayer {
rotationZ = rotation
}
)
Text(stringResource(R.string.app_name))
}
},
actions = {
if (ksuVersion != null) {
if (kernelVersion.isGKI()) {
@@ -249,17 +296,6 @@ private fun TopBar(
)
}
@Composable
fun getSeasonalIcon(): ImageVector {
val month = Calendar.getInstance().get(Calendar.MONTH) // 0-11 for January-December
return when (month) {
Calendar.DECEMBER, Calendar.JANUARY, Calendar.FEBRUARY -> Icons.Filled.AcUnit // Winter
Calendar.MARCH, Calendar.APRIL, Calendar.MAY -> Icons.Filled.Spa // Spring
Calendar.JUNE, Calendar.JULY, Calendar.AUGUST -> Icons.Filled.WbSunny // Summer
Calendar.SEPTEMBER, Calendar.OCTOBER, Calendar.NOVEMBER -> Icons.Filled.Forest // Fall
else -> Icons.Filled.Whatshot // Fallback icon
}
}
@Composable
private fun StatusCard(
@@ -292,8 +328,10 @@ private fun StatusCard(
intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
if (ksuVersion != null) {
context.startActivity(intent)
} else {
} else if (kernelVersion.isGKI()) {
onClickInstall()
} else {
Toast.makeText(context, "Something weird happened... 🤔", Toast.LENGTH_SHORT).show()
}
} else if (ksuVersion == null && kernelVersion.isGKI()) {
onClickInstall()
@@ -312,7 +350,7 @@ private fun StatusCard(
}
Icon(
getSeasonalIcon(), // Use dynamic seasonal icon
imageVector = Icons.Filled.CheckCircle,
contentDescription = stringResource(R.string.home_working)
)
Column(
@@ -322,25 +360,49 @@ private fun StatusCard(
val labelStyle = LabelItemDefaults.style
TextRow(
trailingContent = {
LabelItem(
icon = if (Natives.isSafeMode) {
{
Icon(
tint = labelStyle.contentColor,
imageVector = Icons.Filled.Security,
contentDescription = null
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
LabelItem(
icon = if (Natives.isSafeMode) {
{
Icon(
tint = labelStyle.contentColor,
imageVector = Icons.Filled.Security,
contentDescription = null
)
}
} else {
null
},
text = {
Text(
text = workingMode,
style = labelStyle.textStyle.copy(color = labelStyle.contentColor),
)
}
} else {
null
},
text = {
Text(
text = workingMode,
style = labelStyle.textStyle.copy(color = labelStyle.contentColor),
)
if (isSuCompatDisabled()) {
LabelItem(
icon = {
Icon(
tint = labelStyle.contentColor,
imageVector = Icons.Filled.Warning,
contentDescription = null
)
},
text = {
Text(
text = stringResource(R.string.sucompat_disabled),
style = labelStyle.textStyle.copy(
color = labelStyle.contentColor,
)
)
}
)
}
)
}
}
) {
Text(
@@ -364,27 +426,11 @@ private fun StatusCard(
text = stringResource(R.string.home_module_count, getModuleCount()),
style = MaterialTheme.typography.bodyMedium
)
if (moduleUpdateCount > 0) {
Text(
text = stringResource(R.string.home_module_update_count, moduleUpdateCount),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary
)
}
val suSFS = getSuSFS()
if (suSFS == "Supported") {
Text(
text = "SuSFS: " + stringResource(R.string.susfs_supported),
style = MaterialTheme.typography.bodyMedium
)
}
}
}
kernelVersion.isGKI() -> {
Icon(Icons.Filled.Report, stringResource(R.string.home_not_installed))
Icon(Icons.Filled.NewReleases, stringResource(R.string.home_not_installed))
Column(Modifier.padding(start = 20.dp)) {
Text(
text = stringResource(R.string.home_not_installed),
@@ -399,7 +445,7 @@ private fun StatusCard(
}
else -> {
Icon(Icons.Filled.Dangerous, stringResource(R.string.home_failure))
Icon(Icons.Filled.Cancel, stringResource(R.string.home_failure))
Column(Modifier.padding(start = 20.dp)) {
Text(
text = stringResource(R.string.home_failure),
@@ -531,7 +577,7 @@ private fun InfoCard(autoExpand: Boolean = false) {
Spacer(Modifier.height(16.dp))
InfoCardItem(
label = stringResource(R.string.home_susfs_version),
content = "${getSuSFSVersion()} (${getSuSFSVariant()}) $susSUMode",
content = "${stringResource(R.string.susfs_supported)} | ${getSuSFSVersion()} (${getSuSFSVariant()}) $susSUMode",
icon = painterResource(R.drawable.ic_sus),
)
}

View File

@@ -234,7 +234,7 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
val rootAvailable = rootAvailable()
val isAbDevice = isAbDevice()
val selectFileTip = stringResource(
id = R.string.select_file_tip, if (isInitBoot()) "init_boot" else "boot"
id = R.string.select_file_tip, if (isInitBoot()) "init_boot/vendor_boot" else "boot"
)
val radioOptions =
mutableListOf<InstallMethod>(InstallMethod.SelectFile(summary = selectFileTip))

View File

@@ -9,10 +9,14 @@ import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -73,6 +77,7 @@ 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.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
@@ -84,7 +89,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
@@ -119,6 +123,7 @@ import com.rifsxd.ksunext.ui.util.reboot
import com.rifsxd.ksunext.ui.util.toggleModule
import com.rifsxd.ksunext.ui.util.uninstallModule
import com.rifsxd.ksunext.ui.util.restoreModule
import com.rifsxd.ksunext.ui.util.zygiskRequired
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
import com.rifsxd.ksunext.ui.webui.WebUIActivity
import com.rifsxd.ksunext.ui.webui.WebUIXActivity
@@ -287,12 +292,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
floatingActionButton = {
if (!hideInstallButton) {
val moduleInstall = stringResource(id = R.string.module_install)
val confirmTitle = stringResource(R.string.module)
var zipUris by remember { mutableStateOf<List<Uri>>(emptyList()) }
val confirmDialog = rememberConfirmDialog(onConfirm = {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(zipUris)))
viewModel.markNeedRefresh()
})
val selectZipLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { result ->
@@ -311,19 +310,13 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
data.data?.let { uris.add(it) }
}
// Show confirm dialog with selected zip file(s) name(s)
val moduleNames =
uris.mapIndexed { index, uri -> "\n${index + 1}. ${uri.getFileName(context)}" }
.joinToString("")
val confirmContent =
context.getString(R.string.module_install_prompt_with_name, moduleNames)
zipUris = uris
confirmDialog.showConfirm(
title = confirmTitle,
content = confirmContent,
markdown = true
)
if (uris.isEmpty()) return@rememberLauncherForActivityResult
viewModel.updateZipUris(uris)
navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(uris)))
viewModel.clearZipUris()
viewModel.markNeedRefresh()
}
ExtendedFloatingActionButton(
@@ -419,11 +412,13 @@ private fun ModuleList(
val rebootToApply = stringResource(R.string.reboot_to_apply)
val moduleStr = stringResource(R.string.module)
val uninstall = stringResource(R.string.uninstall)
val uninstalled = stringResource(R.string.uninstalled)
val restore = stringResource(R.string.restore)
val cancel = stringResource(android.R.string.cancel)
val moduleUninstallConfirm = stringResource(R.string.module_uninstall_confirm)
val moduleRestoreConfirm = stringResource(R.string.module_restore_confirm)
val updateText = stringResource(R.string.module_update)
val updateLable = stringResource(R.string.module_update_available)
val changelogText = stringResource(R.string.module_changelog)
val downloadingText = stringResource(R.string.module_downloading)
val startDownloadingText = stringResource(R.string.module_start_downloading)
@@ -437,6 +432,8 @@ private fun ModuleList(
val loadingDialog = rememberLoadingDialog()
val confirmDialog = rememberConfirmDialog()
var expandedModuleId by rememberSaveable { mutableStateOf<String?>(null) }
suspend fun onModuleUpdate(
module: ModuleViewModel.ModuleInfo,
changelogUrl: String,
@@ -659,6 +656,10 @@ private fun ModuleList(
},
onClick = {
onClickModule(it.dirId, it.name, it.hasWebUi)
},
expanded = expandedModuleId == module.id,
onExpandToggle = {
expandedModuleId = if (expandedModuleId == module.id) null else module.id
}
)
@@ -684,9 +685,18 @@ fun ModuleItem(
onCheckChanged: (Boolean) -> Unit,
onUpdate: (ModuleViewModel.ModuleInfo) -> Unit,
onClick: (ModuleViewModel.ModuleInfo) -> Unit,
expanded: Boolean,
onExpandToggle: () -> Unit,
) {
val viewModel = viewModel<ModuleViewModel>()
ElevatedCard(
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.medium)
.clickable(
onClick = onExpandToggle
)
) {
Box(
modifier = Modifier
@@ -694,11 +704,10 @@ fun ModuleItem(
) {
val context = LocalContext.current
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val useLagacyUI = prefs.getBoolean("use_legacyui", false)
val useBanner = prefs.getBoolean("use_banner", true)
if (useBanner && !useLagacyUI && module.banner.isNotEmpty()) {
if (useBanner && module.banner.isNotEmpty()) {
val isDark = isSystemInDarkTheme()
val colorScheme = MaterialTheme.colorScheme
val context = LocalContext.current
@@ -769,10 +778,7 @@ fun ModuleItem(
}
}
Column {
val textDecoration = if (!module.remove) null else TextDecoration.LineThrough
val interactionSource = remember { MutableInteractionSource() }
val indication = LocalIndication.current
val viewModel = viewModel<ModuleViewModel>()
var developerOptionsEnabled by rememberSaveable {
mutableStateOf(
@@ -780,116 +786,188 @@ fun ModuleItem(
)
}
val filterZygiskModules = zygiskAvailable() || !module.zygiskRequired
LaunchedEffect(Unit) {
developerOptionsEnabled = prefs.getBoolean("enable_developer_options", false)
}
if (useLagacyUI) {
Column(
modifier = Modifier
.padding(22.dp, 18.dp, 22.dp, 12.dp)
Column(
modifier = Modifier
.padding(22.dp, 18.dp, 22.dp, 12.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
val moduleVersion = stringResource(id = R.string.module_version)
val moduleAuthor = stringResource(id = R.string.module_author)
val moduleId = stringResource(id = R.string.module_id)
val moduleVersionCode = stringResource(id = R.string.module_version_code)
val moduleUpdateJson = stringResource(id = R.string.module_update_json)
val moduleUpdateJsonEmpty = stringResource(id = R.string.module_update_json_empty)
Column(
modifier = Modifier.fillMaxWidth(0.8f)
) {
val moduleVersion = stringResource(id = R.string.module_version)
val moduleAuthor = stringResource(id = R.string.module_author)
val moduleId = stringResource(id = R.string.module_id)
val moduleVersionCode = stringResource(id = R.string.module_version_code)
val moduleUpdateJson = stringResource(id = R.string.module_update_json)
val moduleUpdateJsonEmpty = stringResource(id = R.string.module_update_json_empty)
Column(
modifier = Modifier.fillMaxWidth(0.8f)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
Text(
text = module.name,
fontSize = MaterialTheme.typography.titleMedium.fontSize,
fontWeight = FontWeight.SemiBold,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.titleMedium.fontFamily,
textDecoration = textDecoration,
)
Text(
text = "$moduleVersion: ${module.version}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
Text(
text = "$moduleAuthor: ${module.author}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
if (developerOptionsEnabled) {
Text(
text = "$moduleId: ${module.id}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
LabelItem(
text = formatSize(module.size),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
)
Text(
text = "$moduleVersionCode: ${module.versionCode}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
if (module.remove) {
LabelItem(
text = stringResource(R.string.uninstalled),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.errorContainer,
contentColor = MaterialTheme.colorScheme.onErrorContainer
)
)
Text(
text = if (module.updateJson.isNotEmpty()) "$moduleUpdateJson: ${module.updateJson}" else "$moduleUpdateJson: $moduleUpdateJsonEmpty",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
}
if (!zygiskAvailable() && module.zygiskRequired && !module.remove) {
LabelItem(
text = stringResource(R.string.zygisk_required),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.errorContainer,
contentColor = MaterialTheme.colorScheme.onErrorContainer
)
)
}
if (updateUrl.isNotEmpty() && !module.remove && !module.update) {
LabelItem(
text = stringResource(R.string.module_update_available),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
)
)
}
if (!module.remove) {
if (module.update) {
LabelItem(
text = stringResource(R.string.module_updated),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
)
)
}
}
if (module.enabled && !module.remove) {
if (module.hasWebUi && filterZygiskModules) {
LabelItem(
text = stringResource(R.string.webui),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
)
)
}
if (module.hasActionScript && filterZygiskModules) {
LabelItem(
text = stringResource(R.string.action),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
)
)
}
}
}
Spacer(modifier = Modifier.weight(1f))
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End,
) {
Switch(
enabled = !module.update,
checked = module.enabled,
onCheckedChange = onCheckChanged,
interactionSource = if (!module.hasWebUi) interactionSource else null
Text(
text = module.name,
fontSize = MaterialTheme.typography.titleMedium.fontSize,
fontWeight = FontWeight.SemiBold,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.titleMedium.fontFamily
)
Text(
text = "$moduleVersion: ${module.version}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily
)
Text(
text = "$moduleAuthor: ${module.author}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily
)
if (developerOptionsEnabled) {
Text(
text = "$moduleId: ${module.id}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily
)
Text(
text = "$moduleVersionCode: ${module.versionCode}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily
)
Text(
text = if (module.updateJson.isNotEmpty()) "$moduleUpdateJson: ${module.updateJson}" else "$moduleUpdateJson: $moduleUpdateJsonEmpty",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily
)
}
}
Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.weight(1f))
Text(
text = module.description,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontWeight = MaterialTheme.typography.bodySmall.fontWeight,
overflow = TextOverflow.Ellipsis,
maxLines = 4,
textDecoration = textDecoration
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End,
) {
Switch(
enabled = !module.update,
checked = module.enabled,
onCheckedChange = onCheckChanged,
interactionSource = if (!module.hasWebUi) interactionSource else null
)
}
}
Spacer(modifier = Modifier.height(16.dp))
Spacer(modifier = Modifier.height(12.dp))
HorizontalDivider(thickness = Dp.Hairline)
Text(
text = module.description,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontWeight = MaterialTheme.typography.bodySmall.fontWeight,
overflow = TextOverflow.Ellipsis,
maxLines = 4
)
Spacer(modifier = Modifier.height(4.dp))
Spacer(modifier = Modifier.height(2.dp))
if (expanded) {
Spacer(modifier = Modifier.height(10.dp))
}
AnimatedVisibility(
visible = expanded,
enter = fadeIn() + expandVertically(),
exit = shrinkVertically() + fadeOut()
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
@@ -897,7 +975,7 @@ fun ModuleItem(
if (module.hasActionScript) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
enabled = !module.remove && module.enabled && filterZygiskModules,
onClick = {
navigator.navigate(ExecuteModuleActionScreenDestination(module.dirId))
viewModel.markNeedRefresh()
@@ -906,7 +984,7 @@ fun ModuleItem(
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.PlayArrow,
imageVector = Icons.Outlined.Terminal,
contentDescription = null
)
if (!module.hasWebUi && updateUrl.isEmpty()) {
@@ -925,7 +1003,7 @@ fun ModuleItem(
if (module.hasWebUi) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
enabled = !module.remove && module.enabled && filterZygiskModules,
onClick = { onClick(module) },
interactionSource = interactionSource,
contentPadding = ButtonDefaults.TextButtonContentPadding
@@ -948,7 +1026,7 @@ fun ModuleItem(
Spacer(modifier = Modifier.weight(1f, true))
if (updateUrl.isNotEmpty()) {
if (updateUrl.isNotEmpty() && !module.remove && !module.update) {
Button(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove,
@@ -1018,254 +1096,6 @@ fun ModuleItem(
}
}
}
} else {
Column(
modifier = Modifier
.padding(22.dp, 18.dp, 22.dp, 12.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
val moduleVersion = stringResource(id = R.string.module_version)
val moduleAuthor = stringResource(id = R.string.module_author)
val moduleId = stringResource(id = R.string.module_id)
val moduleVersionCode = stringResource(id = R.string.module_version_code)
val moduleUpdateJson = stringResource(id = R.string.module_update_json)
val moduleUpdateJsonEmpty = stringResource(id = R.string.module_update_json_empty)
Column(
modifier = Modifier.fillMaxWidth(0.8f)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
LabelItem(
text = formatSize(module.size),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
)
)
LabelItem(
text = if (module.enabled) stringResource(R.string.enabled) else stringResource(R.string.disabled),
style = if (module.enabled)
com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy()
else
com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.errorContainer,
contentColor = MaterialTheme.colorScheme.onErrorContainer
)
)
if (module.remove) {
LabelItem(
text = stringResource(R.string.uninstalled),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.errorContainer,
contentColor = MaterialTheme.colorScheme.onErrorContainer
)
)
}
if (updateUrl.isNotEmpty() && !module.remove && !module.update) {
LabelItem(
text = stringResource(R.string.module_update),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.onTertiary,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
)
)
}
if (!module.remove) {
if (module.update) {
LabelItem(
text = stringResource(R.string.module_updated),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
)
)
}
}
if (!module.remove) {
if (module.hasWebUi) {
LabelItem(
text = stringResource(R.string.webui),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
)
)
}
if (module.hasActionScript) {
LabelItem(
text = stringResource(R.string.action),
style = com.dergoogler.mmrl.ui.component.LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
)
)
}
}
}
Spacer(modifier = Modifier.height(8.dp))
Text(
text = module.name,
fontSize = MaterialTheme.typography.titleMedium.fontSize,
fontWeight = FontWeight.SemiBold,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.titleMedium.fontFamily,
textDecoration = textDecoration,
)
Text(
text = "$moduleVersion: ${module.version}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
Text(
text = "$moduleAuthor: ${module.author}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
if (developerOptionsEnabled) {
Text(
text = "$moduleId: ${module.id}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
Text(
text = "$moduleVersionCode: ${module.versionCode}",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
Text(
text = if (module.updateJson.isNotEmpty()) "$moduleUpdateJson: ${module.updateJson}" else "$moduleUpdateJson: $moduleUpdateJsonEmpty",
fontSize = MaterialTheme.typography.bodySmall.fontSize,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
textDecoration = textDecoration
)
}
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End,
) {
var expanded by remember { mutableStateOf(false) }
IconButton(onClick = { expanded = true }) {
Icon(
Icons.Filled.MoreVert,
contentDescription = "Module actions"
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
if (updateUrl.isNotEmpty() && !module.remove) {
DropdownMenuItem(
text = { Text(stringResource(R.string.module_update)) },
onClick = {
expanded = false
onUpdate(module)
}
)
HorizontalDivider()
}
if (!module.remove) {
if (module.hasWebUi) {
DropdownMenuItem(
text = { Text(stringResource(R.string.webui)) },
onClick = {
expanded = false
onClick(module)
}
)
}
if (module.hasActionScript) {
DropdownMenuItem(
text = { Text(stringResource(R.string.action)) },
onClick = {
expanded = false
navigator.navigate(ExecuteModuleActionScreenDestination(module.dirId))
viewModel.markNeedRefresh()
}
)
}
if (module.hasWebUi || module.hasActionScript ) {
HorizontalDivider()
}
}
if (!module.remove) {
DropdownMenuItem(
text = {
Text(
if (module.enabled) stringResource(R.string.disable)
else stringResource(R.string.enable)
)
},
onClick = {
expanded = false
onCheckChanged(!module.enabled)
}
)
}
if (module.remove) {
DropdownMenuItem(
text = { Text(stringResource(R.string.restore)) },
onClick = {
expanded = false
onRestore(module)
}
)
} else {
DropdownMenuItem(
text = { Text(stringResource(R.string.uninstall)) },
onClick = {
expanded = false
onUninstall(module)
}
)
}
}
}
}
Spacer(modifier = Modifier.height(12.dp))
Text(
text = module.description,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
fontWeight = MaterialTheme.typography.bodySmall.fontWeight,
overflow = TextOverflow.Ellipsis,
maxLines = 4,
textDecoration = textDecoration
)
Spacer(modifier = Modifier.height(6.dp))
}
}
}
}
@@ -1273,6 +1103,7 @@ fun ModuleItem(
}
fun formatSize(size: Long): String {
if (size == 0L) return "null"
val kb = 1024
val mb = kb * 1024
val gb = mb * 1024
@@ -1302,7 +1133,8 @@ fun ModuleItemPreview() {
hasActionScript = false,
dirId = "dirId",
size = 12345678L,
banner = ""
banner = "",
zygiskRequired = false
)
ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}, {})
ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}, {}, false, {})
}

View File

@@ -67,6 +67,7 @@ import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplat
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.generated.destinations.BackupRestoreScreenDestination
import com.ramcosta.composedestinations.generated.destinations.CustomizationScreenDestination
import com.ramcosta.composedestinations.generated.destinations.DeveloperScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
@@ -224,9 +225,11 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
var useOverlayFs by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_overlay_fs", false)
)
mutableStateOf(readMountSystemFile())
}
LaunchedEffect(Unit) {
useOverlayFs = readMountSystemFile()
}
var showRebootDialog by remember { mutableStateOf(false) }
@@ -244,8 +247,10 @@ fun SettingScreen(navigator: DestinationsNavigator) {
useOverlayFs = it
if (useOverlayFs) {
moduleBackup()
updateMountSystemFile(true)
} else {
moduleMigration()
updateMountSystemFile(false)
}
if (isManager) install()
showRebootDialog = true
@@ -289,78 +294,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
checkUpdate = it
}
var enableWebDebugging by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_web_debugging", false)
)
}
if (ksuVersion != null) {
SwitchItem(
icon = Icons.Filled.Web,
title = stringResource(id = R.string.enable_web_debugging),
summary = stringResource(id = R.string.enable_web_debugging_summary),
checked = enableWebDebugging
) {
prefs.edit().putBoolean("enable_web_debugging", it).apply()
enableWebDebugging = it
}
}
var developerOptionsEnabled by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_developer_options", false)
)
}
if (ksuVersion != null) {
SwitchItem(
icon = Icons.Filled.DeveloperMode,
title = stringResource(id = R.string.enable_developer_options),
summary = stringResource(id = R.string.enable_developer_options_summary),
checked = developerOptionsEnabled
) {
prefs.edit().putBoolean("enable_developer_options", it).apply()
developerOptionsEnabled = it
}
}
var useWebUIX by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_webuix", true)
)
}
if (ksuVersion != null) {
SwitchItem(
beta = false,
enabled = Platform.isAlive,
icon = Icons.Filled.WebAsset,
title = stringResource(id = R.string.use_webuix),
summary = stringResource(id = R.string.use_webuix_summary),
checked = useWebUIX
) {
prefs.edit().putBoolean("use_webuix", it).apply()
useWebUIX = it
}
}
var useWebUIXEruda by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_webuix_eruda", false)
)
}
if (ksuVersion != null) {
SwitchItem(
beta = false,
enabled = Platform.isAlive && useWebUIX && enableWebDebugging,
icon = Icons.Filled.FormatListNumbered,
title = stringResource(id = R.string.use_webuix_eruda),
summary = stringResource(id = R.string.use_webuix_eruda_summary),
checked = useWebUIXEruda
) {
prefs.edit().putBoolean("use_webuix_eruda", it).apply()
useWebUIXEruda = it
}
}
if (isOverlayAvailable && useOverlayFs) {
val shrink = stringResource(id = R.string.shrink_sparse_image)
val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message)
@@ -415,6 +348,22 @@ fun SettingScreen(navigator: DestinationsNavigator) {
)
}
val developer = stringResource(id = R.string.developer)
if (ksuVersion != null) {
ListItem(
leadingContent = {
Icon(
Icons.Filled.DeveloperBoard,
developer
)
},
headlineContent = { Text(developer) },
modifier = Modifier.clickable {
navigator.navigate(DeveloperScreenDestination)
}
)
}
val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
if (lkmMode) {
UninstallItem(navigator) {

View File

@@ -54,19 +54,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
}
}
LaunchedEffect(viewModel.search) {
if (viewModel.search.isEmpty()) {
listState.scrollToItem(0)
}
}
LaunchedEffect(Unit) {
if (viewModel.refreshOnReturn) {
viewModel.fetchAppList()
viewModel.refreshOnReturn = false
}
}
Scaffold(
topBar = {
SearchAppBar(
@@ -105,7 +92,7 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
}
)
}, onClick = {
viewModel.showSystemApps = !viewModel.showSystemApps
viewModel.updateShowSystemApps(!viewModel.showSystemApps)
showDropdown = false
})
}
@@ -131,7 +118,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
) {
items(viewModel.appList, key = { it.packageName + it.uid }) { app ->
AppItem(app) {
viewModel.refreshOnReturn = true
navigator.navigate(AppProfileScreenDestination(app))
}
}
@@ -177,10 +163,18 @@ private fun AppItem(
LabelItem(
text = "CUSTOM",
style = LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.onTertiary,
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
)
)
} else if (!app.allowSu && !Natives.uidShouldUmount(app.uid)) {
LabelItem(
text = "DEFAULT",
style = LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
)
)
}
}
}

View File

@@ -28,6 +28,7 @@ import java.io.File
* @date 2023/1/1.
*/
private const val TAG = "KsuCli"
private const val BUSYBOX = "/data/adb/ksu/bin/busybox"
private fun ksuDaemonMagicPath(): String {
return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud_magic.so"
@@ -37,10 +38,16 @@ private fun ksuDaemonOverlayfsPath(): String {
return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud_overlayfs.so"
}
fun readMountSystemFile(): Boolean {
val shell = getRootShell()
val filePath = "/data/adb/ksu/mount_system"
val result = ShellUtils.fastCmd(shell, "cat $filePath").trim()
return result == "OVERLAYFS"
}
// Get the path based on the user's choice
fun getKsuDaemonPath(): String {
val prefs = ksuApp.getSharedPreferences("settings", Context.MODE_PRIVATE)
val useOverlayFs = prefs.getBoolean("use_overlay_fs", false)
val useOverlayFs = readMountSystemFile()
return if (useOverlayFs) {
ksuDaemonOverlayfsPath()
@@ -49,6 +56,16 @@ fun getKsuDaemonPath(): String {
}
}
fun updateMountSystemFile(useOverlayFs: Boolean) {
val shell = getRootShell()
val filePath = "/data/adb/ksu/mount_system"
if (useOverlayFs) {
ShellUtils.fastCmd(shell, "echo -n OVERLAYFS > $filePath")
} else {
ShellUtils.fastCmd(shell, "echo -n MAGIC_MOUNT > $filePath")
}
}
data class FlashResult(val code: Int, val err: String, val showReboot: Boolean) {
constructor(result: Shell.Result, showReboot: Boolean) : this(result.code, result.err.joinToString("\n"), showReboot)
constructor(result: Shell.Result) : this(result, result.isSuccess)
@@ -89,9 +106,9 @@ fun createRootShell(globalMnt: Boolean = false): Shell {
val builder = Shell.Builder.create()
return try {
if (globalMnt) {
builder.build(getKsuDaemonPath(), "debug", "su", "-g")
builder.build(ksuDaemonMagicPath(), "debug", "su", "-g")
} else {
builder.build(getKsuDaemonPath(), "debug", "su")
builder.build(ksuDaemonMagicPath(), "debug", "su")
}
} catch (e: Throwable) {
Log.w(TAG, "ksu failed: ", e)
@@ -474,7 +491,7 @@ fun moduleBackup(): Boolean {
val internalBackupDir = "/sdcard/.ksunext/modules"
val internalBackupPath = "$internalBackupDir/$tarName"
val tarCmd = "tar -cpf $tarPath -C /data/adb/modules $(ls /data/adb/modules)"
val tarCmd = "$BUSYBOX tar -cpf $tarPath -C /data/adb/modules $(ls /data/adb/modules)"
val tarResult = ShellUtils.fastCmd(shell, tarCmd).trim()
if (tarResult.isNotEmpty()) return false
@@ -495,7 +512,7 @@ fun moduleRestore(): Boolean {
val tarPath = ShellUtils.fastCmd(shell, findTarCmd).trim()
if (tarPath.isEmpty()) return false
val extractCmd = "tar -xpf $tarPath -C /data/adb/modules_update"
val extractCmd = "$BUSYBOX tar -xpf $tarPath -C /data/adb/modules_update"
val extractResult = ShellUtils.fastCmd(shell, extractCmd).trim()
return extractResult.isEmpty()
}
@@ -517,7 +534,7 @@ fun allowlistBackup(): Boolean {
val internalBackupDir = "/sdcard/.ksunext/allowlist"
val internalBackupPath = "$internalBackupDir/$tarName"
val tarCmd = "tar -cpf $tarPath -C /data/adb/ksu .allowlist"
val tarCmd = "$BUSYBOX tar -cpf $tarPath -C /data/adb/ksu .allowlist"
val tarResult = ShellUtils.fastCmd(shell, tarCmd).trim()
if (tarResult.isNotEmpty()) return false
@@ -540,7 +557,7 @@ fun allowlistRestore(): Boolean {
if (tarPath.isEmpty()) return false
// Extract the tar to /data/adb/ksu (restores .allowlist folder with permissions)
val extractCmd = "tar -xpf $tarPath -C /data/adb/ksu"
val extractCmd = "$BUSYBOX tar -xpf $tarPath -C /data/adb/ksu"
val extractResult = ShellUtils.fastCmd(shell, extractCmd).trim()
return extractResult.isEmpty()
}
@@ -607,11 +624,48 @@ fun currentMountSystem(): String {
fun getModuleSize(dir: File): Long {
val shell = getRootShell()
val cmd = "du -sb '${dir.absolutePath}' | awk '{print \$1}'"
val cmd = "$BUSYBOX du -sb '${dir.absolutePath}' | awk '{print \$1}'"
val result = ShellUtils.fastCmd(shell, cmd).trim()
return result.toLongOrNull() ?: 0L
}
fun isSuCompatDisabled(): Boolean {
return Natives.version >= Natives.MINIMAL_SUPPORTED_SU_COMPAT && !Natives.isSuEnabled()
}
fun zygiskRequired(dir: File): Boolean {
val shell = getRootShell()
val zygiskLib = "${dir.absolutePath}/zygisk"
val cmd = "ls \"$zygiskLib\""
val result = ShellUtils.fastCmdResult(shell, cmd)
return result
}
fun zygiskAvailable(): Boolean {
val shell = getRootShell()
val zygiskLib = "libzygisk.so"
val rezygisk64 = "/data/adb/modules/rezygisk/lib64/$zygiskLib"
val rezygisk = "/data/adb/modules/rezygisk/lib/$zygiskLib"
val zygiskNext64 = "/data/adb/modules/zygisksu/lib64/$zygiskLib"
val zygiskNext = "/data/adb/modules/zygisksu/lib/$zygiskLib"
val cmdRezygisk64 = "[ -f \"$rezygisk64\" ]"
if (ShellUtils.fastCmdResult(shell, cmdRezygisk64)) {
return true
}
val cmdZygiskNext64 = "[ -f \"$zygiskNext64\" ]"
if (ShellUtils.fastCmdResult(shell, cmdZygiskNext64)) {
return true
}
val cmdRezygisk = "[ -f \"$rezygisk\" ]"
if (ShellUtils.fastCmdResult(shell, cmdRezygisk)) {
return true
}
val cmdZygiskNext = "[ -f \"$zygiskNext\" ]"
return ShellUtils.fastCmdResult(shell, cmdZygiskNext)
}
fun setAppProfileTemplate(id: String, template: String): Boolean {
val shell = getRootShell()
val escapedTemplate = template.replace("\"", "\\\"")

View File

@@ -0,0 +1,149 @@
package com.rifsxd.ksunext.ui.util
import android.annotation.TargetApi
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.provider.Settings
import java.util.Locale
object LocaleHelper {
/**
* Check if should use system language settings (Android 13+)
*/
val useSystemLanguageSettings: Boolean
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
/**
* Launch system app locale settings (Android 13+)
*/
fun launchSystemLanguageSettings(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
try {
val intent = Intent(Settings.ACTION_APP_LOCALE_SETTINGS).apply {
data = Uri.fromParts("package", context.packageName, null)
}
context.startActivity(intent)
} catch (e: Exception) {
// Fallback to app language settings if system settings not available
}
}
}
/**
* Apply saved language setting to context (for Android < 13)
*/
fun applyLanguage(context: Context): Context {
// On Android 13+, language is handled by system
if (useSystemLanguageSettings) {
return context
}
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val localeTag = prefs.getString("app_locale", "system") ?: "system"
return if (localeTag == "system") {
context
} else {
val locale = parseLocaleTag(localeTag)
setLocale(context, locale)
}
}
/**
* Set locale for context (Android < 13)
*/
private fun setLocale(context: Context, locale: Locale): Context {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
updateResources(context, locale)
} else {
updateResourcesLegacy(context, locale)
}
}
@TargetApi(Build.VERSION_CODES.N)
private fun updateResources(context: Context, locale: Locale): Context {
val configuration = Configuration()
configuration.setLocale(locale)
configuration.setLayoutDirection(locale)
return context.createConfigurationContext(configuration)
}
@SuppressWarnings("deprecation")
private fun updateResourcesLegacy(context: Context, locale: Locale): Context {
Locale.setDefault(locale)
val resources = context.resources
val configuration = resources.configuration
configuration.locale = locale
configuration.setLayoutDirection(locale)
resources.updateConfiguration(configuration, resources.displayMetrics)
return context
}
/**
* Parse locale tag to Locale object
*/
private fun parseLocaleTag(tag: String): Locale {
return try {
if (tag.contains("_")) {
val parts = tag.split("_")
Locale.Builder()
.setLanguage(parts[0])
.setRegion(parts.getOrNull(1) ?: "")
.build()
} else {
Locale.Builder()
.setLanguage(tag)
.build()
}
} catch (e: Exception) {
Locale.getDefault()
}
}
/**
* Restart activity to apply language change (Android < 13)
*/
fun restartActivity(context: Context) {
if (context is Activity && !useSystemLanguageSettings) {
context.recreate()
}
}
/**
* Get current app locale
*/
fun getCurrentAppLocale(context: Context): Locale? {
return if (useSystemLanguageSettings) {
// Android 13+ - get from system app locale settings
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
try {
val localeManager = context.getSystemService(Context.LOCALE_SERVICE) as? android.app.LocaleManager
val locales = localeManager?.applicationLocales
if (locales != null && !locales.isEmpty) {
locales.get(0)
} else {
null // System default
}
} catch (e: Exception) {
null // System default
}
} else {
null // System default
}
} else {
// Android < 13 - get from SharedPreferences
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val localeTag = prefs.getString("app_locale", "system") ?: "system"
if (localeTag == "system") {
null // System default
} else {
parseLocaleTag(localeTag)
}
}
}
}

View File

@@ -1,5 +1,6 @@
package com.rifsxd.ksunext.ui.viewmodel
import android.net.Uri
import android.os.SystemClock
import android.util.Log
import androidx.compose.runtime.derivedStateOf
@@ -22,6 +23,8 @@ import com.rifsxd.ksunext.ksuApp
import com.rifsxd.ksunext.ui.util.HanziToPinyin
import com.rifsxd.ksunext.ui.util.listModules
import com.rifsxd.ksunext.ui.util.getModuleSize
import com.rifsxd.ksunext.ui.util.zygiskRequired
import com.rifsxd.ksunext.ui.util.zygiskAvailable
import org.json.JSONArray
import org.json.JSONObject
@@ -47,7 +50,8 @@ class ModuleViewModel : ViewModel() {
val hasActionScript: Boolean,
val dirId: String,
val size: Long,
val banner: String
val banner: String,
val zygiskRequired: Boolean
)
data class ModuleUpdateInfo(
@@ -93,6 +97,16 @@ class ModuleViewModel : ViewModel() {
isNeedRefresh = true
}
var zipUris by mutableStateOf<List<Uri>>(emptyList())
fun updateZipUris(uris: List<Uri>) {
zipUris = uris
}
fun clearZipUris() {
zipUris = emptyList()
}
fun fetchModuleList() {
viewModelScope.launch {
@@ -128,6 +142,7 @@ class ModuleViewModel : ViewModel() {
val dirId = obj.getString("dir_id")
val moduleDir = File("/data/adb/modules/$dirId")
val size = getModuleSize(moduleDir)
val zygiskRequired = zygiskRequired(moduleDir)
ModuleInfo(
id,
@@ -144,7 +159,8 @@ class ModuleViewModel : ViewModel() {
obj.optBoolean("action"),
dirId,
size,
obj.optString("banner")
obj.optString("banner"),
zygiskRequired
)
}.toList()
isNeedRefresh = false

View File

@@ -1,5 +1,9 @@
package com.rifsxd.ksunext.ui.viewmodel
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.os.Parcelable
@@ -24,16 +28,17 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.withTimeoutOrNull
import java.text.Collator
import java.util.*
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import androidx.core.content.edit
class SuperUserViewModel : ViewModel() {
val isPlatformAlive get() = Platform.isAlive
var refreshOnReturn by mutableStateOf(false)
public set
companion object {
private const val TAG = "SuperUserViewModel"
private var apps by mutableStateOf<List<AppInfo>>(emptyList())
private var profileOverrides by mutableStateOf<Map<String, Natives.Profile>>(emptyMap())
}
@Parcelize
@@ -63,16 +68,26 @@ class SuperUserViewModel : ViewModel() {
}
}
private val prefs = ksuApp.getSharedPreferences("settings", Context.MODE_PRIVATE)!!
var search by mutableStateOf("")
var showSystemApps by mutableStateOf(false)
var showSystemApps by mutableStateOf(prefs.getBoolean("show_system_apps", false))
private set
var isRefreshing by mutableStateOf(false)
private set
fun updateShowSystemApps(newValue: Boolean) {
showSystemApps = newValue
prefs.edit { putBoolean("show_system_apps", newValue) }
}
private val sortedList by derivedStateOf {
val comparator = compareBy<AppInfo> {
when {
it.allowSu -> 0
it.hasCustomProfile -> 1
it.profile != null && it.profile.allowSu -> 0
it.profile != null && (
if (it.profile.allowSu) !it.profile.rootUseDefault else !it.profile.nonRootUseDefault
) -> 1
else -> 2
}
}.then(compareBy(Collator.getInstance(Locale.getDefault()), AppInfo::label))
@@ -82,7 +97,9 @@ class SuperUserViewModel : ViewModel() {
}
val appList by derivedStateOf {
sortedList.filter {
sortedList.map { app ->
profileOverrides[app.packageName]?.let { app.copy(profile = it) } ?: app
}.filter {
it.label.contains(search, true) || it.packageName.contains(
search,
true
@@ -94,11 +111,15 @@ class SuperUserViewModel : ViewModel() {
}
}
fun updateAppProfile(packageName: String, newProfile: Natives.Profile) {
profileOverrides = profileOverrides.toMutableMap().apply {
put(packageName, newProfile)
}
}
suspend fun fetchAppList() {
isRefreshing = true
withContext(Dispatchers.IO) {
withTimeoutOrNull(TIMEOUT_MILLIS) {
while (!isPlatformAlive) {
@@ -124,6 +145,7 @@ class SuperUserViewModel : ViewModel() {
profile = profile,
)
}.filter { it.packageName != ksuApp.packageName }
profileOverrides = emptyMap()
Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}")
}
}

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="issue_report_title">Problémája van?</string>
<string name="issue_report_body">Hibát észlelt, vagy van visszajelzése?</string>
<string name="issue_report_body">Hibát észlelt, vagy visszajelzése van?</string>
<string name="issue_report_body_2">Jelentse mielőbb!</string>
<string name="issue_report_github">Report on GitHub</string>
<string name="issue_report_telegram">Kapcsolatfelvétel Telegramon keresztül</string>
@@ -12,13 +12,16 @@
<string name="home">Kezdőlap</string>
<string name="home_not_installed">Nincs telepítve</string>
<string name="home_click_to_install">Kattintson a telepítéshez</string>
<string name="lkm_alternative_suggestion">Telepíts GKI kernelt, vagy integráld a KernelSU Next-et az eszközödbe.</string>
<string name="home_working">Működik</string>
<string name="home_working_version">Verzió: %d</string>
<string name="home_superuser_count">Superuserek: %d</string>
<string name="home_module_count">Modulok: %d</string>
<string name="home_module_update_count">Frissítések: %d</string>
<string name="home_failure">KernelSU Next v2 aláírás nem található a kernelben! [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">Kérje meg kernel fejlesztőjét, hogy integrálja a KernelSU Next-et!</string>
<string name="home_kernel">Kernel verzió</string>
<string name="disable">Kikapcsolva</string>
<string name="enabled">Bekapcsolva</string>
<string name="disabled">Kikapcsolva</string>
<string name="susfs_supported">Támogatott</string>
@@ -38,13 +41,15 @@
<string name="module_empty">Nincs telepített modul</string>
<string name="module">Modul</string>
<string name="module_install_prompt_with_name">A következő modul(ok) lesznek telepítve: %1$s</string>
<string name="module_sort_a_to_z">Rendezés (A-Z)</string>
<string name="module_sort_z_to_a">Rendezés (Z-A)</string>
<string name="module_sort_a_to_z">Rendezés (AZ)</string>
<string name="module_sort_z_to_a">Rendezés (ZA)</string>
<string name="module_size_high_to_low">Rendezés (Magas → Alacsony)</string>
<string name="uninstall">Eltávolítás</string>
<string name="restore">Visszaállítás</string>
<string name="module_install">Telepítés</string>
<string name="install">Telepítés</string>
<string name="reboot">Újraindítás</string>
<string name="uninstalled">Eltávolítva</string>
<string name="settings">Beállítások</string>
<string name="reboot_userspace">Lágy újraindítás</string>
<string name="reboot_recovery">Újraindítás Recovery módba</string>
@@ -96,6 +101,7 @@
<string name="proceed">Folytatás</string>
<string name="cancel">Mégse</string>
<string name="later">Később</string>
<string name="lkm_warning_message">Az LKM patch zárt forráskódú komponenseken alapul. Folytatja?</string>
<string name="home_next_kernelsu">🔥 Next build</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Next kísérleti branch. Nézze meg a GitHubon!</string>
@@ -129,6 +135,7 @@
<string name="profile_selinux_domain">Domain</string>
<string name="profile_selinux_rules">Szabályok</string>
<string name="module_update">Frissítés</string>
<string name="module_updated">Frissítve</string>
<string name="module_downloading">%s modul letöltése</string>
<string name="module_start_downloading">Letöltés indítása: %s</string>
<string name="new_version_available">Új verzió (%s) elérhető, kattintson a frissítéshez.</string>
@@ -136,6 +143,7 @@
<string name="close">Bezár</string>
<string name="force_stop_app">Kényszer leállítás</string>
<string name="restart_app">Újraindítás</string>
<string name="restart_app_message">A módosítás érvénybe lépéséhez újra kell indítani az alkalmazást.</string>
<string name="failed_to_update_sepolicy">Nem sikerült frissíteni a SELinux szabályait a következőhöz: %s</string>
<string name="su_not_allowed">Superuser megadása nem engedélyezett a következőhöz: %s</string>
<string name="module_changelog">Változásnapló</string>
@@ -194,4 +202,20 @@
<string name="settings_disable_su">Kapcsolja ki a su kompatibilitást</string>
<string name="settings_disable_su_summary">Ideiglenesen tiltsa le bármely alkalmazás azon képességét, hogy root jogosultságokat szerezzen a su paranccsal (a már meglévő folyamatokat ez nem érinti).</string>
<string name="settings_language">Nyelv</string>
<string name="lkm_mode_deprecated">Az LKM mód elavult!</string>
<string name="hook_mode">Hook módszer</string>
<string name="enable">Bekapcsolva</string>
<string name="module_size_low_to_high">Rendezés (Alacsony → Magas)</string>
<string name="settings_amoled_mode">AMOLED mód</string>
<string name="settings_amoled_mode_summary">Engedélyezzen egy teljesen fekete témát, amely leginkább AMOLED képernyőkön hasznos. Csökkenti a szem megerőltetését és az akkumulátort is kíméli.</string>
<string name="restart_required">Újraindítás szükséges</string>
<string name="settings_legacyui">Legacy UI használata</string>
<string name="settings_legacyui_summary">Váltás az előző felhasználói felületre.</string>
<string name="settings_banner">Bannerek engedélyezése</string>
<string name="settings_banner_summary">Mutassa a modulok hátterének bannereit.</string>
<string name="use_webuix">WebUI X használata</string>
<string name="use_webuix_summary">A WebUI X több API-t támogat, mint a WebUI.</string>
<string name="use_webuix_eruda">Eruda injektálása a WebUI X-be</string>
<string name="use_webuix_eruda_summary">Hibakeresési konzol injektálása a WebUI X-be a hibakeresés megkönnyítése érdekében. Ehhez a webes hibakeresést be kell kapcsolni.</string>
<string name="customization">Testreszabás</string>
</resources>

View File

@@ -18,10 +18,13 @@
<string name="home_working_version">Versione: %d</string>
<string name="home_superuser_count">Applicazioni con accesso root: %d</string>
<string name="home_module_count">Moduli: %d</string>
<string name="home_module_update_count">Aggiornamenti: %d</string>
<string name="home_failure">Firma KernelSU Next v2 non trovata nel kernel! [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">Chiedi allo sviluppatore del kernel di integrare KernelSU Next!</string>
<string name="home_kernel">Versione Kernel</string>
<string name="hook_mode">Modalità Hook</string>
<string name="enable">Abilita</string>
<string name="disable">Disabilita</string>
<string name="enabled">Abilitato</string>
<string name="disabled">Disabilitato</string>
<string name="susfs_supported">Supportato</string>
@@ -42,13 +45,16 @@
<string name="module_empty">Nessun modulo installato</string>
<string name="module">Modulo</string>
<string name="module_install_prompt_with_name">Verranno installati i seguenti moduli: %1$s</string>
<string name="module_sort_a_to_z">Ordinare (A-Z)</string>
<string name="module_sort_z_to_a">Ordinare (Z-A)</string>
<string name="module_sort_a_to_z">Ordina (AZ)</string>
<string name="module_sort_z_to_a">Ordina (ZA)</string>
<string name="module_size_low_to_high">Ordina (Basso → Alto)</string>
<string name="module_size_high_to_low">Ordina (Alto → Basso)</string>
<string name="uninstall">Disinstalla</string>
<string name="restore">Ripristina</string>
<string name="module_install">Installa</string>
<string name="install">Installa</string>
<string name="reboot">Riavvia</string>
<string name="uninstalled">Disinstallato</string>
<string name="settings">Impostazioni</string>
<string name="reboot_userspace">Riavvio rapido</string>
<string name="reboot_recovery">Riavvia in Recovery</string>
@@ -100,6 +106,7 @@
<string name="proceed">Procedere</string>
<string name="cancel">Cancellare</string>
<string name="later">Dopo</string>
<string name="lkm_warning_message">La patch LKM si basa su componenti closed source. Vuoi continuare?</string>
<string name="home_next_kernelsu">🔥 Next build</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Branch sperimentale di Next. Dai un\'occhiata su GitHub!</string>
@@ -133,6 +140,7 @@
<string name="profile_selinux_domain">Dominio</string>
<string name="profile_selinux_rules">Regole</string>
<string name="module_update">Aggiorna</string>
<string name="module_updated">Aggiornato</string>
<string name="module_downloading">Sto scaricando il modulo: %s</string>
<string name="module_start_downloading">Inizia a scaricare: %s</string>
<string name="new_version_available">Nuova versione: %s disponibile, tocca per aggiornare.</string>
@@ -140,6 +148,10 @@
<string name="close">Chiudi</string>
<string name="force_stop_app">Arresto forzato</string>
<string name="restart_app">Riavvia</string>
<string name="settings_amoled_mode">Modalità AMOLED</string>
<string name="settings_amoled_mode_summary">Abilita un tema nero puro, utile per gli schermi AMOLED, per ridurre l\'affaticamento degli occhi e risparmiare batteria.</string>
<string name="restart_required">Riavvio richiesto</string>
<string name="restart_app_message">Affinché la modifica abbia effetto, è necessario riavviare l\'app.</string>
<string name="failed_to_update_sepolicy">Aggiornamento regole SELinux per %s fallito</string>
<string name="su_not_allowed">Non è consentito concedere i privilegi di superutente per: %s</string>
<string name="module_changelog">Registro aggiornamenti</string>
@@ -169,6 +181,7 @@
<string name="settings_check_update_summary">Controlla automaticamente gli aggiornamenti all\'apertura dell\'applicazione.</string>
<string name="grant_root_failed">Impossibile ottenere l\'accesso root!</string>
<string name="action">Azione</string>
<string name="webui">WebUI</string>
<string name="open">Apri</string>
<string name="enable_web_debugging">Abilita il debug di WebView</string>
<string name="enable_web_debugging_summary">Può essere usato per il debug di WebUI, è consigliato attivarlo solo quando necessario.</string>
@@ -198,8 +211,14 @@
<string name="settings_disable_su">Disabilita la compatibilità su</string>
<string name="settings_disable_su_summary">Disattiva temporaneamente la possibilità per qualsiasi app di ottenere privilegi di root tramite il comando su (i processi di root esistenti non saranno interessati).</string>
<string name="settings_language">Lingua</string>
<string name="settings_legacyui">Usa Legacy UI</string>
<string name="settings_legacyui_summary">Passa allo stile precedente dell\'interfaccia utente.</string>
<string name="settings_banner">Abilita banner</string>
<string name="settings_banner_summary">Mostra banner di sfondo per i moduli.</string>
<string name="use_webuix">Usa WebUI X</string>
<string name="use_webuix_summary">Usa WebUI X invece di WebUI che supporta più API</string>
<string name="use_webuix_eruda">Iniettare Eruda in WebUI X</string>
<string name="use_webuix_eruda_summary">Inietta una console di debug in WebUI X per semplificare il debug. Richiede che il debug web sia attivo.</string>
<string name="use_webuix_summary">Usa WebUI X invece di WebUI che supporta più API.</string>
<string name="use_webuix_eruda">Iniettare Eruda in WebUI X</string>
<string name="use_webuix_eruda_summary">Inietta una console di debug in WebUI X per semplificare il debug. Richiede che il debug web sia attivo.</string>
<string name="customization">Personalizzazione</string>
<string name="developer">Sviluppatore</string>
</resources>

View File

@@ -9,16 +9,22 @@
<string name="issue_report_telegram_link">https://t.me/ksunext</string>
<string name="confirm">Potwierdź</string>
<string name="app_name" translatable="false">KernelSU Next</string>
<string name="home">Strona główna</string>
<string name="home">Główna</string>
<string name="home_not_installed">Niezainstalowany</string>
<string name="home_click_to_install">Kliknij, aby zainstalować</string>
<string name="lkm_mode_deprecated">Tryb LKM jest już przestarzały!</string>
<string name="lkm_alternative_suggestion">Zainstaluj jądro GKI lub zintegruj KernelSU Next ze swoim urządzeniem.</string>
<string name="home_working">Uruchomiony</string>
<string name="home_working_version">Wersja: %d</string>
<string name="home_superuser_count">Superuserów: %d</string>
<string name="home_module_count">Modułów: %d</string>
<string name="home_module_update_count">Aktualizacji: %d</string>
<string name="home_failure">Nie znaleziono sygnatury KernelSU Next v2 w jądrze! [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">Poproś swojego programistę jądra o integrację KernelSU Next!</string>
<string name="home_kernel">Wersja jądra</string>
<string name="hook_mode">Rodzaj hooków</string>
<string name="enable">Aktywuj</string>
<string name="disable">Dezaktywuj</string>
<string name="enabled">Aktywny</string>
<string name="disabled">Nieaktywny</string>
<string name="susfs_supported">Obsługiwany</string>
@@ -27,6 +33,7 @@
<string name="home_susfs_sus_su">SuS SU</string>
<string name="home_android">Wersja Androida</string>
<string name="home_manager_version">Wersja managera</string>
<string name="home_abi">ABI</string>
<string name="home_selinux_status">Status SELinux</string>
<string name="selinux_status_disabled">Wyłączony</string>
<string name="selinux_status_enforcing">Enforcing</string>
@@ -38,20 +45,23 @@
<string name="module_empty">Brak zainstalowanych modułów</string>
<string name="module">Moduły</string>
<string name="module_install_prompt_with_name">Następujące moduły zostaną zainstalowane: %1$s</string>
<string name="module_sort_a_to_z">Sortuj (A-Z)</string>
<string name="module_sort_z_to_a">Sortuj (Z-A)</string>
<string name="module_sort_a_to_z">Sortuj (AZ)</string>
<string name="module_sort_z_to_a">Sortuj (ZA)</string>
<string name="module_size_low_to_high">Sortuj (Najmniejszy → Największy)</string>
<string name="module_size_high_to_low">Sortuj (Największy → Najmniejszy)</string>
<string name="uninstall">Odinstaluj</string>
<string name="restore">Przywróć</string>
<string name="module_install">Zainstaluj</string>
<string name="install">Zainstaluj</string>
<string name="reboot">Reboot (uruchom ponownie)</string>
<string name="uninstalled">Odinstalowany</string>
<string name="settings">Ustawienia</string>
<string name="reboot_userspace">Miękki reboot</string>
<string name="reboot_recovery">Reboot do trybu Recovery</string>
<string name="reboot_bootloader">Reboot do trybu Bootloader</string>
<string name="reboot_download">Reboot do trybu Download</string>
<string name="reboot_edl">Reboot do trybu EDL</string>
<string name="about">O autorze</string>
<string name="about">O aplikacji</string>
<string name="module_uninstall_confirm">Czy na pewno chcesz odinstalować moduł %s?</string>
<string name="module_uninstall_success">%s został odinstalowany</string>
<string name="module_uninstall_failed">Nie można odinstalować: %s</string>
@@ -84,7 +94,7 @@
<string name="reboot_message">Zmiany zaczną obowiązywać po restarcie systemu. Czy chcesz teraz uruchomić ponownie system?</string>
<string name="module_restore">Przywróć moduły z kopii zapasowej</string>
<string name="module_restore_message">Przywróć moduły z ostatniej kopii zapasowej.</string>
<string name="backup_restore">Tworzenie / przywracanie kopii zapasowej</string>
<string name="backup_restore">Tworzenie i przywracanie kopii zapasowej</string>
<string name="module_backup">Utwórz kopię zapasową modułów</string>
<string name="module_backup_message">Utwórz kopię zapasową obecnie zainstalowanych modułów.</string>
<string name="allowlist_restore">Przywróć listę zgód z kopii zapasowej</string>
@@ -96,6 +106,7 @@
<string name="proceed">Dalej</string>
<string name="cancel">Anuluj</string>
<string name="later">Później</string>
<string name="lkm_warning_message">Łatka LKM opiera się na komponentach o zamkniętym kodzie źródłowym. Czy chcesz kontynuować?</string>
<string name="home_next_kernelsu">🔥 Kompilacja Next</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Eksperymentalna gałąź Next. Sprawdź na GitHub!</string>
@@ -129,6 +140,7 @@
<string name="profile_selinux_domain">Domena</string>
<string name="profile_selinux_rules">Reguły</string>
<string name="module_update">Zaktualizuj</string>
<string name="module_updated">Zaktualizowany</string>
<string name="module_downloading">Pobieranie modułu: %s</string>
<string name="module_start_downloading">Rozpocznij pobieranie: %s</string>
<string name="new_version_available">Nowa wersja %s jest dostępna, kliknij, aby zaktualizować.</string>
@@ -136,6 +148,10 @@
<string name="close">Zamknij</string>
<string name="force_stop_app">Wymuś zatrzymanie</string>
<string name="restart_app">Uruchom ponownie</string>
<string name="settings_amoled_mode">Tryb AMOLED</string>
<string name="settings_amoled_mode_summary">Włącz czysto czarny motyw, przydatny dla ekranów AMOLED, aby zmniejszyć zmęczenie oczu oraz zużycie baterii.</string>
<string name="restart_required">Wymagany restart</string>
<string name="restart_app_message">Aplikacja wymaga ponownego uruchomienia, aby zmiana została uwzględniona.</string>
<string name="failed_to_update_sepolicy">Nie udało się zaktualizować reguł SELinux dla: %s</string>
<string name="su_not_allowed">Przyznanie uprawnień superusera nie jest dozwolone dla: %s</string>
<string name="module_changelog">Dziennik zmian</string>
@@ -165,6 +181,7 @@
<string name="settings_check_update_summary">Automatycznie sprawdzaj dostępność aktualizacji przy otwieraniu aplikacji.</string>
<string name="grant_root_failed">Nie udało się przyznać uprawnień roota!</string>
<string name="action">Akcja</string>
<string name="webui">WebUI</string>
<string name="open">Otwórz</string>
<string name="enable_web_debugging">Włącz debugowanie WebView</string>
<string name="enable_web_debugging_summary">Możesz użyć tej opcji w celu debugowania WebUI. Włącz tylko wtedy, gdy jest to potrzebne.</string>
@@ -194,4 +211,15 @@
<string name="settings_disable_su">Wyłącz funkcjonalność su</string>
<string name="settings_disable_su_summary">Tymczasowo wyłącz możliwość uzyskania uprawnień roota przez dowolną aplikację za pomocą polecenia su (nie będzie to miało wpływu na istniejące procesy roota).</string>
<string name="settings_language">Język</string>
<string name="settings_legacyui">Używaj starszego interfejsu użytkownika</string>
<string name="settings_legacyui_summary">Przełącz na poprzedni styl interfejsu użytkownika.</string>
<string name="settings_banner">Włącz banery</string>
<string name="settings_banner_summary">Pokazuj tła-banery dla modułów.</string>
<string name="use_webuix">Używaj WebUI X</string>
<string name="use_webuix_summary">Używaj WebUI X zamiast WebUI, który obsługuje więcej interfejsów API.</string>
<string name="use_webuix_eruda">Wstrzykuj Eruda do WebUI X</string>
<string name="use_webuix_eruda_summary">Wstrzyknij konsolę debugowania do WebUI X, aby ułatwić debugowanie. Wymagane jest aktywne debugowanie WebView.</string>
<string name="customization">Personalizacja</string>
<string name="developer">Programista</string>
<string name="sucompat_disabled">SUCOMPAT NIEAKTYWNY</string>
</resources>

View File

@@ -18,10 +18,14 @@
<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_module_update_count">Atualizações: %d</string>
<string name="module_update_available">Atualizar</string>
<string name="home_failure">Assinatura KernelSU Next v2 não encontrada no kernel! [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">Peça ao seu desenvolvedor de kernel para integrar o KernelSU Next!</string>
<string name="home_kernel">Versão do kernel</string>
<string name="hook_mode">Modo do hook</string>
<string name="enable">Ativar</string>
<string name="disable">Desativar</string>
<string name="enabled">Ativado</string>
<string name="disabled">Desativado</string>
<string name="susfs_supported">Suportado</string>
@@ -42,13 +46,16 @@
<string name="module_empty">Nenhum módulo instalado</string>
<string name="module">Módulo</string>
<string name="module_install_prompt_with_name">Os seguintes módulos serão instalados: %1$s</string>
<string name="module_sort_a_to_z">Ordenar (A-Z)</string>
<string name="module_sort_z_to_a">Ordenar (Z-A)</string>
<string name="module_sort_a_to_z">Ordenar (AZ)</string>
<string name="module_sort_z_to_a">Ordenar (ZA)</string>
<string name="module_size_low_to_high">Ordenar (Menor → Maior)</string>
<string name="module_size_high_to_low">Ordenar (Maior → Menor)</string>
<string name="uninstall">Desinstalar</string>
<string name="restore">Restaurar</string>
<string name="module_install">Instalar</string>
<string name="install">Instalar</string>
<string name="reboot">Reiniciar</string>
<string name="uninstalled">Desinstalado</string>
<string name="settings">Configurações</string>
<string name="reboot_userspace">Reinicialização suave</string>
<string name="reboot_recovery">Reiniciar em modo Recovery</string>
@@ -134,6 +141,7 @@
<string name="profile_selinux_domain">Domínio</string>
<string name="profile_selinux_rules">Regras</string>
<string name="module_update">Atualizar</string>
<string name="module_updated">Atualizado</string>
<string name="module_downloading">Baixando módulo %s</string>
<string name="module_start_downloading">Começando a baixar %s</string>
<string name="new_version_available">Nova versão %s está disponível, clique para atualizar.</string>
@@ -141,6 +149,10 @@
<string name="close">Fechar</string>
<string name="force_stop_app">Forçar parada</string>
<string name="restart_app">Reiniciar</string>
<string name="settings_amoled_mode">Modo AMOLED</string>
<string name="settings_amoled_mode_summary">Ative um tema preto puro útil para telas AMOLED para reduzir o cansaço visual e economizar bateria.</string>
<string name="restart_required">Reinicialização necessária</string>
<string name="restart_app_message">O app precisa ser reiniciado para que essa alteração tenha efeito.</string>
<string name="failed_to_update_sepolicy">Falha ao atualizar as regras do SELinux para: %s</string>
<string name="su_not_allowed">O acesso de SuperUsuário não é permitido para: %s</string>
<string name="module_changelog">Registro de alterações</string>
@@ -170,6 +182,7 @@
<string name="settings_check_update_summary">Verifique automaticamente se há atualizações ao abrir o app</string>
<string name="grant_root_failed">Falha ao conceder acesso root!</string>
<string name="action">Ação</string>
<string name="webui">WebUI</string>
<string name="open">Abrir</string>
<string name="enable_web_debugging">Ativar depuração do WebView</string>
<string name="enable_web_debugging_summary">Pode ser usado para depurar o WebUI. Por favor, ative somente quando necessário.</string>
@@ -199,8 +212,17 @@
<string name="settings_disable_su">Desativar compatibilidade su</string>
<string name="settings_disable_su_summary">Desative temporariamente a capacidade de qualquer app obter privilégios root por meio do comando su (processos root existentes não serão afetados).</string>
<string name="settings_language">Idioma</string>
<string name="system_default">Padrão do sistema</string>
<string name="settings_legacyui">Usar IU antiga</string>
<string name="settings_legacyui_summary">Mude para o estilo de interface do usuário anterior.</string>
<string name="settings_banner">Ativar banners</string>
<string name="settings_banner_summary">Mostre banners de fundo para módulos.</string>
<string name="use_webuix">Usar WebUI X</string>
<string name="use_webuix_summary">Use o WebUI X em vez do WebUI, que oferece suporte a mais APIs.</string>
<string name="use_webuix_eruda">Injetar Eruda no WebUI X</string>
<string name="use_webuix_eruda_summary">Injeta um console de depuração no WebUI X para facilitar a depuração. Requer que a depuração web esteja ativada.</string>
<string name="customization">Personalização</string>
<string name="developer">Desenvolvedor</string>
<string name="sucompat_disabled">SUCOMPAT DESATIVADO</string>
<string name="zygisk_required">Zygisk necessário</string>
</resources>

View File

@@ -15,16 +15,19 @@
<string name="lkm_mode_deprecated">Режим LKM теперь устарел!</string>
<string name="lkm_alternative_suggestion">Установите GKI ядро или интегрируйте ядра рядом с вашим устройством.</string>
<string name="home_working">Работает</string>
<string name="home_working_version">Версия: %d</string>
<string name="home_superuser_count">Superusers: %d</string>
<string name="home_module_count">Модули: %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_module_update_count">Обновлений: %d</string>
<string name="home_failure">Подпись KernelSU Next v2 не найдена в ядре! [!KSU_NEXT || != size/hash]</string>
<string name="home_failure_tip">Попросите вашего разработчика ядра интегрировать KernelSU Next!</string>
<string name="home_kernel">Версия ядра</string>
<string name="hook_mode">Режим хуков</string>
<string name="enable">Включить</string>
<string name="disable">Отключить</string>
<string name="disabled">Отключено</string>
<string name="enabled">Включено</string>
<string name="susfs_supported">Поддерживается</string>
<string name="susfs_supported">Доступно</string>
<string name="home_susfs">SuSFS: %s</string>
<string name="home_susfs_version">Версия SuSFS</string>
<string name="home_susfs_sus_su">SuS SU</string>
@@ -41,14 +44,17 @@
<string name="module_failed_to_disable">Не удалось отключить модуль: %s</string>
<string name="module_empty">Нет установленных модулей</string>
<string name="module">Модули</string>
<string name="module_install_prompt_with_name">Следующие модуль(и) будут установлены: %1$s</string>
<string name="module_sort_a_to_z">Сортировать (А-Я)</string>
<string name="module_sort_z_to_a">Сортировать (Я-А)</string>
<string name="module_install_prompt_with_name">Следующие модули будут установлены: %1$s</string>
<string name="module_sort_a_to_z">Сортировать (АЯ)</string>
<string name="module_sort_z_to_a">Сортировать (ЯА)</string>
<string name="module_size_low_to_high">Сортировать (Меньше → Больше)</string>
<string name="module_size_high_to_low">Сортировать (Больше → Меньше)</string>
<string name="uninstall">Удалить</string>
<string name="restore">Восстановить</string>
<string name="module_install">Установить</string>
<string name="install">Установить</string>
<string name="reboot">Перезагрузка</string>
<string name="uninstalled">Удалено</string>
<string name="settings">Настройки</string>
<string name="reboot_userspace">Мягкая перезагрузка</string>
<string name="reboot_recovery">Перезагрузка в Recovery</string>
@@ -100,6 +106,7 @@
<string name="proceed">Продолжить</string>
<string name="cancel">Отмена</string>
<string name="later">Позже</string>
<string name="lkm_warning_message">Патч LKM использует компоненты с закрытым исходным кодом. Хотите продолжить?</string>
<string name="home_next_kernelsu">🔥 Следующий билд</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Следующая экспериментальная ветка. Посмотрите на GitHub!</string>
@@ -109,7 +116,7 @@
<string name="home_experimental_kernelsu_body_point_1"> • Используйте на свой страх и риск: могут возникнуть сбои, непредвиденное поведение или проблемы с системой.</string>
<string name="home_experimental_kernelsu_body_point_2"> • Предупреждение: разработчики не несут ответственности за потерю данных, повреждение системы или другие последствия, вызванные использованием.</string>
<string name="home_experimental_kernelsu_body_point_3"> • Только для тестирования: предназначено для пользователей, которые понимают риски и готовы решать возникающие проблемы.</string>
<string name="about_source_code"><![CDATA[Посмотреть исходный код на %1$s]]></string>
<string name="about_source_code"><![CDATA[Исходный код на %1$s]]></string>
<string name="profile" translatable="false">Профиль Приложения</string>
<string name="profile_default">По умолчанию</string>
<string name="profile_template">Шаблон</string>
@@ -133,6 +140,7 @@
<string name="profile_selinux_domain">Домен</string>
<string name="profile_selinux_rules">Правила</string>
<string name="module_update">Обновить</string>
<string name="module_updated">Обновлено</string>
<string name="module_downloading">Загрузка модуля: %s</string>
<string name="module_start_downloading">Начало загрузки: %s</string>
<string name="new_version_available">Доступна новая версия %s, нажмите для обновления.</string>
@@ -140,6 +148,10 @@
<string name="close">Закрыть</string>
<string name="force_stop_app">Принудительно остановить</string>
<string name="restart_app">Перезапустить</string>
<string name="settings_amoled_mode">Режим AMOLED</string>
<string name="settings_amoled_mode_summary">Включить полностью тёмную тему, оптимизированную для дисплеев AMOLED, чтобы снизить зрительную нагрузку и сэкономить заряд аккумулятора.</string>
<string name="restart_required">Требуется перезапуск</string>
<string name="restart_app_message">Чтобы изменения вступили в силу, необходимо перезапустить приложение.</string>
<string name="failed_to_update_sepolicy">Не удалось обновить правила SELinux для: %s</string>
<string name="su_not_allowed">Предоставление прав суперпользователя запрещено для: %s</string>
<string name="module_changelog">Журнал изменений</string>
@@ -168,8 +180,9 @@
<string name="settings_check_update">Проверять обновления</string>
<string name="settings_check_update_summary">Автоматически проверять обновления при открытии приложения.</string>
<string name="grant_root_failed">Не удалось предоставить root-доступ!</string>
<string name="action">Запустить</string>
<string name="open">Открыть</string>
<string name="action">Скрипт</string>
<string name="webui">WebUI</string>
<string name="open">WebUI</string>
<string name="enable_web_debugging">Отладка WebView</string>
<string name="enable_web_debugging_summary">Можно использовать для отладки WebUI. Включайте только при необходимости.</string>
<string name="direct_install">Прямая установка (Рекомендуется)</string>
@@ -192,14 +205,21 @@
<string name="flash_success">Прошивка выполнена успешно</string>
<string name="flash_failed">Ошибка прошивки</string>
<string name="selected_lkm">Выбран LKM: %s</string>
<string name="save_log">Сохранить логи</string>
<string name="save_log">Сохранить\nлоги</string>
<string name="log_saved">Логи сохранены</string>
<string name="send_log">Поделиться логами</string>
<string name="send_log">Поделиться\nлогами</string>
<string name="settings_disable_su">Откл. совместимость с su</string>
<string name="settings_disable_su_summary">Временно отключить возможность приложениям получать права root через команду su (существующие процессы с правами root не будут затронуты).</string>
<string name="settings_language">Язык</string>
<string name="settings_legacyui">Использовать старый UI</string>
<string name="settings_legacyui_summary">Переключиться на предыдущий стиль интерфейса.</string>
<string name="settings_banner">Включить баннеры</string>
<string name="settings_banner_summary">Показывать фоновые баннеры для модулей.</string>
<string name="use_webuix">Использовать WebUI X</string>
<string name="use_webuix_summary">Использовать WebUI X вместо WebUI, который поддерживает больше API.</string>
<string name="use_webuix_eruda">Инжект Eruda в WebUI X</string>
<string name="use_webuix_eruda_summary">Инжектить консоль отладки в WebUI X, чтобы упростить отладку. Требуется включить отладку WebView.</string>
<string name="customization">Кастомизация</string>
<string name="developer">Для разработчиков</string>
<string name="sucompat_disabled">SUCOMPAT ОТКЛЮЧЕН</string>
</resources>

View File

@@ -18,10 +18,13 @@
<string name="home_working_version">Sürüm: %d</string>
<string name="home_superuser_count">Süper kullanıcılar: %d</string>
<string name="home_module_count">Modüller: %d</string>
<string name="home_module_update_count">Güncellemeler: %d</string>
<string name="home_failure">Kernel\'de KernelSU Next v2 imzası bulunamadı! [ !KSU_NEXT || != boyut/hash ]</string>
<string name="home_failure_tip">Kernel geliştiricinizden KernelSU Next\'i entegre etmesini isteyin!</string>
<string name="home_kernel">Kernel sürümü</string>
<string name="hook_mode">Kanca Modu</string>
<string name="enable">Etkinleştir</string>
<string name="disable">Devre Dışı Bırak</string>
<string name="enabled">Etkin</string>
<string name="disabled">Devre dışı</string>
<string name="susfs_supported">Destekleniyor</string>
@@ -49,6 +52,7 @@
<string name="module_install">Yükle</string>
<string name="install">Yükle</string>
<string name="reboot">Yeniden Başlat</string>
<string name="uninstalled">Kaldırıldı</string>
<string name="settings">Ayarlar</string>
<string name="reboot_userspace">Yumuşak Yeniden Başlat</string>
<string name="reboot_recovery">Kurtarma Moduna Yeniden Başlat</string>
@@ -100,6 +104,7 @@
<string name="proceed">Devam Et</string>
<string name="cancel">İptal</string>
<string name="later">Daha Sonra</string>
<string name="lkm_warning_message">LKM yaması, kapalı kaynak bileşenlere dayanır. Devam etmek istiyor musunuz?</string>
<string name="home_next_kernelsu">🔥 Yeni Sürüm</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Son deneysel dal. GitHub\'da kontrol edin!</string>
@@ -133,6 +138,7 @@
<string name="profile_selinux_domain">Etki Alanı</string>
<string name="profile_selinux_rules">Kurallar</string>
<string name="module_update">Güncelle</string>
<string name="module_updated">Güncellendi</string>
<string name="module_downloading">Modül indiriliyor: %s</string>
<string name="module_start_downloading">İndirmeye başla: %s</string>
<string name="new_version_available">%s sürümü mevcut, yükseltmek için tıklayın.</string>
@@ -140,6 +146,10 @@
<string name="close">Kapat</string>
<string name="force_stop_app">Zorla durdur</string>
<string name="restart_app">Yeniden Başlat</string>
<string name="settings_amoled_mode">AMOLED modu</string>
<string name="settings_amoled_mode_summary">Göz yorgunluğunu azaltmak ve pil tasarrufu sağlamak için AMOLED ekranlara uygun saf siyah tema etkinleştirilir.</string>
<string name="restart_required">Yeniden Başlatma Gerekli</string>
<string name="restart_app_message">Bu değişikliğin etkili olması için uygulamanın yeniden başlatılması gerekiyor.</string>
<string name="failed_to_update_sepolicy">%s için SELinux kuralları güncellenemedi.</string>
<string name="su_not_allowed">SüperKullanıcı yetkisi verilemez: %s</string>
<string name="module_changelog">Değişiklik Günlüğü</string>
@@ -169,6 +179,7 @@
<string name="settings_check_update_summary">Uygulama açıldığında otomatik olarak güncellemeleri kontrol et.</string>
<string name="grant_root_failed">Root yetkisi verilemedi!</string>
<string name="action">Eylem</string>
<string name="webui">WebUI</string>
<string name="open"></string>
<string name="enable_web_debugging">WebView hata ayıklamasını etkinleştir</string>
<string name="enable_web_debugging_summary">WebUI hata ayıklaması için kullanılabilir. Lütfen yalnızca gerekli olduğunda etkinleştirin.</string>
@@ -198,8 +209,11 @@
<string name="settings_disable_su">Su uyumluluğunu devre dışı bırak</string>
<string name="settings_disable_su_summary">Geçici olarak herhangi bir uygulamanın su komutu aracılığıyla kök ayrıcalıkları elde etme yeteneğini devre dışı bırakır (mevcut kök süreçleri etkilenmez).</string>
<string name="settings_language">Dil</string>
<string name="settings_legacyui">Eski Arayüzü Kullan</string>
<string name="settings_legacyui_summary">Önceki kullanıcı arayüzü stiline geç.</string>
<string name="use_webuix">WebUI X\'i kullanın</string>
<string name="use_webuix_summary">Daha fazla API\'yi destekleyen WebUI yerine WebUI X kullanın</string>
<string name="use_webuix_eruda">WebUI X\'e Eruda Enjekte Et</string>
<string name="use_webuix_eruda_summary">Hata ayıklamayı kolaylaştırmak için WebUI X\'e bir debug konsolu enjekte edin. Web hata ayıklamanın açık olması gerekir.</string>
<string name="customization">Özelleştirme</string>
</resources>

View File

@@ -15,16 +15,19 @@
<string name="lkm_mode_deprecated">Режим LKM тепер застарілий!</string>
<string name="lkm_alternative_suggestion">Встановіть ядро GKI або інтегруйте ядра поруч із вашим пристроєм.</string>
<string name="home_working">Працює</string>
<string name="home_working_version">Версія: %d</string>
<string name="home_superuser_count">SuperUsers: %d</string>
<string name="home_module_count">Модулі: %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_module_update_count">Оновлення: %d</string>
<string name="home_failure">Підпис KernelSU Next v2 не знайдено в ядрі! [!KSU_NEXT || != size/hash]</string>
<string name="home_failure_tip">Попросіть вашого розробника ядра інтегрувати KernelSU Next!</string>
<string name="home_kernel">Версія ядра</string>
<string name="hook_mode">Режим хуків</string>
<string name="enable">Увімкнути</string>
<string name="disable">Вимкнути</string>
<string name="disabled">Вимкнено</string>
<string name="enabled">Увімкнено</string>
<string name="susfs_supported">Підтримується</string>
<string name="susfs_supported">Доступно</string>
<string name="home_susfs">SuSFS: %s</string>
<string name="home_susfs_version">Версія SuSFS</string>
<string name="home_susfs_sus_su">SuS SU</string>
@@ -41,15 +44,18 @@
<string name="module_failed_to_disable">Не вдалося вимкнути модуль: %s</string>
<string name="module_empty">Нема встановлених модулів</string>
<string name="module">Модулі</string>
<string name="module_install_prompt_with_name">Наступні модуль(і) будуть встановлені: %1$s</string>
<string name="module_install_prompt_with_name">Наступні модулі будуть встановлені: %1$s</string>
<string name="module_sort_a_to_z">Сортувати (А-Я)</string>
<string name="module_sort_z_to_a">Сортувати (Я-А)</string>
<string name="module_size_low_to_high">Сортувати (Менше → Більше)</string>
<string name="module_size_high_to_low">Сортувати (Більше → Менше)</string>
<string name="uninstall">Видалити</string>
<string name="restore">Відновити</string>
<string name="module_install">Встановити</string>
<string name="install">Встановити</string>
<string name="reboot">Перезавантаження</string>
<string name="settings">Налаштування</string>
<string name="uninstalled">Видалено</string>
<string name="settings">Параметри</string>
<string name="reboot_userspace">М’яка перезавантаження</string>
<string name="reboot_recovery">Перезавантаження в Recovery</string>
<string name="reboot_bootloader">Перезавантаження в Bootloader</string>
@@ -87,19 +93,20 @@
<string name="reboot_required">Потрібно перезавантаження</string>
<string name="reboot_message">Зміни вступлять в силу після перезавантаження системи. Перезавантажити зараз?</string>
<string name="module_restore">Відновити модуль</string>
<string name="module_restore_message">Відновлення модулів із останньої резервної копії.</string>
<string name="backup_restore">Резервне копіювання і відновлення</string>
<string name="module_restore_message">Відновлення модулів із останнього бекапу.</string>
<string name="backup_restore">Бекап і відновлення</string>
<string name="module_backup">Бекап модуля</string>
<string name="module_backup_message">Бекап поточних встановлених модулів.</string>
<string name="allowlist_restore">Відновити список дозволів</string>
<string name="allowlist_restore_message">Відновити список дозволів із останнього резервного копіювання.</string>
<string name="allowlist_restore_message">Відновити список дозволів із останнього бекапу.</string>
<string name="allowlist_backup">Бекап списку дозволів</string>
<string name="allowlist_backup_message">Бекап поточного списку дозволів.</string>
<string name="warning">Попередження</string>
<string name="warning_message">Ця функція все ще перебуває у стадії бета-тестування. Будь ласка, переконайтеся, що ви створили резервні копії модулів перед використанням. Використовуйте це лише якщо розумієте можливі ризики. Будьте обережні.</string>
<string name="warning_message">Ця функція все ще перебуває у стадії бета-тестування. Будь ласка, переконайтеся, що ви створили бекап модулів перед використанням. Використовуйте це лише якщо розумієте можливі ризики. Будьте обережні.</string>
<string name="proceed">Продовжити</string>
<string name="cancel">Скасувати</string>
<string name="later">Пізніше</string>
<string name="lkm_warning_message">Патч LKM базується на компонентах із закритим кодом. Продовжити?</string>
<string name="home_next_kernelsu">🔥 Наступна збірка</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Наступна експериментальна гілка. Подивіться на GitHub!</string>
@@ -109,9 +116,9 @@
<string name="home_experimental_kernelsu_body_point_1"> • Використовуйте на свій страх і ризик: можуть виникати збої, несподівана поведінка або проблеми з системою.</string>
<string name="home_experimental_kernelsu_body_point_2"> • Попередження: розробники не несуть відповідальності за втрату даних, пошкодження системи або інші наслідки, викликані використанням.</string>
<string name="home_experimental_kernelsu_body_point_3"> • Лише для тестування: призначено для користувачів, які розуміють ризики і готові вирішувати виникаючі проблеми.</string>
<string name="about_source_code"><![CDATA[Переглянути вихідний код на %1$s]]></string>
<string name="about_source_code"><![CDATA[Вихідний код на %1$s]]></string>
<string name="profile" translatable="false">Профіль додатка</string>
<string name="profile_default">За замовчуванням</string>
<string name="profile_default">Дефолт</string>
<string name="profile_template">Шаблон</string>
<string name="profile_custom">Налаштувати</string>
<string name="profile_name">Ім’я профілю</string>
@@ -133,6 +140,7 @@
<string name="profile_selinux_domain">Домен</string>
<string name="profile_selinux_rules">Правила</string>
<string name="module_update">Оновити</string>
<string name="module_updated">Оновлено</string>
<string name="module_downloading">Завантаження модуля: %s</string>
<string name="module_start_downloading">Початок завантаження: %s</string>
<string name="new_version_available">Доступна нова версія %s, натисніть для оновлення.</string>
@@ -140,6 +148,10 @@
<string name="close">Закрити</string>
<string name="force_stop_app">Примусово зупинити</string>
<string name="restart_app">Перезапустити</string>
<string name="settings_amoled_mode">AMOLED-режим</string>
<string name="settings_amoled_mode_summary">Увімкніть чисто чорну тему, корисну для екранів AMOLED, щоб зменшити навантаження на очі та заощадити заряд батареї.</string>
<string name="restart_required">Потрібно перезавантажити</string>
<string name="restart_app_message">Щоб ця зміна набула чинності, потрібно перезапустити програму.</string>
<string name="failed_to_update_sepolicy">Не вдалося оновити правила SELinux для: %s</string>
<string name="su_not_allowed">Надання прав суперкористувача заборонено для: %s</string>
<string name="module_changelog">Журнал змін</string>
@@ -168,8 +180,9 @@
<string name="settings_check_update">Перевіряти оновлення</string>
<string name="settings_check_update_summary">Автоматично перевіряти оновлення при відкритті додатка.</string>
<string name="grant_root_failed">Не вдалося надати root-доступ!</string>
<string name="action">Запустити</string>
<string name="open">Відкрити</string>
<string name="action">Скрипт</string>
<string name="webui">WebUI</string>
<string name="open">WebUI</string>
<string name="enable_web_debugging">Відладка WebView</string>
<string name="enable_web_debugging_summary">Можна використовувати для відладки WebUI. Увімкніть лише при необхідності.</string>
<string name="direct_install">Пряма установка (Рекомендовано)</string>
@@ -179,27 +192,34 @@
<string name="install_next">Далі</string>
<string name="select_file_tip">Рекомендовано образ розділу %1$s</string>
<string name="select_kmi">Виберіть KMI</string>
<string name="shrink_sparse_image">Зменшити modules.img образ</string>
<string name="shrink_sparse_image_message">Змініть розмір modules.img образу, у якому знаходяться модулі, до його фактичного розміру. Зверніть увагу, що це може викликати ненормальну роботу модулів, тому використовуйте лише при необхідності (наприклад, для резервного копіювання).</string>
<string name="shrink_sparse_image">Мінімізувати розріджене зображення</string>
<string name="shrink_sparse_image_message">Змініть розмір розрідженого зображення, де розташований модуль, до його фактичного розміру. Зверніть увагу, що це може призвести до неправильної роботи модуля, тому використовуйте його лише за необхідності (наприклад, для бекапу).</string>
<string name="settings_uninstall">Видалення</string>
<string name="settings_uninstall_temporary">Тимчасове видалення</string>
<string name="settings_uninstall_permanent">Повне видалення</string>
<string name="settings_restore_stock_image">Відновити стандартний образ</string>
<string name="settings_uninstall_temporary_message">Тимчасово видаліть KernelSU Next, відновивши початковий стан після наступного перезавантаження.</string>
<string name="settings_uninstall_permanent_message">Повне і остаточне видалення KernelSU Next (Root та всіх модулів).</string>
<string name="settings_restore_stock_image_message">Відновлення стандартного заводського образу (якщо є резервна копія), зазвичай використовується перед OTA; якщо потрібно видалити KernelSU Next, використовуйте "Повне видалення".</string>
<string name="settings_restore_stock_image_message">Відновлення стандартного заводського образу (якщо є бекап), зазвичай використовується перед OTA; якщо потрібно видалити KernelSU Next, використовуйте "Повне видалення".</string>
<string name="flashing">Прошивка</string>
<string name="flash_success">Прошивка виконана успішно</string>
<string name="flash_failed">Помилка прошивки</string>
<string name="selected_lkm">Вибрано LKM: %s</string>
<string name="save_log">Зберегти логи</string>
<string name="save_log">Зберегти\nлоги</string>
<string name="log_saved">Логи збережено</string>
<string name="send_log">Поділитися логами</string>
<string name="send_log">Поділитися\nлогами</string>
<string name="settings_disable_su">Вимкн. сумісність із su</string>
<string name="settings_disable_su_summary">Тимчасово вимкнути можливість додаткам отримувати права root через команду su (існуючі процеси з правами root не будуть зачеплені).</string>
<string name="settings_language">Мова</string>
<string name="settings_legacyui">Використовувати застарілий UI</string>
<string name="settings_legacyui_summary">Перейти до попереднього стилю інтерфейсу користувача.</string>
<string name="settings_banner">Увімкнути банери</string>
<string name="settings_banner_summary">Показувати фонові банери для модулів.</string>
<string name="use_webuix">Використовувати WebUI X</string>
<string name="use_webuix_summary">Використовувати WebUI X замість WebUI, який підтримує більше API.</string>
<string name="use_webuix_eruda">Інжект Eruda у WebUI X</string>
<string name="use_webuix_eruda_summary">Інжектити консоль відладки у WebUI X, щоб спростити відладку. Потрібно увімкнути відладку WebView.</string>
<string name="customization">Кастомізація</string>
<string name="developer">Для Розробників</string>
<string name="sucompat_disabled">SUCOMPAT ВИМКНЕНО</string>
</resources>

View File

@@ -14,21 +14,26 @@
<string name="home_click_to_install">Bấm để cài đặt</string>
<string name="lkm_mode_deprecated">Chế độ LKM không còn được hỗ trợ!</string>
<string name="lkm_alternative_suggestion">Cài đặt kernel GKI hoặc tự nhúng KernelSU Next vào kernel của bạn.</string>
<string name="home_working">Đã cài đặt và hoạt động</string>
<string name="home_working">Đã cài đặt</string>
<string name="home_working_version">Phiên bản: %d</string>
<string name="home_superuser_count">Ứng dụng đã cấp su: %d</string>
<string name="home_module_count">Module: %d</string>
<string name="home_module_update_count">Module có cập nhật: %d</string>
<string name="home_failure">Không tìm thấy chữ kí KernelSU Next v2 (chưa cài đặt, nhúng sai cách hoặc nhầm trình quản lý?) [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">Hỏi hoặc tự nhúng KernelSU Next vào kernel của bạn!</string>
<string name="home_failure_tip">Hỏi hoặc tự nhúng nhân KernelSU Next vào kernel của bạn!</string>
<string name="home_kernel">Phiên bản kernel</string>
<string name="enabled">Kích hoạt</string>
<string name="disabled">Vô hiệu hoá</string>
<string name="hook_mode">Chế độ hook</string>
<string name="enable">Kích hoạt</string>
<string name="disable">Vô hiệu hóa</string>
<string name="enabled">Đã kích hoạt</string>
<string name="disabled">Đã vô hiệu hoá</string>
<string name="susfs_supported">Hỗ trợ</string>
<string name="home_susfs">SuSFS: %s</string>
<string name="home_susfs_version">Phiên bản SuSFS</string>
<string name="home_susfs_sus_su">SuS SU</string>
<string name="home_android">Phiên bản Android</string>
<string name="home_manager_version">Phiên bản trình quản lý</string>
<string name="home_abi">ABI</string>
<string name="home_selinux_status">Trạng thái SELinux</string>
<string name="selinux_status_disabled">Vô hiệu hoá</string>
<string name="selinux_status_enforcing">Enforcing</string>
@@ -42,13 +47,16 @@
<string name="module_install_prompt_with_name">Bạn có THẬT SỰ muốn cài module này không (kiểm tra trước khi cài ASAF) %1$s?</string>
<string name="module_sort_a_to_z">Sắp xếp (A-Z)</string>
<string name="module_sort_z_to_a">Sắp xếp (Z-A)</string>
<string name="module_size_low_to_high">Sắp xếp (Thấp → Cao)</string>
<string name="module_size_high_to_low">Sắp xếp (Cao → Thấp)</string>
<string name="uninstall">Gỡ cài đặt</string>
<string name="restore">Khôi phục</string>
<string name="module_install">Cài đặt</string>
<string name="install">Cài đặt</string>
<string name="reboot">Khởi động lại</string>
<string name="uninstalled">Đã gỡ cài đặt</string>
<string name="settings">Cài đặt</string>
<string name="reboot_userspace">Khởi động mềm</string>
<string name="reboot_userspace">Khởi động TẠM</string>
<string name="reboot_recovery">Vào Recovery</string>
<string name="reboot_bootloader">Vào Bootloader</string>
<string name="reboot_download">Vào Download Mode</string>
@@ -66,7 +74,7 @@
<string name="module_version_code">Code</string>
<string name="module_update_json">UpdateJson</string>
<string name="module_update_json_empty">Trống</string>
<string name="enable_developer_options">Kích hoạt tính năng dành cho nhà phát triển</string>
<string name="enable_developer_options">Cài đặt dành cho nhà phát triển</string>
<string name="enable_developer_options_summary">Hiện thị những cài đặt ẩn và nhũng log DÀNH RIÊNG CHO NHÀ PHÁT TRIỂN.</string>
<string name="module_overlay_fs_not_available">Không thể sử dụng module vì flag Overlayfs không được kích hoạt trong kernel, vui lòng kích hoạt</string>
<string name="refresh">Làm mới</string>
@@ -98,6 +106,7 @@
<string name="proceed">Tiếp tục</string>
<string name="cancel">Huỷ</string>
<string name="later">Để sau</string>
<string name="lkm_warning_message">Bản vá LKM này có những thành phần mã nguồn đóng, bạn có muốn tiếp tục không</string>
<string name="home_next_kernelsu">🔥 Bản dựng tiếp theo</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Nhánh thử nghiệm tiếp theo. Xem trong GitHub!</string>
@@ -108,7 +117,7 @@
<string name="home_experimental_kernelsu_body_point_2"> • Không bảo hành: Các nhà phát triển KernelSU Next và bên thứ 3 sẽ không chịu trách nghiệm cho hardbrick, bootloop, mất dữ liệu,...</string>
<string name="home_experimental_kernelsu_body_point_3"> • Đùng để thử nghiệm là chính: Chỉ dành cho những người có kĩ năng, kinh nghiệm, trải nghiệm .</string>
<string name="about_source_code"><![CDATA[Xem mã nguồn tại %1$s]]></string>
<string name="profile" translatable="false">Hồ sơ ứng dụng</string>
<string name="profile" translatable="false">App Profile</string>
<string name="profile_default">Mặc định</string>
<string name="profile_template">Mẫu</string>
<string name="profile_custom">Tuỳ biến</string>
@@ -131,6 +140,7 @@
<string name="profile_selinux_domain">Tên miền</string>
<string name="profile_selinux_rules">Quyền</string>
<string name="module_update">Có cập nhật!</string>
<string name="module_updated">Đã cập nhật</string>
<string name="module_downloading">Tải xuống module: %s</string>
<string name="module_start_downloading">Đang tải xuống module: %s</string>
<string name="new_version_available">Phiên bản %s đã ra mắt, bấm để cập nhật.</string>
@@ -138,6 +148,10 @@
<string name="close">Đóng</string>
<string name="force_stop_app">Buộc tắt</string>
<string name="restart_app">Khởi động lại</string>
<string name="settings_amoled_mode">Chế độ AMOLED</string>
<string name="settings_amoled_mode_summary">Kích hoạt nền đen tuyền, tốt cho mắt và pin trên những thiết bị sử dụng màn AMOLED/OLED.</string>
<string name="restart_required">Yêu cầu khởi động lại</string>
<string name="restart_app_message">Ứng dụng yêu cầu khởi động lại để có hiệu lực.</string>
<string name="failed_to_update_sepolicy">Cập nhật phân quyền SELinux thất bại cho: %s</string>
<string name="su_not_allowed">Cấp quyền SU không được phép cho: %s</string>
<string name="module_changelog">Nhật kí thay đổi</string>
@@ -162,13 +176,14 @@
<string name="app_profile_template_sync">Đồng bộ với hồ sơ ứng dụng trực tuyến</string>
<string name="app_profile_template_save_failed">Lưu hồ sơ ứng dụng thất bại</string>
<string name="app_profile_template_import_empty">Bảng nhớ tạm đang trống hoặc sai thông tin!</string>
<string name="module_changelog_failed">Đọc nhất kí thay đôi thất bại: %s</string>
<string name="module_changelog_failed">Lấy nhất kí thay đổi module thất bại: %s</string>
<string name="settings_check_update">Kiểm tra cập nhật</string>
<string name="settings_check_update_summary">Tự động kiểm tra cập nhật khi mở ứng dụng.</string>
<string name="grant_root_failed">Cấp quyền root thất bại!</string>
<string name="action">Chạy</string>
<string name="webui">WebUI</string>
<string name="open">Mở</string>
<string name="enable_web_debugging">Kích hoạt WebView debugging</string>
<string name="enable_web_debugging">Kích hoạt gỡ lỗi WebView</string>
<string name="enable_web_debugging_summary">Sử dụng để debug WebUI. Sử dụng khi bạn có kinh nghiệm, kĩ năng.</string>
<string name="direct_install">Cài đặt trực tiếp (cho GKI 2.0)</string>
<string name="select_file">Chọn file</string>
@@ -193,11 +208,18 @@
<string name="save_log">Lưu logs</string>
<string name="log_saved">Logs đã được lưu</string>
<string name="send_log">Chia sẻ logs</string>
<string name="settings_disable_su">Vô hiệu hoá khả năng của lệnh SU</string>
<string name="settings_disable_su">Vô hiệu hoá lệnh SU</string>
<string name="settings_disable_su_summary">Vô hiệu hoá khả năng thực thi lệnh SU để lấy quyền root (những app đã cấp trước đó không bị ảnh hưởng).</string>
<string name="settings_language">Ngôn ngữ</string>
<string name="settings_legacyui">Sử dụng giao diện cũ</string>
<string name="settings_legacyui_summary">Chuyển về giao diện cũ.</string>
<string name="settings_banner">Hiện thị ảnh bìa</string>
<string name="settings_banner_summary">Hiện thị ảnh bìa trong module.</string>
<string name="use_webuix">Dùng WebUI X</string>
<string name="use_webuix_summary">Dùng WebUI X thay vì WebUI (hỗ trợ nhiều API hơn).</string>
<string name="use_webuix_eruda">Nhúng nhân Eruda vào WebUI X</string>
<string name="use_webuix_eruda_summary">Nhúng trình gỡ lỗi vào WebUI X để việc sửa lỗi thuận tiện hơn. Yêu cầu gỡ lỗi webview được bật.</string>
<string name="customization">Tùy biến</string>
<string name="developer">Cài đặt nhà phát triển</string>
<string name="sucompat_disabled">ĐÃ VÔ HIỆU HÓA SUCOMPAT</string>
</resources>

View File

@@ -4,7 +4,7 @@
<string name="issue_report_body">发现错误或者有改进建议?</string>
<string name="issue_report_body_2">快向我们报告吧!</string>
<string name="issue_report_github">在 GitHub 报告</string>
<string name="issue_report_telegram">在 Telegram 联系</string>
<string name="issue_report_telegram">在 Telegram 获得最新消息</string>
<string name="issue_report_github_link">https://github.com/KernelSU-Next/KernelSU-Next/issues</string>
<string name="issue_report_telegram_link">https://t.me/ksunext</string>
<string name="confirm">确认</string>
@@ -12,42 +12,55 @@
<string name="home">主页</string>
<string name="home_not_installed">未安装</string>
<string name="home_click_to_install">点击安装</string>
<string name="lkm_mode_deprecated">LKM 模式现已弃用!</string>
<string name="lkm_alternative_suggestion">请使用 GKI 内核或手动将 KernelSU Next 集成到你的设备。</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_module_update_count">%d 个模块可更新!</string>
<string name="home_failure">内核中未找到 KernelSU Next V2 签名! [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">请让你的内核开发人员集成 KernelSU Next</string>
<string name="home_kernel">内核版本</string>
<string name="hook_mode">Hook 模式</string>
<string name="enable">启用</string>
<string name="disable">禁用</string>
<string name="enabled">已启用</string>
<string name="disabled">已禁用</string>
<string name="susfs_supported">支持</string>
<string name="home_susfs">SuSFS%s</string>
<string name="home_susfs_version">SuSFS 版本</string>
<string name="home_susfs_sus_su">SuS SU</string>
<string name="home_android">Android 版本</string>
<string name="home_manager_version">管理器版本</string>
<string name="home_abi">接口</string>
<string name="home_selinux_status">SELinux 状态</string>
<string name="selinux_status_disabled">禁用</string>
<string name="selinux_status_enforcing">强制执行</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_failed_to_enable">启用模块失败数%s</string>
<string name="module_failed_to_disable">禁用模块失败数%s</string>
<string name="module_empty">什么都没有呢</string>
<string name="module">模块</string>
<string name="module_install_prompt_with_name">是否要继续安装模块 %1$s </string>
<string name="module_sort_a_to_z">按 AZ 排序</string>
<string name="module_sort_z_to_a">按 ZA 排序</string>
<string name="module_sort_a_to_z">按 A - Z 排序</string>
<string name="module_sort_z_to_a">按 Z - A 排序</string>
<string name="module_size_low_to_high">正序排序(按模块大小)</string>
<string name="module_size_high_to_low">倒序排序(按模块大小)</string>
<string name="uninstall">卸载</string>
<string name="restore">恢复</string>
<string name="module_install">安装</string>
<string name="install">安装</string>
<string name="reboot">重启</string>
<string name="uninstalled">重启以应用卸载</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="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>
@@ -62,20 +75,20 @@
<string name="module_update_json">更新配置</string>
<string name="module_update_json_empty">无更新配置</string>
<string name="enable_developer_options">启用开发者模式</string>
<string name="enable_developer_options_summary">显示隐藏的开发者专用设置和调试信息</string>
<string name="module_overlay_fs_not_available">OverlayFS 被内核禁用,模块不可用</string>
<string name="enable_developer_options_summary">显示隐藏的开发者专用设置和调试信息</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="export_log">导出日志</string>
<string name="safe_mode">安全模式</string>
<string name="reboot_to_apply">重启生效</string>
<string name="module_magisk_conflict">由于与 Magisk 冲突,模块不可用</string>
<string name="module_magisk_conflict">由于与 Magisk 冲突,模块系统不可用</string>
<string name="home_mount_system">模块系统</string>
<string name="home_magic_mount">Magic Mount</string>
<string name="home_overlayfs_mount">OverlayFS</string>
<string name="unavailable">不可用</string>
<string name="use_overlay_fs">使用 OverlayFS(实验性)</string>
<string name="use_overlay_fs">使用 OverlayFS</string>
<string name="use_overlay_fs_summary">在 OverlayFS 和 Magic Mount 两种挂载系统之间进行切换。</string>
<string name="reboot_required">需要重启</string>
<string name="reboot_message">更改将在重启系统后生效。您想现在重启吗?</string>
@@ -88,21 +101,22 @@
<string name="allowlist_backup_message">备份当前的超级用户列表</string>
<string name="module_backup">备份模块</string>
<string name="module_backup_message">备份当前已安装的模块。</string>
<string name="warning">警告</string>
<string name="warning">免责声明</string>
<string name="warning_message">此为尚在开发阶段的实验功能,继续操作前请确保模块已备份。使用此功能需要先了解其风险,在知晓后果的情况下谨慎操作。</string>
<string name="proceed">继续</string>
<string name="cancel">取消</string>
<string name="later">稍后</string>
<string name="lkm_warning_message">此 LKM 补丁依赖于闭源组件,确认操作代表你知晓因继续使用该功能所导致的一切后果与开发团队无关。</string>
<string name="home_next_kernelsu">🔥 Next 构建</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Next 实验性分支。在 GitHub 上查看!</string>
<string name="home_experimental_kernelsu">⚠️ 实验性开发警告!</string>
<string name="home_experimental_kernelsu_repo">127.0.0.1</string>
<string name="home_experimental_kernelsu_body">KernelSU Next 属于第三方版本,保持着积极的实验开发。该版本所得即所用,不保证稳定性、性能和可靠性。</string>
<string name="home_experimental_kernelsu_body_point_1"> • 风险自担:可能会发生崩溃、意外行为或导致系统故障。</string>
<string name="home_experimental_kernelsu_body_point_1"> • 风险自担:可能会出现崩溃、意外行为或导致系统故障。</string>
<string name="home_experimental_kernelsu_body_point_2"> • 不做保证:开发者不对数据丢失、系统损坏等问题负责。</string>
<string name="home_experimental_kernelsu_body_point_3"> • 仅供测试:此版适合了解风险并能轻松解决问题的用户。</string>
<string name="about_source_code"><![CDATA[在 %1$s 查看源码]]></string>
<string name="about_source_code"><![CDATA[在 %1$s 查看源码]]></string>
<string name="profile" translatable="false">App Profile</string>
<string name="profile_default">默认</string>
<string name="profile_template">模板</string>
@@ -126,6 +140,8 @@
<string name="profile_selinux_domain"></string>
<string name="profile_selinux_rules">规则</string>
<string name="module_update">更新</string>
<string name="module_update_available">更新可用</string>
<string name="module_updated">重启以应用更新</string>
<string name="module_downloading">正在下载模块: %s</string>
<string name="module_start_downloading">开始下载: %s</string>
<string name="new_version_available">发现新版本:%s点击升级。</string>
@@ -133,15 +149,19 @@
<string name="close">关闭</string>
<string name="force_stop_app">强制停止</string>
<string name="restart_app">重新启动</string>
<string name="settings_amoled_mode">AMOLED 模式</string>
<string name="settings_amoled_mode_summary">启用适用于 AMOLED 屏幕的纯黑主题,可减少视觉疲劳并节省电量。</string>
<string name="restart_required">需要重启</string>
<string name="restart_app_message">请重启 APP 以确保更改生效。</string>
<string name="failed_to_update_sepolicy">为 %s 更新 SELinux 规则失败</string>
<string name="su_not_allowed">拒绝授予%s超级用户权限</string>
<string name="module_changelog">更新日志</string>
<string name="settings_profile_template">App Profile 模板</string>
<string name="settings_profile_template_summary">管理本地和在线的 App Profile 模版</string>
<string name="settings_profile_template_summary">管理本地和在线的 App Profile 模版</string>
<string name="app_profile_template_create">创建模版</string>
<string name="app_profile_template_edit">编辑模版</string>
<string name="app_profile_template_id">模板 ID</string>
<string name="app_profile_template_id_invalid">模板 ID 不合</string>
<string name="app_profile_template_id_invalid">模板 ID 不合</string>
<string name="app_profile_template_name">名字</string>
<string name="app_profile_template_description">描述</string>
<string name="app_profile_template_save">保存</string>
@@ -159,9 +179,10 @@
<string name="app_profile_template_import_empty">剪贴板为空!</string>
<string name="module_changelog_failed">获取更新日志失败: %s</string>
<string name="settings_check_update">检查更新</string>
<string name="settings_check_update_summary">在应用启动后自动检查是否有新版。</string>
<string name="settings_check_update_summary">在应用启动后自动检查是否有新版</string>
<string name="grant_root_failed">获取 root 失败!</string>
<string name="action">执行</string>
<string name="webui">WebUI</string>
<string name="open">打开</string>
<string name="enable_web_debugging">启用 WebView 调试</string>
<string name="enable_web_debugging_summary">可用于调试 WebUI请仅在需要时启用。</string>
@@ -173,7 +194,7 @@
<string name="select_file_tip">建议选择 %1$s 分区镜像</string>
<string name="select_kmi">选择 KMI</string>
<string name="shrink_sparse_image">最小化稀疏文件</string>
<string name="shrink_sparse_image_message">将模块所在的稀疏文件镜像调整为其实际大小,注意这可能导致模块工作异常,请仅在必要时(如备份)使用</string>
<string name="shrink_sparse_image_message">将模块所在的稀疏文件镜像调整为其实际大小,注意这可能导致模块工作异常,请仅在必要时(如备份)使用</string>
<string name="settings_uninstall">卸载</string>
<string name="settings_uninstall_temporary">临时卸载</string>
<string name="settings_uninstall_permanent">完全卸载</string>
@@ -189,6 +210,18 @@
<string name="log_saved">日志已保存</string>
<string name="send_log">分享日志</string>
<string name="settings_disable_su">禁用超级用户指令</string>
<string name="settings_disable_su_summary">临时禁止任何应用通过 su 命令获取 root 权限(运行的 root 进程不受影响)</string>
<string name="settings_disable_su_summary">临时禁止任何应用通过 su 命令获取 root 权限(正在运行的 root 进程不受影响)</string>
<string name="settings_language">语言</string>
<string name="system_default">系统默认</string>
<string name="settings_legacyui">切换到传统 UI</string>
<string name="settings_legacyui_summary">使用早期的用户界面风格。</string>
<string name="settings_banner">启用横幅</string>
<string name="settings_banner_summary">针对模块启用背景横幅。</string>
<string name="use_webuix">使用 WebUI X</string>
<string name="use_webuix_summary">使用更完善的 WebUI X 来取代旧有 WebUI请注意模块开发者可在模块信息中单独覆盖此项设置。</string>
<string name="use_webuix_eruda">对 WebUI X 注入 Eruda</string>
<string name="use_webuix_eruda_summary">使用 WebUI X 时注入控制台以便于调试,需要启用 WebView 调试功能。</string>
<string name="customization">外观</string>
<string name="developer">开发者选项</string>
<string name="sucompat_disabled">SUCOMPAT 已禁用</string>
</resources>

View File

@@ -3,8 +3,8 @@
<string name="issue_report_title">有任何問題?</string>
<string name="issue_report_body">遇到錯誤或者需要反饋?</string>
<string name="issue_report_body_2">請儘快告知我們!</string>
<string name="issue_report_github"> GitHub 回報</string>
<string name="issue_report_telegram">透過 Telegram 聯繫</string>
<string name="issue_report_github"> GitHub 回報</string>
<string name="issue_report_telegram">透過 Telegram 取得最新情報</string>
<string name="issue_report_github_link">https://github.com/KernelSU-Next/KernelSU-Next/issues</string>
<string name="issue_report_telegram_link">https://t.me/ksunext</string>
<string name="confirm">確認</string>
@@ -12,18 +12,28 @@
<string name="home">主頁</string>
<string name="home_not_installed">未安裝</string>
<string name="home_click_to_install">點擊安裝</string>
<string name="lkm_mode_deprecated">LKM 模式現已棄用!</string>
<string name="lkm_alternative_suggestion">請使用 GKI 內核或手動將 KernelSU Next 整合到你的裝置。</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_module_update_count">可升級模組: %d</string>
<string name="home_failure">內核中未找到 KernelSU Next v2 簽名! [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">請讓你的內核開發人員整合 KernelSU Next</string>
<string name="home_kernel">內核版本</string>
<string name="hook_mode">Hook 方法</string>
<string name="enable">啓用</string>
<string name="disable">禁用</string>
<string name="enabled">已經啓用</string>
<string name="disabled">已經禁用</string>
<string name="susfs_supported">支援</string>
<string name="home_susfs">SuSFS%s</string>
<string name="home_susfs_version">SuSFS 版本</string>
<string name="home_susfs_sus_su">SuS SU</string>
<string name="home_android">Android 版本</string>
<string name="home_manager_version">管理版本</string>
<string name="home_manager_version">管理版本</string>
<string name="home_abi">ABI</string>
<string name="home_selinux_status">SELinux 狀態</string>
<string name="selinux_status_disabled">被禁用</string>
<string name="selinux_status_enforcing">強制執行</string>
@@ -37,11 +47,14 @@
<string name="module_install_prompt_with_name">是否要繼續安裝模組 %1$s </string>
<string name="module_sort_a_to_z">按 A - Z 排序</string>
<string name="module_sort_z_to_a">按 Z - A 排序</string>
<string name="module_size_low_to_high">正序排序(按模組大小)</string>
<string name="module_size_high_to_low">倒序排序(按模組大小)</string>
<string name="uninstall">卸載</string>
<string name="restore">恢復</string>
<string name="module_install">安裝</string>
<string name="install">安裝</string>
<string name="reboot">重啟</string>
<string name="uninstalled">重啓以完成卸載</string>
<string name="settings">設定</string>
<string name="reboot_userspace">軟重啟</string>
<string name="reboot_recovery">重啟到 Recovery</string>
@@ -63,7 +76,7 @@
<string name="module_update_json_empty">無更新配置</string>
<string name="enable_developer_options">啟用開發人員模式</string>
<string name="enable_developer_options_summary">顯示隱藏的開發人員專用設置和調試信息</string>
<string name="module_overlay_fs_not_available">OverlayFS 被內核禁用,模組不可用。</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>
@@ -75,7 +88,7 @@
<string name="home_magic_mount">Magic Mount</string>
<string name="home_overlayfs_mount">OverlayFS</string>
<string name="unavailable">不可用</string>
<string name="use_overlay_fs">使用 OverlayFS (實驗性功能)</string>
<string name="use_overlay_fs">使用 OverlayFS</string>
<string name="use_overlay_fs_summary">對於 KernelSU Next 的掛載系統,在使用 OverlayFS 和 Magic Mount 之間進行切換。</string>
<string name="reboot_required">需要重啟</string>
<string name="reboot_message">更改將在重啟系統後生效。您想現在重啟嗎?</string>
@@ -93,6 +106,7 @@
<string name="proceed">繼續</string>
<string name="cancel">取消</string>
<string name="later">稍後</string>
<string name="lkm_warning_message">該 LKM 補丁依賴閉源元件,確定繼續嗎?</string>
<string name="home_next_kernelsu">🔥 Next 構建</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Next 實驗性分支。在 GitHub 上查看!</string>
@@ -126,6 +140,8 @@
<string name="profile_selinux_domain"></string>
<string name="profile_selinux_rules">規則</string>
<string name="module_update">更新</string>
<string name="module_update_available">更新可用</string>
<string name="module_updated">重啓以完成更新</string>
<string name="module_downloading">正在下載模組: %s</string>
<string name="module_start_downloading">開始下載: %s</string>
<string name="new_version_available">發現新版本:%s點擊升級。</string>
@@ -133,22 +149,26 @@
<string name="close">關閉</string>
<string name="force_stop_app">強制停止</string>
<string name="restart_app">重新啟動</string>
<string name="settings_amoled_mode">AMOLED 模式</string>
<string name="settings_amoled_mode_summary">啓用 AMOLED 屏幕專用的純黑主題,減少視覺疲勞的同時節約電池使用。</string>
<string name="restart_required">需要重啓</string>
<string name="restart_app_message">請重啓程式確保改動生效。</string>
<string name="failed_to_update_sepolicy">為:%s 更新 SELinux 規則失敗</string>
<string name="su_not_allowed">拒絕授予%s超級使用者權限</string>
<string name="module_changelog">更新日誌</string>
<string name="settings_profile_template">App Profile 模板</string>
<string name="settings_profile_template_summary">管理本地和線上的 App Profile 模板</string>
<string name="settings_profile_template_summary">管理本地和線上的 App Profile 模板</string>
<string name="app_profile_template_create">創建模板</string>
<string name="app_profile_template_edit">編輯模板</string>
<string name="app_profile_template_id">模板 id</string>
<string name="app_profile_template_id_invalid">模板 id 不合法</string>
<string name="app_profile_template_id">模板 ID</string>
<string name="app_profile_template_id_invalid">模板 ID 不合法</string>
<string name="app_profile_template_name">名字</string>
<string name="app_profile_template_description">描述</string>
<string name="app_profile_template_save">保存</string>
<string name="app_profile_template_delete">刪除</string>
<string name="app_profile_template_view">查看模板</string>
<string name="app_profile_template_readonly">只讀</string>
<string name="app_profile_template_id_exist">模板 id 已存在!</string>
<string name="app_profile_template_id_exist">模板 ID 已存在!</string>
<string name="app_profile_import_export">匯入/匯出</string>
<string name="app_profile_import_from_clipboard">從剪貼簿匯入</string>
<string name="app_profile_export_to_clipboard">匯出到剪貼簿</string>
@@ -159,12 +179,13 @@
<string name="app_profile_template_import_empty">剪貼簿為空!</string>
<string name="module_changelog_failed">獲取更新日誌失敗: %s</string>
<string name="settings_check_update">檢查更新</string>
<string name="settings_check_update_summary">在應用啟動後自動檢查是否有新版。</string>
<string name="settings_check_update_summary">在應用啟動後自動檢查是否有新版</string>
<string name="grant_root_failed">獲取 root 失敗!</string>
<string name="action">執行</string>
<string name="webui">WebUI</string>
<string name="open">打開</string>
<string name="enable_web_debugging">啟用 WebView 偵錯</string>
<string name="enable_web_debugging_summary">可用於偵錯 WebUI 僅在需要時啟用。</string>
<string name="enable_web_debugging_summary">可用於偵錯 WebUI ,僅在需要時啟用。</string>
<string name="direct_install">直接安裝(推薦)</string>
<string name="select_file">選擇一個檔案</string>
<string name="install_inactive_slot">安裝到未使用的槽位OTA 後)</string>
@@ -173,7 +194,7 @@
<string name="select_file_tip">建議選擇 %1$s 分區映像檔</string>
<string name="select_kmi">選擇 KMI</string>
<string name="shrink_sparse_image">最小化稀疏檔案</string>
<string name="shrink_sparse_image_message">將模組所在的稀疏檔案映像調整為其實際大小,注意這可能導致模組工作異常,請僅在必要時(如備份)使用</string>
<string name="shrink_sparse_image_message">將模組所在的稀疏檔案映像調整為其實際大小,注意這可能導致模組工作異常,請僅在必要時(如備份)使用</string>
<string name="settings_uninstall">卸載</string>
<string name="settings_uninstall_temporary">臨時卸載</string>
<string name="settings_uninstall_permanent">永久卸載</string>
@@ -189,6 +210,18 @@
<string name="log_saved">日誌已保存</string>
<string name="send_log">發送日誌</string>
<string name="settings_disable_su">關閉 SU 相容</string>
<string name="settings_disable_su_summary">暫時禁止任何應用通過 su 命令獲取 root 權限(已運行的 root 進程不受影響)</string>
<string name="settings_disable_su_summary">暫時禁止任何應用通過 su 命令獲取 root 權限(已運行的 root 進程不受影響)</string>
<string name="settings_language">語言</string>
<string name="system_default">跟隨系統</string>
<string name="settings_legacyui">換回傳統 UI</string>
<string name="settings_legacyui_summary">使用早期版本 UI 風格。</string>
<string name="settings_banner">啓用橫幅</string>
<string name="settings_banner_summary">對模組啓用背景橫幅。</string>
<string name="use_webuix">使用 WebUI X</string>
<string name="use_webuix_summary">使用更爲完善的 WebUI X 而不是 WebUI請注意模組開發人員能在模組信息中覆寫這個設置。</string>
<string name="use_webuix_eruda">將 Eruda 注入 WebUI X</string>
<string name="use_webuix_eruda_summary">在使用 WebUI X 時注入控制台以便於偵錯,需要啟用 WebView 偵錯功能。</string>
<string name="customization">自訂外觀</string>
<string name="developer">開發人員設定</string>
<string name="sucompat_disabled">SUCOMPAT 已經禁用</string>
</resources>

View File

@@ -56,7 +56,7 @@
<string name="reboot">Reboot</string>
<string name="uninstalled">Uninstalled</string>
<string name="settings">Settings</string>
<string name="reboot_userspace">Soft Reboot</string>
<string name="reboot_userspace">Soft reboot</string>
<string name="reboot_recovery">Reboot to Recovery</string>
<string name="reboot_bootloader">Reboot to Bootloader</string>
<string name="reboot_download">Reboot to Download</string>
@@ -112,7 +112,7 @@
<string name="home_next_kernelsu_body">Next experimental branch. Check it out on GitHub!</string>
<string name="home_experimental_kernelsu">⚠️ Experimental development warning!</string>
<string name="home_experimental_kernelsu_repo">127.0.0.1</string>
<string name="home_experimental_kernelsu_body">KernelSU Next is a non-official version that is always under active experimental development. It is provided as-is, with no guarantees of stability, performance, or reliability.</string>
<string name="home_experimental_kernelsu_body">KernelSU Next is a non-official version that is always under active experimental development. It\'s provided as-is, with no guarantees of stability, performance, or reliability.</string>
<string name="home_experimental_kernelsu_body_point_1"> • Use at your own risk: crashes, unexpected behavior, or system issues may occur.</string>
<string name="home_experimental_kernelsu_body_point_2"> • No warranty: the developers aren\'t responsible for any data loss, system damage, or other consequences resulting from its use.</string>
<string name="home_experimental_kernelsu_body_point_3"> • For testing purposes only: intended for users who understand the risks and are comfortable troubleshooting issues.</string>
@@ -140,6 +140,7 @@
<string name="profile_selinux_domain">Domain</string>
<string name="profile_selinux_rules">Rules</string>
<string name="module_update">Update</string>
<string name="module_update_available">Update</string>
<string name="module_updated">Updated</string>
<string name="module_downloading">Downloading module: %s</string>
<string name="module_start_downloading">Start downloading: %s</string>
@@ -150,7 +151,7 @@
<string name="restart_app">Restart</string>
<string name="settings_amoled_mode">AMOLED mode</string>
<string name="settings_amoled_mode_summary">Enable a pure black theme useful for AMOLED screens to reduce eye strain and save battery.</string>
<string name="restart_required">Restart Required</string>
<string name="restart_required">Restart required</string>
<string name="restart_app_message">The app needs to restart for this change to take effect.</string>
<string name="failed_to_update_sepolicy">Failed to update SELinux rules for: %s</string>
<string name="su_not_allowed">Granting superuser isn\'t allowed for: %s</string>
@@ -211,7 +212,8 @@
<string name="settings_disable_su">Disable su compatibility</string>
<string name="settings_disable_su_summary">Temporarily disable the ability of any app to gain root privileges via the su command (existing root processes won\'t be affected).</string>
<string name="settings_language">Language</string>
<string name="settings_legacyui">Use Legacy UI</string>
<string name="system_default">System default</string>
<string name="settings_legacyui">Use legacy UI</string>
<string name="settings_legacyui_summary">Switch to the previous user interface style.</string>
<string name="settings_banner">Enable banners</string>
<string name="settings_banner_summary">Show background banners for modules.</string>
@@ -220,4 +222,7 @@
<string name="use_webuix_eruda">Inject Eruda into WebUI X</string>
<string name="use_webuix_eruda_summary">Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on.</string>
<string name="customization">Customization</string>
<string name="developer">Developer</string>
<string name="sucompat_disabled">SUCOMPAT DISABLED</string>
<string name="zygisk_required">Zygisk required</string>
</resources>

View File

@@ -28,8 +28,8 @@ cmaker {
}
val androidMinSdkVersion = 26
val androidTargetSdkVersion = 35
val androidCompileSdkVersion = 35
val androidTargetSdkVersion = 36
val androidCompileSdkVersion = 36
val androidCompileNdkVersion = "28.1.13356709"
val androidSourceCompatibility = JavaVersion.VERSION_21
val androidTargetCompatibility = JavaVersion.VERSION_21

View File

@@ -1,9 +1,9 @@
[versions]
agp = "8.10.0"
agp = "8.10.1"
kotlin = "2.1.21"
ksp = "2.1.21-2.0.1"
compose-bom = "2025.05.01"
lifecycle = "2.9.0"
ksp = "2.1.21-2.0.2"
compose-bom = "2025.06.00"
lifecycle = "2.9.1"
navigation = "2.9.0"
activity-compose = "1.10.1"
kotlinx-coroutines = "1.10.2"
@@ -11,7 +11,7 @@ coil-compose = "2.7.0"
compose-destination = "2.2.0"
sheets-compose-dialogs = "1.3.0"
markdown = "4.6.2"
webkit = "1.13.0"
webkit = "1.14.0"
appiconloader-coil = "1.5.0"
parcelablelist = "2.0.1"
libsu = "6.0.0"
@@ -72,7 +72,7 @@ sheet-compose-dialogs-input = { group = "com.maxkeppeler.sheets-compose-dialogs"
markdown = { group = "io.noties.markwon", name = "core", version.ref = "markdown" }
lsposed-cxx = { module = "org.lsposed.libcxx:libcxx", version = "27.0.12077973" }
lsposed-cxx = { module = "org.lsposed.libcxx:libcxx", version = "28.1.13356709" }
mmrl-webui = { group = "com.github.MMRLApp.MMRL", name = "webui", version.ref = "mmrl" }
mmrl-platform = { group = "com.github.MMRLApp.MMRL", name = "platform", version.ref = "mmrl" }

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStorePath=wrapper/dists

View File

@@ -13,9 +13,9 @@ dependencies = [
[[package]]
name = "adler2"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "adler32"
@@ -81,9 +81,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.18"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -96,33 +96,33 @@ dependencies = [
[[package]]
name = "anstyle"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.8"
version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
dependencies = [
"anstyle",
"once_cell_polyfill",
@@ -184,9 +184,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.0"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "block-buffer"
@@ -199,9 +199,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.17.0"
version = "3.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
[[package]]
name = "byteorder"
@@ -217,18 +217,18 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"
version = "1.2.23"
version = "1.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "chrono"
@@ -246,9 +246,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.38"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
dependencies = [
"clap_builder",
"clap_derive",
@@ -256,9 +256,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.38"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
dependencies = [
"anstream",
"anstyle",
@@ -268,9 +268,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.32"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
dependencies = [
"heck",
"proc-macro2",
@@ -280,15 +280,15 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "colorchoice"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "const_format"
@@ -536,12 +536,12 @@ dependencies = [
[[package]]
name = "errno"
version = "0.3.11"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -573,9 +573,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flate2"
version = "1.1.1"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"libz-rs-sys",
@@ -594,9 +594,9 @@ dependencies = [
[[package]]
name = "getopts"
version = "0.2.21"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
dependencies = [
"unicode-width",
]
@@ -631,9 +631,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.2"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heck"
@@ -710,7 +710,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
"hashbrown 0.15.4",
]
[[package]]
@@ -807,9 +807,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.172"
version = "0.2.173"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb"
[[package]]
name = "libflate"
@@ -843,9 +843,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libz-rs-sys"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221"
dependencies = [
"zlib-rs",
]
@@ -891,15 +891,15 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.4"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "miniz_oxide"
version = "0.8.8"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
@@ -945,12 +945,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
version = "1.70.0"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2611b99ab098a31bdc8be48b4f1a285ca0ced28bd5b4f23e45efa8c63b09efa5"
dependencies = [
"once_cell",
]
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "pin-project-lite"
@@ -985,7 +982,7 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.9.1",
"chrono",
"flate2",
"hex",
@@ -999,7 +996,7 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.9.1",
"chrono",
"hex",
]
@@ -1088,17 +1085,17 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "rustix"
version = "0.38.34"
source = "git+https://github.com/KernelSU-Next/rustix.git?branch=main#4a53fbc7cb7a07cabe87125cc21dbc27db316259"
dependencies = [
"bitflags 2.9.0",
"errno 0.3.11",
"bitflags 2.9.1",
"errno 0.3.12",
"itoa",
"libc",
"linux-raw-sys 0.4.15",
@@ -1112,31 +1109,31 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.9.0",
"errno 0.3.11",
"bitflags 2.9.1",
"errno 0.3.12",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.5"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [
"bitflags 2.9.0",
"errno 0.3.11",
"bitflags 2.9.1",
"errno 0.3.12",
"libc",
"linux-raw-sys 0.9.4",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
name = "rustversion"
version = "1.0.20"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "ryu"
@@ -1240,9 +1237,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.101"
version = "2.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
dependencies = [
"proc-macro2",
"quote",
@@ -1258,8 +1255,8 @@ dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix 1.0.5",
"windows-sys 0.52.0",
"rustix 1.0.7",
"windows-sys 0.59.0",
]
[[package]]
@@ -1283,9 +1280,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]]
name = "tokio"
version = "1.45.0"
version = "1.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
dependencies = [
"backtrace",
"bytes",
@@ -1306,9 +1303,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
version = "0.1.14"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "unicode-xid"
@@ -1407,13 +1404,12 @@ dependencies = [
[[package]]
name = "which"
version = "7.0.3"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d"
dependencies = [
"either",
"env_home",
"rustix 1.0.5",
"rustix 1.0.7",
"winsafe",
]
@@ -1439,7 +1435,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -1485,9 +1481,9 @@ dependencies = [
[[package]]
name = "windows-link"
version = "0.1.1"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-result"
@@ -1601,7 +1597,7 @@ version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.9.1",
]
[[package]]
@@ -1662,9 +1658,9 @@ dependencies = [
[[package]]
name = "zlib-rs"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a"
[[package]]
name = "zopfli"

View File

@@ -38,7 +38,7 @@ rust-embed = { version = "8", features = [
"debug-embed",
"compression", # must clean build after updating binaries
] }
which = "7"
which = "8"
getopts = "0.2"
sha256 = "1"
sha1 = "0.10"

View File

@@ -167,6 +167,36 @@ fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
Ok(())
}
fn do_vendor_init_boot_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
let vendor_init_boot_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("cpio")
.arg(vendor_init_boot_cpio)
.arg(cmd)
.status()?;
ensure!(status.success(), "magiskboot cpio {} failed", cmd);
Ok(())
}
fn do_vendor_ramdisk_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("cpio")
.arg(vendor_ramdisk_cpio)
.arg(cmd)
.status()?;
ensure!(status.success(), "magiskboot cpio {} failed", cmd);
Ok(())
}
fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -179,6 +209,32 @@ fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.code() == Some(1))
}
fn is_magisk_patched_vendor_init_boot(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_init_boot_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(["cpio", vendor_init_boot_cpio.to_str().unwrap(), "test"])
.status()?;
// 0: stock, 1: magisk
Ok(status.code() == Some(1))
}
fn is_magisk_patched_vendor_ramdisk(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(["cpio", vendor_ramdisk_cpio.to_str().unwrap(), "test"])
.status()?;
// 0: stock, 1: magisk
Ok(status.code() == Some(1))
}
fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -190,6 +246,38 @@ fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.success())
}
fn is_kernelsu_patched_vendor_init_boot(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args([
"cpio",
vendor_ramdisk_cpio.to_str().unwrap(),
"exists kernelsu.ko",
])
.status()?;
Ok(status.success())
}
fn is_kernelsu_patched_vendor_ramdisk(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args([
"cpio",
vendor_ramdisk_cpio.to_str().unwrap(),
"exists kernelsu.ko",
])
.status()?;
Ok(status.success())
}
fn dd<P: AsRef<Path>, Q: AsRef<Path>>(ifile: P, ofile: Q) -> Result<()> {
let status = Command::new("dd")
.stdout(Stdio::null())
@@ -234,9 +322,22 @@ pub fn restore(
.status()?;
ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists();
let no_vendor_init_boot = !workdir
.join("vendor_ramdisk")
.join("init_boot.cpio")
.exists();
let no_vendor_ramdisk = !workdir
.join("vendor_ramdisk")
.join("ramdisk.cpio")
.exists();
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_init_boot =
is_kernelsu_patched_vendor_init_boot(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_ramdisk =
is_kernelsu_patched_vendor_ramdisk(&magiskboot, workdir)?;
ensure!(
is_kernelsu_patched,
is_kernelsu_patched || is_kernelsu_patched_vendor_init_boot || is_kernelsu_patched_vendor_ramdisk,
"boot image is not patched by KernelSU Next"
);
@@ -270,16 +371,44 @@ pub fn restore(
}
if new_boot.is_none() {
// remove kernelsu.ko
do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
if no_ramdisk {
if !no_vendor_init_boot {
// vendor init_boot restore
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
// if init.real exists, restore it
let status = do_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
let status =
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let vendor_init_boot = workdir.join("vendor_ramdisk").join("init_boot.cpio");
std::fs::remove_file(vendor_init_boot)?;
}
} else if !no_vendor_ramdisk {
// vendor ramdisk restore
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
let status =
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let vendor_ramdisk = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
std::fs::remove_file(vendor_ramdisk)?;
}
}
} else {
let ramdisk = workdir.join("ramdisk.cpio");
std::fs::remove_file(ramdisk)?;
// remove kernelsu.ko
do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
// if init.real exists, restore it
let status = do_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let ramdisk = workdir.join("ramdisk.cpio");
std::fs::remove_file(ramdisk)?;
}
}
println!("- Repacking boot image");
@@ -441,11 +570,6 @@ fn do_patch(
assets::copy_assets_to_file("ksuinit", init_file).context("copy ksuinit failed")?;
}
// magiskboot unpack boot.img
// magiskboot cpio ramdisk.cpio 'cp init init.real'
// magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init'
// magiskboot cpio ramdisk.cpio 'add 0755 <kmod> kernelsu.ko'
println!("- Unpacking boot image");
let status = Command::new(&magiskboot)
.current_dir(workdir)
@@ -457,28 +581,73 @@ fn do_patch(
ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists();
let no_vendor_init_boot = !workdir
.join("vendor_ramdisk")
.join("init_boot.cpio")
.exists();
let no_vendor_ramdisk = !workdir
.join("vendor_ramdisk")
.join("ramdisk.cpio")
.exists();
if no_ramdisk && no_vendor_init_boot && no_vendor_ramdisk {
bail!("No compatible ramdisk found.");
}
let is_magisk_patched = is_magisk_patched(&magiskboot, workdir)?;
let is_magisk_patched_vendor_init_boot =
is_magisk_patched_vendor_init_boot(&magiskboot, workdir)?;
let is_magisk_patched_vendor_ramdisk =
is_magisk_patched_vendor_ramdisk(&magiskboot, workdir)?;
ensure!(
no_ramdisk || !is_magisk_patched,
!is_magisk_patched || !is_magisk_patched_vendor_init_boot || !is_magisk_patched_vendor_ramdisk,
"Cannot work with Magisk patched image"
);
println!("- Adding KernelSU Next LKM");
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_init_boot =
is_kernelsu_patched_vendor_init_boot(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_ramdisk =
is_kernelsu_patched_vendor_ramdisk(&magiskboot, workdir)?;
let mut need_backup = false;
if !is_kernelsu_patched {
// kernelsu.ko is not exist, backup init if necessary
let status = do_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
if !is_kernelsu_patched || (no_ramdisk && !is_kernelsu_patched_vendor_init_boot) || (no_ramdisk && no_vendor_init_boot && !is_kernelsu_patched_vendor_ramdisk)
{
if no_ramdisk {
if !no_vendor_init_boot {
// vendor init_boot patching
let status = do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
} else if !no_vendor_ramdisk {
// vendor ramdisk patching
let status = do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
}
} else {
// kernelsu.ko is not exist, backup init if necessary
let status = do_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
need_backup = flash;
}
need_backup = flash;
}
do_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?;
if no_ramdisk {
if !no_vendor_init_boot {
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?;
} else if !no_vendor_ramdisk {
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "add 0750 init init")?;
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "add 0750 kernelsu.ko kernelsu.ko")?;
}
} else {
do_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?;
}
#[cfg(target_os = "android")]
if need_backup {
@@ -658,8 +827,12 @@ fn find_boot_image(
let init_boot_exist =
Path::new(&format!("/dev/block/by-name/init_boot{slot_suffix}")).exists();
let vendor_boot_exist =
Path::new(&format!("/dev/block/by-name/vendor_boot{slot_suffix}")).exists();
let boot_partition = if !is_replace_kernel && init_boot_exist && !skip_init {
format!("/dev/block/by-name/init_boot{slot_suffix}")
} else if !is_replace_kernel && vendor_boot_exist && !skip_init {
format!("/dev/block/by-name/vendor_boot{slot_suffix}")
} else {
format!("/dev/block/by-name/boot{slot_suffix}")
};

View File

@@ -13,9 +13,9 @@ dependencies = [
[[package]]
name = "adler2"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "adler32"
@@ -29,7 +29,7 @@ version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.1",
"once_cell",
"version_check",
"zerocopy",
@@ -81,9 +81,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.18"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -96,33 +96,33 @@ dependencies = [
[[package]]
name = "anstyle"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.8"
version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
dependencies = [
"anstyle",
"once_cell_polyfill",
@@ -168,7 +168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if 1.0.0",
"cfg-if 1.0.1",
"libc",
"miniz_oxide",
"object",
@@ -184,9 +184,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.0"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "block-buffer"
@@ -199,9 +199,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.17.0"
version = "3.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
[[package]]
name = "byteorder"
@@ -217,9 +217,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"
version = "1.2.23"
version = "1.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
dependencies = [
"shlex",
]
@@ -232,9 +232,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "chrono"
@@ -252,9 +252,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.38"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
dependencies = [
"clap_builder",
"clap_derive",
@@ -262,9 +262,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.38"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
dependencies = [
"anstream",
"anstyle",
@@ -274,9 +274,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.32"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
dependencies = [
"heck",
"proc-macro2",
@@ -286,15 +286,15 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "colorchoice"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "const_format"
@@ -361,7 +361,7 @@ version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.1",
]
[[package]]
@@ -495,7 +495,7 @@ version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.1",
]
[[package]]
@@ -542,12 +542,12 @@ dependencies = [
[[package]]
name = "errno"
version = "0.3.11"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -579,9 +579,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flate2"
version = "1.1.1"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"libz-rs-sys",
@@ -600,9 +600,9 @@ dependencies = [
[[package]]
name = "getopts"
version = "0.2.21"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
dependencies = [
"unicode-width",
]
@@ -613,7 +613,7 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.1",
"libc",
"r-efi",
"wasi",
@@ -637,9 +637,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.2"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heck"
@@ -729,7 +729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
"hashbrown 0.15.4",
]
[[package]]
@@ -828,9 +828,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.172"
version = "0.2.173"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb"
[[package]]
name = "libflate"
@@ -864,9 +864,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libz-rs-sys"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221"
dependencies = [
"zlib-rs",
]
@@ -921,9 +921,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.4"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "memmap"
@@ -937,9 +937,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.8.8"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
@@ -985,12 +985,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
version = "1.70.0"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2611b99ab098a31bdc8be48b4f1a285ca0ced28bd5b4f23e45efa8c63b09efa5"
dependencies = [
"once_cell",
]
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "pin-project-lite"
@@ -1025,7 +1022,7 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.9.1",
"chrono",
"flate2",
"hex",
@@ -1039,7 +1036,7 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.9.1",
"chrono",
"hex",
]
@@ -1128,17 +1125,17 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "rustix"
version = "0.38.34"
source = "git+https://github.com/KernelSU-Next/rustix.git?branch=main#4a53fbc7cb7a07cabe87125cc21dbc27db316259"
dependencies = [
"bitflags 2.9.0",
"errno 0.3.11",
"bitflags 2.9.1",
"errno 0.3.12",
"itoa",
"libc",
"linux-raw-sys 0.4.15",
@@ -1152,31 +1149,31 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.9.0",
"errno 0.3.11",
"bitflags 2.9.1",
"errno 0.3.12",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.5"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [
"bitflags 2.9.0",
"errno 0.3.11",
"bitflags 2.9.1",
"errno 0.3.12",
"libc",
"linux-raw-sys 0.9.4",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
name = "rustversion"
version = "1.0.20"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "ryu"
@@ -1231,7 +1228,7 @@ version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.1",
"cpufeatures",
"digest",
]
@@ -1242,7 +1239,7 @@ version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.1",
"cpufeatures",
"digest",
]
@@ -1280,9 +1277,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.101"
version = "2.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
dependencies = [
"proc-macro2",
"quote",
@@ -1298,8 +1295,8 @@ dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix 1.0.5",
"windows-sys 0.52.0",
"rustix 1.0.7",
"windows-sys 0.59.0",
]
[[package]]
@@ -1343,9 +1340,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]]
name = "tokio"
version = "1.45.0"
version = "1.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
dependencies = [
"backtrace",
"bytes",
@@ -1366,9 +1363,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
version = "0.1.14"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "unicode-xid"
@@ -1413,7 +1410,7 @@ version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.1",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
@@ -1467,13 +1464,12 @@ dependencies = [
[[package]]
name = "which"
version = "7.0.3"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d"
dependencies = [
"either",
"env_home",
"rustix 1.0.5",
"rustix 1.0.7",
"winsafe",
]
@@ -1499,7 +1495,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -1545,9 +1541,9 @@ dependencies = [
[[package]]
name = "windows-link"
version = "0.1.1"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-result"
@@ -1661,7 +1657,7 @@ version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.9.1",
]
[[package]]
@@ -1722,9 +1718,9 @@ dependencies = [
[[package]]
name = "zlib-rs"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a"
[[package]]
name = "zopfli"

View File

@@ -37,7 +37,7 @@ rust-embed = { version = "8", features = [
"debug-embed",
"compression", # must clean build after updating binaries
] }
which = "7"
which = "8"
getopts = "0.2"
sha256 = "1"
sha1 = "0.10"

View File

@@ -167,6 +167,36 @@ fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
Ok(())
}
fn do_vendor_init_boot_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
let vendor_init_boot_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("cpio")
.arg(vendor_init_boot_cpio)
.arg(cmd)
.status()?;
ensure!(status.success(), "magiskboot cpio {} failed", cmd);
Ok(())
}
fn do_vendor_ramdisk_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("cpio")
.arg(vendor_ramdisk_cpio)
.arg(cmd)
.status()?;
ensure!(status.success(), "magiskboot cpio {} failed", cmd);
Ok(())
}
fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -179,6 +209,32 @@ fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.code() == Some(1))
}
fn is_magisk_patched_vendor_init_boot(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_init_boot_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(["cpio", vendor_init_boot_cpio.to_str().unwrap(), "test"])
.status()?;
// 0: stock, 1: magisk
Ok(status.code() == Some(1))
}
fn is_magisk_patched_vendor_ramdisk(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(["cpio", vendor_ramdisk_cpio.to_str().unwrap(), "test"])
.status()?;
// 0: stock, 1: magisk
Ok(status.code() == Some(1))
}
fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -190,6 +246,38 @@ fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.success())
}
fn is_kernelsu_patched_vendor_init_boot(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args([
"cpio",
vendor_ramdisk_cpio.to_str().unwrap(),
"exists kernelsu.ko",
])
.status()?;
Ok(status.success())
}
fn is_kernelsu_patched_vendor_ramdisk(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args([
"cpio",
vendor_ramdisk_cpio.to_str().unwrap(),
"exists kernelsu.ko",
])
.status()?;
Ok(status.success())
}
fn dd<P: AsRef<Path>, Q: AsRef<Path>>(ifile: P, ofile: Q) -> Result<()> {
let status = Command::new("dd")
.stdout(Stdio::null())
@@ -234,9 +322,22 @@ pub fn restore(
.status()?;
ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists();
let no_vendor_init_boot = !workdir
.join("vendor_ramdisk")
.join("init_boot.cpio")
.exists();
let no_vendor_ramdisk = !workdir
.join("vendor_ramdisk")
.join("ramdisk.cpio")
.exists();
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_init_boot =
is_kernelsu_patched_vendor_init_boot(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_ramdisk =
is_kernelsu_patched_vendor_ramdisk(&magiskboot, workdir)?;
ensure!(
is_kernelsu_patched,
is_kernelsu_patched || is_kernelsu_patched_vendor_init_boot || is_kernelsu_patched_vendor_ramdisk,
"boot image is not patched by KernelSU Next"
);
@@ -270,16 +371,44 @@ pub fn restore(
}
if new_boot.is_none() {
// remove kernelsu.ko
do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
if no_ramdisk {
if !no_vendor_init_boot {
// vendor init_boot restore
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
// if init.real exists, restore it
let status = do_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
let status =
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let vendor_init_boot = workdir.join("vendor_ramdisk").join("init_boot.cpio");
std::fs::remove_file(vendor_init_boot)?;
}
} else if !no_vendor_ramdisk {
// vendor ramdisk restore
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
let status =
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let vendor_ramdisk = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
std::fs::remove_file(vendor_ramdisk)?;
}
}
} else {
let ramdisk = workdir.join("ramdisk.cpio");
std::fs::remove_file(ramdisk)?;
// remove kernelsu.ko
do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
// if init.real exists, restore it
let status = do_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let ramdisk = workdir.join("ramdisk.cpio");
std::fs::remove_file(ramdisk)?;
}
}
println!("- Repacking boot image");
@@ -301,7 +430,7 @@ pub fn restore(
let output_dir = std::env::current_dir()?;
let now = chrono::Utc::now();
let output_image = output_dir.join(format!(
"kernelsu_restore_{}.img",
"kernelsu_next_restore_{}.img",
now.format("%Y%m%d_%H%M%S")
));
@@ -441,11 +570,6 @@ fn do_patch(
assets::copy_assets_to_file("ksuinit", init_file).context("copy ksuinit failed")?;
}
// magiskboot unpack boot.img
// magiskboot cpio ramdisk.cpio 'cp init init.real'
// magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init'
// magiskboot cpio ramdisk.cpio 'add 0755 <kmod> kernelsu.ko'
println!("- Unpacking boot image");
let status = Command::new(&magiskboot)
.current_dir(workdir)
@@ -457,28 +581,73 @@ fn do_patch(
ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists();
let no_vendor_init_boot = !workdir
.join("vendor_ramdisk")
.join("init_boot.cpio")
.exists();
let no_vendor_ramdisk = !workdir
.join("vendor_ramdisk")
.join("ramdisk.cpio")
.exists();
if no_ramdisk && no_vendor_init_boot && no_vendor_ramdisk {
bail!("No compatible ramdisk found.");
}
let is_magisk_patched = is_magisk_patched(&magiskboot, workdir)?;
let is_magisk_patched_vendor_init_boot =
is_magisk_patched_vendor_init_boot(&magiskboot, workdir)?;
let is_magisk_patched_vendor_ramdisk =
is_magisk_patched_vendor_ramdisk(&magiskboot, workdir)?;
ensure!(
no_ramdisk || !is_magisk_patched,
!is_magisk_patched || !is_magisk_patched_vendor_init_boot || !is_magisk_patched_vendor_ramdisk,
"Cannot work with Magisk patched image"
);
println!("- Adding KernelSU Next LKM");
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_init_boot =
is_kernelsu_patched_vendor_init_boot(&magiskboot, workdir)?;
let is_kernelsu_patched_vendor_ramdisk =
is_kernelsu_patched_vendor_ramdisk(&magiskboot, workdir)?;
let mut need_backup = false;
if !is_kernelsu_patched {
// kernelsu.ko is not exist, backup init if necessary
let status = do_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
if !is_kernelsu_patched || (no_ramdisk && !is_kernelsu_patched_vendor_init_boot) || (no_ramdisk && no_vendor_init_boot && !is_kernelsu_patched_vendor_ramdisk)
{
if no_ramdisk {
if !no_vendor_init_boot {
// vendor init_boot patching
let status = do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
} else if !no_vendor_ramdisk {
// vendor ramdisk patching
let status = do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
}
} else {
// kernelsu.ko is not exist, backup init if necessary
let status = do_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
need_backup = flash;
}
need_backup = flash;
}
do_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?;
if no_ramdisk {
if !no_vendor_init_boot {
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?;
} else if !no_vendor_ramdisk {
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "add 0750 init init")?;
do_vendor_ramdisk_cpio_cmd(&magiskboot, workdir, "add 0750 kernelsu.ko kernelsu.ko")?;
}
} else {
do_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?;
}
#[cfg(target_os = "android")]
if need_backup {
@@ -658,8 +827,12 @@ fn find_boot_image(
let init_boot_exist =
Path::new(&format!("/dev/block/by-name/init_boot{slot_suffix}")).exists();
let vendor_boot_exist =
Path::new(&format!("/dev/block/by-name/vendor_boot{slot_suffix}")).exists();
let boot_partition = if !is_replace_kernel && init_boot_exist && !skip_init {
format!("/dev/block/by-name/init_boot{slot_suffix}")
} else if !is_replace_kernel && vendor_boot_exist && !skip_init {
format!("/dev/block/by-name/vendor_boot{slot_suffix}")
} else {
format!("/dev/block/by-name/boot{slot_suffix}")
};

View File

@@ -119,50 +119,50 @@ int main(int argc, char *argv[]) {
ptr_buf += str_len;
}
if (enabled_features & (1 << 5)) {
str_len = strlen("CONFIG_KSU_SUSFS_SUS_OVERLAYFS\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SUS_OVERLAYFS\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 6)) {
str_len = strlen("CONFIG_KSU_SUSFS_TRY_UMOUNT\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_TRY_UMOUNT\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 7)) {
if (enabled_features & (1 << 6)) {
str_len = strlen("CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 8)) {
if (enabled_features & (1 << 7)) {
str_len = strlen("CONFIG_KSU_SUSFS_SPOOF_UNAME\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SPOOF_UNAME\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 9)) {
if (enabled_features & (1 << 8)) {
str_len = strlen("CONFIG_KSU_SUSFS_ENABLE_LOG\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_ENABLE_LOG\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 10)) {
if (enabled_features & (1 << 9)) {
str_len = strlen("CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 11)) {
if (enabled_features & (1 << 10)) {
str_len = strlen("CONFIG_KSU_SUSFS_SPOOF_BOOTCONFIG\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SPOOF_BOOTCONFIG\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 12)) {
if (enabled_features & (1 << 11)) {
str_len = strlen("CONFIG_KSU_SUSFS_OPEN_REDIRECT\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_OPEN_REDIRECT\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 13)) {
if (enabled_features & (1 << 12)) {
str_len = strlen("CONFIG_KSU_SUSFS_SUS_SU\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SUS_SU\n", str_len);
ptr_buf += str_len;
}
if (enabled_features & (1 << 13)) {
str_len = strlen("CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT\n");
strncpy(ptr_buf, "CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT\n", str_len);
ptr_buf += str_len;
}
printf("%s", enabled_features_buf);
free(enabled_features_buf);
} else {