Compare commits

...

106 Commits

Author SHA1 Message Date
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
Rifat Azad
10f7d5cf50 Revert "manager: keep mount system preference persistent"
This reverts commit 609926bff1.
2025-06-10 02:31:14 +06:00
rifsxd
0c883ddfd6 manager: let module banner be set locally from module dir
ex: banner=banner.png , banner=example.webp banner=temp/hello.jpg
if banner string value starts with http, https then it will try to fetch from online.

Co-authored-by: fatalcoder524 <11532648+fatalcoder524@users.noreply.github.com>
2025-06-06 04:09:16 +06:00
Paul
3921175e4c kernel: core_hook: intercept devpts via security_inode_permission LSM (#480)
`ksu handles devpts with selinux lsm hook` - aviraxp

- no, not yet, but yes we can, thats a good idea.

This change tries to do that, so instead of hooking pts_unix98_lookup or
devpts_get_priv, we just watch security_inode_permission, if its devpts,
pass it along to the original handler.

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-05 06:20:53 +06:00
5ec1cff
84fdcf8bf5 throne_tracker: avoid cross fs access 2025-06-03 03:30:54 +06:00
rifsxd
886cfd5a33 manager: adjusted module banner fade opacity 2025-06-03 03:28:42 +06:00
rifsxd
aea384bdd4 manager: do dynamic fade for banner based on monet when available 2025-06-03 01:49:57 +06:00
rifsxd
84695cea71 manager: do white fade for banner when on light mode 2025-06-03 00:58:58 +06:00
rifsxd
f91afe6c46 manager: add module background banners"
module devs can add banners for their modules through module.prop config

Example:

banner=https://something.com/banner.png
2025-06-03 00:34:37 +06:00
rifsxd
3f7e731df6 manager: fix update tag attached to wrong module after using sort options (fix #473) 2025-06-02 15:34:30 +06:00
rifsxd
582662dce9 manager: fix back gestures conflicting with LKM warning window (fix #474) 2025-06-02 15:12:59 +06:00
rifsxd
f3b49723e8 manager: add sorting by size for module list 2025-06-01 21:03:04 +06:00
backslashxx
c4deee1e49 kernel: ksud, throne_tracker: small changes for UL
Safe Ultra-Legacy changes that don't deserve their own commit

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.

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.
ref: openwrt/packages #26453

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-01 20:09:20 +06:00
Yaroslav Zviezda
6a6fc07cd4 kernel: throne_tracker: move throne_tracker to kthread
Runs throne_tracker() in kthread instead of blocking the caller.
Prevents full lockup during installation and removing the manager.

This also looks for manager UID in /data/system/packages.list, not
/data/system/packages.list.tmp

Nice additional side effect is a faster booting.

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-Authored-By: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-06-01 20:03:38 +06:00
rifsxd
d8cb7ef772 manager: fix module sorting state when module list is null initially before modules are fetched (this should fix #470) 2025-06-01 19:47:43 +06:00
rifsxd
dddf2f06a0 manager: show reboot button when flashing LKM directly and inactive slot 2025-06-01 15:46:25 +06:00
rifsxd
e7e935aeb2 manager: added module size label 2025-06-01 15:37:13 +06:00
rifsxd
cb146200aa manager: output full logs of actions and flash modules when developer option is enabled 2025-06-01 04:05:35 +06:00
rifsxd
609926bff1 manager: keep mount system preference persistent 2025-06-01 03:37:10 +06:00
rifsxd
8803058521 manager: added amoled theme for non material u devices 2025-06-01 02:33:02 +06:00
rifsxd
c74805b12b manager: autoexpand infocard when dev option is enabled 2025-06-01 01:43:08 +06:00
rifsxd
43870237fc manager: removed unused imports from backuprestore.kt 2025-06-01 01:17:44 +06:00
rifsxd
ca24085b5b manager: add a separate customization screen in settings 2025-06-01 01:17:35 +06:00
rifsxd
93191c2b8b manager: add legacy ui toggle 2025-06-01 00:20:23 +06:00
rifsxd
ebc3ded2b2 manager: removed module config to override webui engine 2025-05-30 04:18:02 +06:00
rifsxd
d9d1c874ab manager: improved module update detection and pre-load applist and modulelist 2025-05-30 02:09:13 +06:00
rifsxd
08477fc361 manager: improved module update status label 2025-05-29 20:55:11 +06:00
rifsxd
11836b876f manager: change home screen power menu icon to a proper power menu icon 2025-05-29 17:24:20 +06:00
rifsxd
bf20965c46 manager: make the module card neat and clean with less clutter and add useful indicators 2025-05-29 16:14:15 +06:00
rifsxd
22a48e52eb manager: rearrange and refactor the Module Card UI 2025-05-28 21:50:17 +06:00
rifsxd
15b703b5f2 manager: show webui and action label when a module has it 2025-05-28 20:42:57 +06:00
rifsxd
18f0eb8a36 manager: better spacing between app package name and label item in superuser 2025-05-28 18:12:23 +06:00
rifsxd
32cdcc6fbe manager: improve layout and look of module cards 2025-05-28 17:57:46 +06:00
rifsxd
437c4b9bc5 manager: improved AMOLED mode 2025-05-28 16:11:00 +06:00
rifsxd
0a42dbf5ba manager: add amoled mode 2025-05-28 04:21:38 +06:00
igor
ea4f319898 Update strings.xml (#444) 2025-05-28 01:14:02 +06:00
Rifat Azad
7b6b944106 docs: updated architecture support 2025-05-28 01:13:54 +06:00
rifsxd
59c966771e manager: show modules update count on status card only if any update is vailable 2025-05-27 03:24:32 +06:00
rifsxd
a83c20b667 manager: removed the logic for if overlayfs is not found then show warning in module screen
since magic_mount is the default mount system and if overlayfs is not available we cant swtich to use overlayfs anyways
2025-05-27 03:00:04 +06:00
rifsxd
d5c4f85d73 manager: move the wx platform init to the Application class so it starts as soon as the app process launches 2025-05-27 02:05:58 +06:00
rifsxd
36f683a299 manager: fix module list empty until refreshed manually 2025-05-27 01:43:30 +06:00
Rifat Azad
652e9719ed docs: removed LKM deprecation information 2025-05-26 13:31:46 +06:00
Der_Googler
011b658422 manager: Improvements (#443)
* manager: bump mmrl

* manager: use ktx ext Str.toUri

* manager: add "webui-engine" from config.json

This allows the developer to override the user preference of the selected WebUI engine.

Supported engines are:

- `wx` for WebUI X
- `ksu` for the KernelSU WebUI

All not named strings will default to `wx`

R.string.use_webuix_summary needs proper translations

* manager: add support for multilingual module meta
2025-05-26 03:03:31 +06:00
rifsxd
5fa1050e1b src: bring back LKM patching 2025-05-26 03:03:18 +06:00
Rifat Azad
39617497ca manager: change webui TaskDescription title 2025-05-25 10:49:56 +06:00
rifsxd
44ad960da7 src: add x86_64 support 2025-05-24 20:33:38 +06:00
96 changed files with 3150 additions and 1337 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

38
.github/workflows/build-kernel-wsa.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Build Kernel - WSA
on:
push:
branches: ["next"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- ".github/workflows/wsa-kernel.yml"
- "kernel/**"
pull_request:
branches: ["next"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- ".github/workflows/wsa-kernel.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
strategy:
matrix:
arch: [x86_64, arm64]
version: ["5.15.94.2", "5.15.104.1", "5.15.104.2", "5.15.104.3", "5.15.104.4"]
uses: ./.github/workflows/wsa-kernel.yml
with:
arch: ${{ matrix.arch }}
version: ${{ matrix.version }}
check_build:
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
uses: ./.github/workflows/wsa-kernel.yml
strategy:
matrix:
arch: [x86_64, arm64]
with:
arch: ${{ matrix.arch }}
version: "5.15.104.4"

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

@@ -19,12 +19,12 @@ on:
workflow_dispatch:
jobs:
# build-lkm:
# uses: ./.github/workflows/build-lkm.yml
# secrets: inherit
build-lkm:
uses: ./.github/workflows/build-lkm.yml
secrets: inherit
build-susfsd:
# needs: build-lkm
needs: build-lkm
strategy:
matrix:
include:
@@ -42,6 +42,8 @@ jobs:
os: ubuntu-latest
- target: armv7-linux-androideabi
os: ubuntu-latest
- target: x86_64-linux-android
os: ubuntu-latest
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
@@ -104,6 +106,10 @@ jobs:
mkdir -p app/src/main/jniLibs/armeabi-v7a
cp -f ../armeabi-v7a/susfsd ../manager/app/src/main/jniLibs/armeabi-v7a/libsusfsd.so
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../x86_64/susfsd ../manager/app/src/main/jniLibs/x86_64/libsusfsd.so
- name: Download arm64 ksud_overlayfs
uses: actions/download-artifact@v4
with:
@@ -116,12 +122,26 @@ jobs:
name: ksud_overlayfs-armv7-linux-androideabi
path: ksud_overlayfs
- name: Download x86_64 ksud_overlayfs
uses: actions/download-artifact@v4
with:
name: ksud_overlayfs-x86_64-linux-android
path: ksud_overlayfs
- name: Copy ksud_overlayfs to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
mkdir -p app/src/main/jniLibs/armeabi-v7a
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../ksud_overlayfs/aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud_overlayfs.so
cp -f ../ksud_overlayfs/armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud_overlayfs.so
cp -f ../ksud_overlayfs/x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud_overlayfs.so
- name: Download arm64 ksud_magic
uses: actions/download-artifact@v4
with:
@@ -133,13 +153,27 @@ jobs:
with:
name: ksud_magic-armv7-linux-androideabi
path: ksud_magic
- name: Download x86_64 ksud_magic
uses: actions/download-artifact@v4
with:
name: ksud_magic-x86_64-linux-android
path: ksud_magic
- name: Copy ksud_magic to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
mkdir -p app/src/main/jniLibs/armeabi-v7a
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../ksud_magic/aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud_magic.so
cp -f ../ksud_magic/armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud_magic.so
cp -f ../ksud_magic/x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud_magic.so
- name: Build with Gradle
run: |
{

View File

@@ -21,12 +21,12 @@ on:
- cron: "0 12 * * *" # 6 PM UTC+6 | 12 PM UTC
jobs:
# build-lkm:
# uses: ./.github/workflows/build-lkm.yml
# secrets: inherit
build-lkm:
uses: ./.github/workflows/build-lkm.yml
secrets: inherit
build-susfsd:
# needs: build-lkm
needs: build-lkm
strategy:
matrix:
include:
@@ -44,6 +44,8 @@ jobs:
os: ubuntu-latest
- target: armv7-linux-androideabi
os: ubuntu-latest
- target: x86_64-linux-android
os: ubuntu-latest
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
@@ -111,6 +113,10 @@ jobs:
mkdir -p app/src/main/jniLibs/armeabi-v7a
cp -f ../armeabi-v7a/susfsd ../manager/app/src/main/jniLibs/armeabi-v7a/libsusfsd.so
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../x86_64/susfsd ../manager/app/src/main/jniLibs/x86_64/libsusfsd.so
- name: Download arm64 ksud_overlayfs
uses: actions/download-artifact@v4
with:
@@ -123,12 +129,20 @@ jobs:
name: ksud_overlayfs-armv7-linux-androideabi
path: ksud_overlayfs
- name: Download x86_64 ksud_overlayfs
uses: actions/download-artifact@v4
with:
name: ksud_overlayfs-x86_64-linux-android
path: ksud_overlayfs
- name: Copy ksud_overlayfs to app jniLibs
run: |
cp -f ../ksud_overlayfs/aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud_overlayfs.so
cp -f ../ksud_overlayfs/armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud_overlayfs.so
cp -f ../ksud_overlayfs/x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud_overlayfs.so
- name: Download arm64 ksud_magic
uses: actions/download-artifact@v4
with:
@@ -140,6 +154,12 @@ jobs:
with:
name: ksud_magic-armv7-linux-androideabi
path: ksud_magic
- name: Download x86_64 ksud_magic
uses: actions/download-artifact@v4
with:
name: ksud_magic-x86_64-linux-android
path: ksud_magic
- name: Copy ksud_magic to app jniLibs
run: |
@@ -147,6 +167,8 @@ jobs:
cp -f ../ksud_magic/armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud_magic.so
cp -f ../ksud_magic/x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud_magic.so
- name: Build with Gradle
run: |
{

View File

@@ -19,12 +19,12 @@ on:
workflow_dispatch:
jobs:
# build-lkm:
# uses: ./.github/workflows/build-lkm.yml
# secrets: inherit // DISBAND LKM MODE
build-lkm:
uses: ./.github/workflows/build-lkm.yml
secrets: inherit
build-susfsd:
# needs: build-lkm
needs: build-lkm
strategy:
matrix:
include:
@@ -42,6 +42,8 @@ jobs:
os: ubuntu-latest
- target: armv7-linux-androideabi
os: ubuntu-latest
- target: x86_64-linux-android
os: ubuntu-latest
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
@@ -104,6 +106,10 @@ jobs:
mkdir -p app/src/main/jniLibs/armeabi-v7a
cp -f ../armeabi-v7a/susfsd ../manager/app/src/main/jniLibs/armeabi-v7a/libsusfsd.so
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../x86_64/susfsd ../manager/app/src/main/jniLibs/x86_64/libsusfsd.so
- name: Download arm64 ksud_overlayfs
uses: actions/download-artifact@v4
with:
@@ -116,12 +122,20 @@ jobs:
name: ksud_overlayfs-armv7-linux-androideabi
path: ksud_overlayfs
- name: Download x86_64 ksud_overlayfs
uses: actions/download-artifact@v4
with:
name: ksud_overlayfs-x86_64-linux-android
path: ksud_overlayfs
- name: Copy ksud_overlayfs to app jniLibs
run: |
cp -f ../ksud_overlayfs/aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud_overlayfs.so
cp -f ../ksud_overlayfs/armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud_overlayfs.so
cp -f ../ksud_overlayfs/x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud_overlayfs.so
- name: Download arm64 ksud_magic
uses: actions/download-artifact@v4
with:
@@ -133,6 +147,12 @@ jobs:
with:
name: ksud_magic-armv7-linux-androideabi
path: ksud_magic
- name: Download x86_64 ksud_magic
uses: actions/download-artifact@v4
with:
name: ksud_magic-x86_64-linux-android
path: ksud_magic
- name: Copy ksud_magic to app jniLibs
run: |
@@ -140,6 +160,8 @@ jobs:
cp -f ../ksud_magic/armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud_magic.so
cp -f ../ksud_magic/x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud_magic.so
- name: Build with Gradle
run: |
{

View File

@@ -45,4 +45,10 @@ jobs:
- name: Run Clippy
run: |
cross clippy --manifest-path userspace/ksud_magic/Cargo.toml --target aarch64-linux-android --release
cross clippy --manifest-path userspace/ksud_overlayfs/Cargo.toml --target aarch64-linux-android --release
cross clippy --manifest-path userspace/ksud_overlayfs/Cargo.toml --target aarch64-linux-android --release
cross clippy --manifest-path userspace/ksud_magic/Cargo.toml --target armv7-linux-androideabi --release
cross clippy --manifest-path userspace/ksud_overlayfs/Cargo.toml --target armv7-linux-androideabi --release
cross clippy --manifest-path userspace/ksud_magic/Cargo.toml --target x86_64-linux-android --release
cross clippy --manifest-path userspace/ksud_overlayfs/Cargo.toml --target x86_64-linux-android --release

View File

@@ -9,10 +9,10 @@ on:
required: false
type: string
default: ubuntu-latest
# pack_lkm:
# required: false
# type: boolean
# default: true
pack_lkm:
required: false
type: boolean
default: true
use_cache:
required: false
type: boolean
@@ -29,11 +29,11 @@ jobs:
- name: Download Artifacts
uses: actions/download-artifact@v4
# - name: Prepare LKM Files
# if: ${{ inputs.pack_lkm }}
# run: |
# cp android*-lkm/*_kernelsu.ko ./userspace/ksud_overlayfs/bin/aarch64/
# cp android*-lkm/*_kernelsu.ko ./userspace/ksud_magic/bin/aarch64/ // DISBAND LKM MODE
- name: Prepare LKM Files
if: ${{ inputs.pack_lkm }}
run: |
cp android*-lkm/*_kernelsu.ko ./userspace/ksud_overlayfs/bin/aarch64/
cp android*-lkm/*_kernelsu.ko ./userspace/ksud_magic/bin/aarch64/
- name: Import susfsd Libraries
run: |
@@ -41,10 +41,13 @@ jobs:
cp susfsd-linux-android/arm64-v8a/susfsd ./userspace/ksud_magic/bin/aarch64/
cp susfsd-linux-android/armeabi-v7a/susfsd ./userspace/ksud_overlayfs/bin/arm/
cp susfsd-linux-android/armeabi-v7a/susfsd ./userspace/ksud_magic/bin/arm/
cp susfsd-linux-android/x86_64/susfsd ./userspace/ksud_overlayfs/bin/x86_64/
cp susfsd-linux-android/x86_64/susfsd ./userspace/ksud_magic/bin/x86_64/
- name: Setup Rust
run: |
rustup update stable
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
- name: Cache ksud_overlayfs

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
@@ -28,6 +34,8 @@ jobs:
- build-a13-kernel
- build-a14-kernel
- build-a15-kernel
- build-wsa-kernel
- build-arcvm-kernel
runs-on: ubuntu-latest
steps:
- name: Download artifacts
@@ -41,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
@@ -52,6 +78,8 @@ jobs:
android*-lkm/*_kernelsu.ko
AnyKernel3-*.zip
boot-images-*/Image-*/*.img.gz
ksud_magic-*/ksud_magic-*
ksud_overlayfs-*/ksud_overlayfs-*
susfsd-*/susfsd-*
kernel-WSA*.zip
kernel-ARCVM*.zip
ksud_magic*.zip
ksud_overlayfs*.zip
susfsd*.zip

106
.github/workflows/wsa-kernel.yml vendored Normal file
View File

@@ -0,0 +1,106 @@
name: Build Kernel - WSA
on:
workflow_call:
inputs:
arch:
required: true
type: string
description: >
Build arch: x86_64 / arm64
version:
required: true
type: string
description: >
Build version
jobs:
build:
name: Build WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }}
runs-on: ubuntu-22.04
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_HARDLINK: "true"
steps:
- name: Install Build Tools
uses: awalsh128/cache-apt-pkgs-action@v1
with:
packages: bc bison build-essential flex libelf-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu gzip ccache
version: 1.0
- name: Cache LLVM
id: cache-llvm
uses: actions/cache@v4
with:
path: ./llvm
key: llvm-12.0.1
- name: Setup LLVM
uses: KyleMayes/install-llvm-action@v1
with:
version: "12.0.1"
force-version: true
ubuntu-version: "16.04"
cached: ${{ steps.cache-llvm.outputs.cache-hit }}
- name: Checkout KernelSU-Next
uses: actions/checkout@v4
with:
path: KernelSU-Next
fetch-depth: 0
- name: Setup kernel source
uses: actions/checkout@v4
with:
repository: microsoft/WSA-Linux-Kernel
ref: android-lts/latte-2/${{ inputs.version }}
path: WSA-Linux-Kernel
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }}
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
max-size: 2G
- name: Setup KernelSU-Next
working-directory: WSA-Linux-Kernel
run: |
echo "[+] KernelSU-Next setup"
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-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
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-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
- name: Build Kernel
working-directory: WSA-Linux-Kernel
run: |
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
fi
declare -A ARCH_MAP=(["x86_64"]="x64" ["arm64"]="arm64")
cp configs/wsa/config-wsa-${ARCH_MAP[${{ inputs.arch }}]} .config
make olddefconfig
declare -A FILE_NAME=(["x86_64"]="bzImage" ["arm64"]="Image")
make -j`nproc` LLVM=1 ARCH=${{ inputs.arch }} $(if [ "${{ inputs.arch }}" == "arm64" ]; then echo CROSS_COMPILE=aarch64-linux-gnu; fi) ${FILE_NAME[${{ inputs.arch }}]} CCACHE="/usr/bin/ccache"
declare -A ARCH_MAP_FILE=(["x86_64"]="x86" ["arm64"]="arm64")
echo "file_path=WSA-Linux-Kernel/arch/${ARCH_MAP_FILE[${{ inputs.arch }}]}/boot/${FILE_NAME[${{ inputs.arch }}]}" >> $GITHUB_ENV
- name: Upload kernel-${{ inputs.arch }}-${{ inputs.version }}
uses: actions/upload-artifact@v4
with:
name: kernel-WSA-${{ inputs.arch }}-${{ inputs.version }}
path: "${{ env.file_path }}"

View File

@@ -11,9 +11,6 @@ A kernel-based root solution for Android devices.
[![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)
> [!IMPORTANT]
> Support for installing KernelSU Next in LKM mode through manager was disabled, you can still update it by manually repacking `init_boot`.
## Features
1. Kernel-based `su` and root access management.
@@ -27,11 +24,11 @@ KernelSU Next officially supports most Android kernels starting from 4.4 up to 6
- 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` architecture is supported.
Currently, only the `arm64-v8a`, `armeabi-v7a` & `x86_64` architectures are supported.
## Usage
- [Installation instruction](https://ksunext.org/pages/installation.html)
- [Installation instruction](https://kernelsu-next.github.io/webpage/pages/installation.html)
## Security

View File

@@ -24,7 +24,7 @@ KernelSU Next официално поддържа повечето Android яд
- Ядра GKI 1.0 (4.19 - 5.4) изискват прекомпилиране с драйвера на KernelSU
- Остарели ядра (<4.14) също изискват прекомпилиране (3.18+ е експериментална поддръжка)
В момента се поддържа само архитектурата `arm64-v8a`.
В момента се поддържа само архитектурата `arm64-v8a`, `armeabi-v7a` & `x86_64`.
## Инсталация

View File

@@ -24,7 +24,7 @@ KernelSU Next 支持从 4.4 到 6.6 的大多数安卓内核
- GKI 1.04.19 - 5.4)内核需要使用 KernelSU 内核驱动重新编译
- EOL (<4.14) 内核也需要使用 KernelSU 内核驱动重新编译 (3.18+ 的版本处于试验阶段,可能需要移植一些功能)
目前只支持 `arm64-v8a` 架构
目前只支持 `arm64-v8a`, `armeabi-v7a` & `x86_64` 架构
## 用法

View File

@@ -24,7 +24,7 @@ KernelSU Next prend officiellement en charge la plupart des noyaux Android de la
- Les noyaux GKI 1.0 (4.19 - 5.4) doivent être reconstruits avec le pilote KernelSU.
- Les noyaux EOL (<4.14) doivent également être reconstruits avec le pilote KernelSU (3.18+ est expérimental et peut nécessiter des rétroportages fonctionnels).
Actuellement, seul `arm64-v8a` est pris en charge.
Actuellement, seul `arm64-v8a`, `armeabi-v7a` & `x86_64` est pris en charge.
## Utilisation

View File

@@ -24,7 +24,7 @@ KernelSU Next secara resmi mendukung sebagian besar kernel Android mulai dari 4.
- Kernel GKI 1.0 (4.19 - 5.4) perlu dibangun ulang dengan driver KernelSU.
- Kernel EOL (<4.14) juga perlu dibangun ulang dengan driver KernelSU (3.18+ bersifat eksperimental dan mungkin memerlukan beberapa backport fungsi).
Saat ini, hanya `arm64-v8a` yang didukung.
Saat ini, hanya `arm64-v8a`, `armeabi-v7a` & `x86_64` yang didukung.
## Penggunaan

View File

@@ -24,7 +24,7 @@ KernelSU Next supporta ufficialmente la maggior parte dei kernel Android dalla v
- I kernel GKI 1.0 (4.19 - 5.4) devono essere ricostruiti con il driver KernelSU.
- Anche i kernel EOL (<4.14) devono essere ricostruiti con il driver KernelSU (la versione 3.18+ è sperimentale e potrebbe richiedere alcuni backport di funzioni).
Attualmente è supportata solo l'architettura `arm64-v8a`.
Attualmente è supportata solo l'architettura `arm64-v8a`, `armeabi-v7a` & `x86_64`.
## Utilizzo

View File

@@ -24,7 +24,7 @@ KernelSU Next は 4.4 から 6.6 までのほとんどの Android カーネル
- GKI 1.0 (4.19 - 5.4) のカーネルは、KernelSU ドライバを使用してビルドする必要があります。
- EOL (4.14 未満) のカーネルも KernelSU ドライバを使用して再ビルドする必要があります (3.18 以降は実験中の段階であり、一部の関数のバックポートが必要になる場合があります)。
現在 `arm64-v8a` アーキテクチャのみをサポートしています。
現在 `arm64-v8a`, `armeabi-v7a` & `x86_64` アーキテクチャのみをサポートしています。
## 使い方

View File

@@ -24,7 +24,7 @@ KernelSU Next는 공식적으로 대부분의 4.4부터 6.6의 안드로이드
- GKI 1.0 (4.19 - 5.4) 커널은 KernelSU 드라이버로 다시 빌드해야 합니다.
- EOL (<4.14) 커널도 역시 KernelSU 드라이버로 다시 빌드해야 합니다.(3.18+는 실험적이며 일부 함수의 이식이 필요할 수 있습니다.).
현재는, `arm64-v8a`만 지원됩니다.
현재는, `arm64-v8a`, `armeabi-v7a` & `x86_64` 만 지원됩니다.
## 사용 방법

View File

@@ -24,7 +24,7 @@ KernelSU Next oficjalnie obsługuje większość jąder Androida od wersji 4.4 d
- Jądra GKI 1.0 (4.19 - 5.4) muszą zostać zrekompilowane z dodatkiem sterownika KernelSU.
- Jądra EOL (<4.14) również muszą zostać zrekompilowane z dodatkiem sterownika KernelSU (obsługa 3.18+ jest eksperymentalna i może wymagać backportu pewnych funkcji).
Obecnie obsługiwana jest tylko architektura `arm64-v8a`.
Obecnie obsługiwana jest tylko architektura `arm64-v8a`, `armeabi-v7a` & `x86_64`
## Użycie

View File

@@ -11,9 +11,6 @@ Uma solução root baseada em kernel para dispositivos Android.
[![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)
> [!IMPORTANT]
> O suporte para instalação do KernelSU Next no modo LKM através do gerenciador foi desativado. Você ainda pode atualizá-lo manualmente reempacotando `init_boot`.
## Características
1. `su` e gerenciamento de acesso root baseado em kernel.
@@ -27,7 +24,7 @@ KernelSU Next suporta oficialmente a maioria dos kernels Android a partir de 4.4
- 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` é compatível.
Atualmente, apenas as arquiteturas `arm64-v8a`, `armeabi-v7a` & `x86_64` são compatíveis.
## Uso

View File

@@ -24,7 +24,7 @@ KernelSU Next работает с большинством ядер Android (4.4
- GKI 1.0 (4.19 - 5.4) требуют пересборки с драйвером KernelSU.
- EOL (<4.14) также требуют пересборки с драйвером KernelSU (версии 3.18+ экспериментальные и могут потребовать некоторые функции бэкпортов).
Сейчас поддерживается только `arm64-v8a`.
Сейчас поддерживается только `arm64-v8a`, `armeabi-v7a` & `x86_64`.
## Использование

View File

@@ -24,7 +24,7 @@ KernelSU Next รองรับแบบเป็นทางการตั้
- GKI 1.0 (4.19 - 5.4) เคอร์เนลจะต้องรีบิ้วร่วมกับไดร์เวอร์ของ KernelSU
- EOL (<4.14) เคอร์เนลก็ต้องรีบิ้วร่วมกับไดร์เวอร์ของ KernelSU เช่นกัน (3.18+ ยังเป็นเวอร์ชั่นทดลอง และยังต้องเขียนฟังก์ชั่นหลังบ้านเพิ่มเติม)
ในขณะนี้, มีแค่สถาปัตยกรรม `arm64-v8a` ที่รองรับเท่านั้น
ในขณะนี้, มีแค่สถาปัตยกรรม `arm64-v8a`, `armeabi-v7a` & `x86_64` ที่รองรับเท่านั้น
## การใช้งาน

View File

@@ -24,7 +24,7 @@ KernelSU Next, resmi olarak Android çekirdeklerinin çoğunu 4.4 sürümünden
- GKI 1.0 (4.19 - 5.4) çekirdeklerinin KernelSU sürücüsü ile yeniden derlenmesi gerekir.
- EOL (<4.14) çekirdekler de KernelSU sürücüsüyle yeniden derlenmelidir (3.18+ deneysel olup bazı fonksiyonların geri aktarımı gerekebilir).
Şu anda yalnızca `arm64-v8a` mimarisi desteklenmektedir.
Şu anda yalnızca `arm64-v8a`, `armeabi-v7a` & `x86_64` mimarisi desteklenmektedir.
## Kullanım

View File

@@ -24,7 +24,7 @@ KernelSU Next 正式支持大多數從 4.4 到 6.6 的 Android 內核
- GKI 1.0 (4.19 - 5.4) 內核需要重新編譯 KernelSU 驅動程序
- EOL (<4.14) 內核也需要重新編譯 KernelSU 驅動程序3.18+ 是實驗性的,可能需要移植一些功能)
目前僅支持 `arm64-v8a`
目前僅支持 `arm64-v8a`, `armeabi-v7a` & `x86_64`
## 用法

View File

@@ -11,9 +11,6 @@
[![Ліцензія: 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)
> [!IMPORTANT]
> Підтримка встановлення KernelSU Next способом модуля ядра через менеджер була вимкнена, натомість ви можете самі оновити його перепаковуючи ```init_boot``` вручну.
## Можливості
1. `su` на основі ядра та можливість контролювати дозволи руту.
@@ -27,7 +24,7 @@ KernelSU Next офіційно підтримує більшість Android я
- Користувачі GKI 1.0 (4.19 - 5.4) ядра мають бути перезібрані з драйвером KernelSU.
- Користувачі EOL (<4.14) ядра також мають бути перезібрані з драйвером KernelSU (Підтримка 3.18+ експерементальна і потребує бекпортів деяких функцій в ядрі).
На даний момент підтримується лише архітектура `armv8-a`.
На даний момент підтримується лише архітектура `arm64-v8a`, `armeabi-v7a` & `x86_64`.
## Спосіб використання

View File

@@ -24,7 +24,7 @@ KernelSU Next hỗ trợ chính thức các kernel Android từ phiên bản 4.4
- GKI 1.0 (4.19 - 5.4) kernels cần dược build lại với các nhân KernelSU Next
- EOL (<4.14) kernels cần dược build lại với các nhân KernelSU Next (các kernels 3.18+ đang dược thử nghiệm và có thể cần backports 1 vài thứ ).
Hiện tại kernelSU Next chỉ hỗ trợ những cpu có `arm64-v8a`
Hiện tại kernelSU Next chỉ hỗ trợ những cpu có `arm64-v8a`, `armeabi-v7a` & `x86_64`
## Sử dụng

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);
@@ -197,10 +188,8 @@ void escape_to_root(void)
sizeof(cred->cap_ambient));
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;
}
@@ -658,7 +649,7 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
// try umount ksu temp path
try_umount("/debug_ramdisk", false, MNT_DETACH);
try_umount("/sbin", false, MNT_DETACH);
// try umount hosts file
try_umount("/system/etc/hosts", false, MNT_DETACH);
@@ -738,6 +729,19 @@ __maybe_unused int ksu_kprobe_exit(void)
return 0;
}
extern int ksu_handle_devpts(struct inode *inode); // sucompat.c
static int ksu_inode_permission(struct inode *inode, int mask)
{
if (unlikely(inode->i_sb && inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)) {
#ifdef CONFIG_KSU_DEBUG
pr_info("%s: devpts inode accessed with mask: %x\n", __func__, mask);
#endif
ksu_handle_devpts(inode);
}
return 0;
}
// kernel 4.9 and older
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
int ksu_key_permission(key_ref_t key_ref, const struct cred *cred,
@@ -781,6 +785,7 @@ static struct security_hook_list ksu_hooks[] = {
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid),
LSM_HOOK_INIT(inode_permission, ksu_inode_permission),
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
LSM_HOOK_INIT(key_permission, ksu_key_permission)
#endif
@@ -969,7 +974,7 @@ void __init ksu_core_init(void)
{
#ifdef CONFIG_KSU_LSM_SECURITY_HOOKS
ksu_lsm_hook_init();
#else
#else
pr_info("ksu_core_init: LSM hooks not in use.\n");
#endif
}

View File

@@ -338,7 +338,7 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
return 0;
}
if (!d_is_reg(file->f_path.dentry)) {
if (!S_ISREG(file->f_path.dentry->d_inode->i_mode)) {
return 0;
}
@@ -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

@@ -170,7 +170,11 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
return FILLDIR_ACTOR_CONTINUE;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0)
strlcpy(data->dirpath, dirpath, DATA_PATH_LEN);
#else
strscpy(data->dirpath, dirpath, DATA_PATH_LEN);
#endif
data->depth = my_ctx->depth - 1;
list_add_tail(&data->list, my_ctx->data_path_list);
} else {
@@ -212,12 +216,53 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
return FILLDIR_ACTOR_CONTINUE;
}
/*
* 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)
{
struct path kpath;
// kern_path returns 0 on success
if (kern_path(path, 0, &kpath))
return true;
// 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) {
@@ -226,7 +271,11 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
// First depth
struct data_path data;
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0)
strlcpy(data.dirpath, path, DATA_PATH_LEN);
#else
strscpy(data.dirpath, path, DATA_PATH_LEN);
#endif
data.depth = depth;
list_add_tail(&data.list, &data_path_list);
@@ -248,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);
@@ -286,13 +353,25 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
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);

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

@@ -11,6 +11,10 @@ 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
@@ -24,6 +28,9 @@ 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(
@@ -54,5 +61,11 @@ 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,8 @@
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
import androidx.activity.ComponentActivity
@@ -21,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
@@ -35,11 +40,11 @@ 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
import androidx.navigation.compose.currentBackStackEntryAsState
import com.dergoogler.mmrl.platform.Platform
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
@@ -51,10 +56,13 @@ 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.rootAvailable
import com.rifsxd.ksunext.ui.util.install
import com.rifsxd.ksunext.ui.webui.initPlatform
import com.rifsxd.ksunext.ui.util.isSuCompatDisabled
import com.rifsxd.ksunext.ui.screen.FlashIt
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
class MainActivity : ComponentActivity() {
@@ -71,23 +79,66 @@ 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 {
KernelSUTheme {
// 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
) {
val navController = rememberNavController()
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 +146,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 +173,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

@@ -1,15 +1,8 @@
package com.rifsxd.ksunext.ui.screen
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
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
@@ -25,7 +18,6 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
@@ -37,54 +29,32 @@ 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.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.content.FileProvider
import androidx.lifecycle.compose.dropUnlessResumed
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.IconSource
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
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import com.rifsxd.ksunext.BuildConfig
import com.rifsxd.ksunext.Natives
import com.rifsxd.ksunext.ksuApp
import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ui.component.AboutDialog
import com.rifsxd.ksunext.ui.component.ConfirmResult
import com.rifsxd.ksunext.ui.component.DialogHandle
import com.rifsxd.ksunext.ui.component.SwitchItem
import com.rifsxd.ksunext.ui.component.rememberConfirmDialog
import com.rifsxd.ksunext.ui.component.rememberCustomDialog
import com.rifsxd.ksunext.ui.component.rememberLoadingDialog
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
import com.rifsxd.ksunext.ui.util.getBugreportFile
import com.rifsxd.ksunext.ui.util.*
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
/**
* @author rifsxd
@@ -195,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

@@ -0,0 +1,178 @@
package com.rifsxd.ksunext.ui.screen
import android.content.Context
import android.content.Intent
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column
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.AlertDialog
import androidx.compose.material3.TextButton
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.lifecycle.compose.dropUnlessResumed
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 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/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@Composable
fun CustomizationScreen(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 = dropUnlessResumed {
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)
var useBanner by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_banner", true)
)
}
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 {
mutableStateOf(
prefs.getBoolean("enable_amoled", false)
)
}
var showRestartDialog by remember { mutableStateOf(false) }
if (isSystemInDarkTheme()) {
SwitchItem(
icon = Icons.Filled.Contrast,
title = stringResource(id = R.string.settings_amoled_mode),
summary = stringResource(id = R.string.settings_amoled_mode_summary),
checked = enableAmoled
) { checked ->
prefs.edit().putBoolean("enable_amoled", checked).apply()
enableAmoled = checked
showRestartDialog = true
}
if (showRestartDialog) {
AlertDialog(
onDismissRequest = { showRestartDialog = false },
title = { Text(stringResource(R.string.restart_required)) },
text = { Text(stringResource(R.string.restart_app_message)) },
confirmButton = {
TextButton(onClick = {
showRestartDialog = false
// Restart the app
val packageManager = context.packageManager
val intent = packageManager.getLaunchIntentForPackage(context.packageName)
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
Runtime.getRuntime().exit(0)
}) {
Text(stringResource(R.string.restart_app))
}
},
dismissButton = {
TextButton(onClick = { showRestartDialog = false }) {
Text(stringResource(R.string.later))
}
}
)
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
onBack: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
) {
TopAppBar(
title = { Text(stringResource(R.string.customization)) }, 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 CustomizationPreview() {
CustomizationScreen(EmptyDestinationsNavigator)
}

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

@@ -1,5 +1,6 @@
package com.rifsxd.ksunext.ui.screen
import android.content.Context
import android.os.Environment
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
@@ -35,6 +36,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.platform.LocalView
@@ -69,6 +71,11 @@ fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String
var actionResult: Boolean
var isActionRunning by rememberSaveable { mutableStateOf(true) }
val context = LocalContext.current
// Read developer options from SharedPreferences
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val developerOptionsEnabled = prefs.getBoolean("enable_developer_options", false)
val view = LocalView.current
DisposableEffect(isActionRunning) {
view.keepScreenOn = isActionRunning
@@ -158,7 +165,7 @@ fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String
}
Text(
modifier = Modifier.padding(8.dp),
text = text,
text = if (developerOptionsEnabled) logContent.toString() else text,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = FontFamily.Monospace,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,

View File

@@ -1,5 +1,6 @@
package com.rifsxd.ksunext.ui.screen
import android.content.Context
import android.net.Uri
import android.os.Environment
import android.os.Parcelable
@@ -45,6 +46,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
@@ -61,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
@@ -75,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>,
@@ -104,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
@@ -119,6 +136,13 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
mutableStateOf(FlashingStatus.FLASHING)
}
val context = LocalContext.current
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
@@ -127,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)
@@ -165,6 +222,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
flashing,
onBack = dropUnlessResumed {
navigator.popBackStack()
if (finishIntent) activity?.finish()
},
onSave = {
scope.launch {
@@ -204,19 +262,49 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
icon = { Icon(Icons.Filled.Close, contentDescription = null) },
onClick = {
navigator.popBackStack()
if (finishIntent) activity?.finish()
}
)
}
if (flashIt is FlashIt.FlashBoot && (flashing == FlashingStatus.SUCCESS || flashing == FlashingStatus.FAILED)) {
// Close button for LKM flashing
ExtendedFloatingActionButton(
text = { Text(text = stringResource(R.string.close)) },
icon = { Icon(Icons.Filled.Close, contentDescription = null) },
onClick = {
navigator.popBackStack()
val isLocalPatch = flashIt.boot != null && !flashIt.ota
val isDirectOrOta = flashIt.boot == null || flashIt.ota
if (flashing == FlashingStatus.FAILED) {
// Always show close on failure
ExtendedFloatingActionButton(
text = { Text(text = stringResource(R.string.close)) },
icon = { Icon(Icons.Filled.Close, contentDescription = null) },
onClick = {
navigator.popBackStack()
}
)
} else if (flashing == FlashingStatus.SUCCESS) {
if (isLocalPatch) {
// Local patching: show only Close
ExtendedFloatingActionButton(
text = { Text(text = stringResource(R.string.close)) },
icon = { Icon(Icons.Filled.Close, contentDescription = null) },
onClick = {
navigator.popBackStack()
}
)
} else if (isDirectOrOta) {
// Direct install or OTA inactive slot: show only Reboot
ExtendedFloatingActionButton(
onClick = {
scope.launch {
withContext(Dispatchers.IO) {
reboot()
}
}
},
icon = { Icon(Icons.Filled.Refresh, contentDescription = stringResource(R.string.reboot)) },
text = { Text(text = stringResource(R.string.reboot)) }
)
}
)
}
}
},
contentWindowInsets = WindowInsets.safeDrawing,
@@ -237,7 +325,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
}
Text(
modifier = Modifier.padding(8.dp),
text = text,
text = if (developerOptionsEnabled) logContent.toString() else text,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = FontFamily.Monospace,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
@@ -246,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
@@ -35,12 +39,13 @@ import androidx.compose.ui.text.toUpperCase
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.pm.PackageInfoCompat
import androidx.lifecycle.viewmodel.compose.viewModel
import com.dergoogler.mmrl.ui.component.LabelItem
import com.dergoogler.mmrl.ui.component.LabelItemDefaults
import com.dergoogler.mmrl.ui.component.text.TextRow
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
// import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination // DISBAND LKM MODE
import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -49,6 +54,8 @@ import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ui.component.rememberConfirmDialog
import com.rifsxd.ksunext.ui.util.*
import com.rifsxd.ksunext.ui.util.module.LatestVersionInfo
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
import com.rifsxd.ksunext.ui.viewmodel.SuperUserViewModel
import java.util.*
@OptIn(ExperimentalMaterial3Api::class)
@@ -61,14 +68,18 @@ fun HomeScreen(navigator: DestinationsNavigator) {
val isManager = Natives.becomeManager(ksuApp.packageName)
val ksuVersion = if (isManager) Natives.version else null
val context = LocalContext.current
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val developerOptionsEnabled = prefs.getBoolean("enable_developer_options", false)
Scaffold(
topBar = {
TopBar(
kernelVersion,
ksuVersion,
// onInstallClick = {
// navigator.navigate(InstallScreenDestination)
// }, // DISBAND LKM MODE
onInstallClick = {
navigator.navigate(InstallScreenDestination)
},
scrollBehavior = scrollBehavior
)
},
@@ -85,9 +96,23 @@ fun HomeScreen(navigator: DestinationsNavigator) {
val lkmMode = ksuVersion?.let {
if (it >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && kernelVersion.isGKI()) Natives.isLkmMode else null
}
val superUserViewModel: SuperUserViewModel = viewModel()
val moduleViewModel: ModuleViewModel = viewModel()
LaunchedEffect(Unit) {
if (superUserViewModel.appList.isEmpty()) {
superUserViewModel.fetchAppList()
}
if (moduleViewModel.moduleList.isEmpty()) {
moduleViewModel.fetchModuleList()
}
}
StatusCard(kernelVersion, ksuVersion, lkmMode) {
// navigator.navigate(InstallScreenDestination) // DISBAND LKM MODE
navigator.navigate(InstallScreenDestination)
}
if (isManager && Natives.requireNewKernel()) {
WarningCard(
@@ -108,7 +133,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
UpdateCard()
}
//NextCard()
InfoCard()
InfoCard(autoExpand = developerOptionsEnabled)
IssueReportCard()
//EXperimentalCard()
Spacer(Modifier)
@@ -168,25 +193,74 @@ 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(
kernelVersion: KernelVersion,
ksuVersion: Int?,
// onInstallClick: () -> Unit, // DISBAND LKM MODE
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 (kernelVersion.isGKI()) {
// IconButton(onClick = onInstallClick) {
// Icon(
// imageVector = Icons.Filled.Archive,
// contentDescription = stringResource(id = R.string.install)
// )
// }
// } // DISBAND LKM MODE
if (ksuVersion != null) {
if (kernelVersion.isGKI()) {
IconButton(onClick = onInstallClick) {
Icon(
imageVector = Icons.Filled.Archive,
contentDescription = stringResource(id = R.string.install)
)
}
}
}
if (ksuVersion != null) {
var showDropdown by remember { mutableStateOf(false) }
@@ -194,7 +268,7 @@ private fun TopBar(
showDropdown = true
}) {
Icon(
imageVector = Icons.Filled.Refresh,
imageVector = Icons.Filled.PowerSettingsNew,
contentDescription = stringResource(id = R.string.reboot)
)
@@ -222,23 +296,13 @@ 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(
kernelVersion: KernelVersion,
ksuVersion: Int?,
lkmMode: Boolean?,
moduleUpdateCount: Int = 0,
onClickInstall: () -> Unit = {}
) {
val context = LocalContext.current
@@ -255,18 +319,23 @@ private fun StatusCard(
.fillMaxWidth()
.clickable {
tapCount++
if (tapCount == 10) {
if (tapCount == 5) {
Toast.makeText(context, "What are you doing? 🤔", Toast.LENGTH_SHORT).show()
} else if (tapCount == 10) {
Toast.makeText(context, "Never gonna give you up! 💜", Toast.LENGTH_SHORT).show()
// tapCount = 0
val url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(url))
intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
if (ksuVersion != null) {
context.startActivity(intent)
} else if (ksuVersion == null && kernelVersion.isGKI()) {
onClickInstall()
} else {
Toast.makeText(context, "Something weird happened... 🤔", Toast.LENGTH_SHORT).show()
}
} else if (ksuVersion == null && kernelVersion.isGKI()) {
onClickInstall()
}
// if (kernelVersion.isGKI()) {
// onClickInstall()
// }
}
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
when {
@@ -281,7 +350,7 @@ private fun StatusCard(
}
Icon(
getSeasonalIcon(), // Use dynamic seasonal icon
imageVector = Icons.Filled.CheckCircle,
contentDescription = stringResource(R.string.home_working)
)
Column(
@@ -291,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(
@@ -333,34 +426,26 @@ private fun StatusCard(
text = stringResource(R.string.home_module_count, getModuleCount()),
style = MaterialTheme.typography.bodyMedium
)
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.lkm_mode_deprecated))
// Column(Modifier.padding(start = 20.dp)) {
// Text(
// text = stringResource(R.string.lkm_mode_deprecated),
// style = MaterialTheme.typography.titleMedium
// )
// Spacer(Modifier.height(4.dp))
// Text(
// text = stringResource(R.string.lkm_alternative_suggestion),
// style = MaterialTheme.typography.bodyMedium
// )
// }
// }
kernelVersion.isGKI() -> {
Icon(Icons.Filled.NewReleases, stringResource(R.string.home_not_installed))
Column(Modifier.padding(start = 20.dp)) {
Text(
text = stringResource(R.string.home_not_installed),
style = MaterialTheme.typography.titleMedium
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_click_to_install),
style = MaterialTheme.typography.bodyMedium
)
}
}
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),
@@ -401,21 +486,21 @@ fun WarningCard(
}
@Composable
private fun InfoCard() {
private fun InfoCard(autoExpand: Boolean = false) {
val context = LocalContext.current
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var useOverlayFs by rememberSaveable {
mutableStateOf(prefs.getBoolean("use_overlay_fs", false))
}
val isManager = Natives.becomeManager(ksuApp.packageName)
val ksuVersion = if (isManager) Natives.version else null
LaunchedEffect(Unit) {
useOverlayFs = prefs.getBoolean("use_overlay_fs", false)
}
var expanded by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(autoExpand) {
if (autoExpand) {
expanded = true
}
}
ElevatedCard {
Column(
@@ -423,8 +508,6 @@ private fun InfoCard() {
.fillMaxWidth()
.padding(start = 24.dp, top = 24.dp, end = 24.dp, bottom = 16.dp)
) {
var expanded by rememberSaveable { mutableStateOf(false) }
@Composable
fun InfoCardItem(label: String, content: String, icon: Any? = null) {
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -494,7 +577,7 @@ private fun InfoCard() {
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

@@ -22,6 +22,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.FileUpload
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
@@ -30,6 +31,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
@@ -39,6 +41,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -77,6 +80,32 @@ import com.rifsxd.ksunext.ui.util.rootAvailable
@Destination<RootGraph>
@Composable
fun InstallScreen(navigator: DestinationsNavigator) {
var showLkmWarning by rememberSaveable { mutableStateOf(true) }
if (showLkmWarning) {
AlertDialog(
onDismissRequest = {
showLkmWarning = false
navigator.popBackStack()
},
title = { Text(stringResource(R.string.warning)) },
text = { Text(stringResource(R.string.lkm_warning_message)) },
confirmButton = {
TextButton(onClick = { showLkmWarning = false }) {
Text(stringResource(R.string.proceed))
}
},
dismissButton = {
TextButton(onClick = {
showLkmWarning = false
navigator.popBackStack()
}) {
Text(stringResource(R.string.cancel))
}
}
)
}
var installMethod by remember {
mutableStateOf<InstallMethod?>(null)
}

View File

@@ -1,5 +1,6 @@
package com.rifsxd.ksunext.ui.screen
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
@@ -8,7 +9,14 @@ import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.LocalIndication
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.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -20,6 +28,7 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
@@ -29,6 +38,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Wysiwyg
import androidx.compose.material.icons.filled.*
@@ -67,6 +77,10 @@ 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
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -75,11 +89,11 @@ 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
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.lifecycle.viewmodel.compose.viewModel
import com.dergoogler.mmrl.platform.Platform
import com.ramcosta.composedestinations.annotation.Destination
@@ -91,6 +105,8 @@ import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.rifsxd.ksunext.Natives
import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ksuApp
@@ -110,6 +126,8 @@ import com.rifsxd.ksunext.ui.util.restoreModule
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
import com.rifsxd.ksunext.ui.webui.WebUIActivity
import com.rifsxd.ksunext.ui.webui.WebUIXActivity
import com.dergoogler.mmrl.ui.component.LabelItem
import com.topjohnwu.superuser.io.SuFile
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@@ -122,9 +140,11 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
LaunchedEffect(Unit) {
viewModel.sortAToZ = prefs.getBoolean("module_sort_a_to_z", true)
viewModel.sortZToA = prefs.getBoolean("module_sort_z_to_a", false)
viewModel.sortSizeLowToHigh = prefs.getBoolean("module_sort_size_low_to_high", false)
viewModel.sortSizeHighToLow = prefs.getBoolean("module_sort_size_high_to_low", false)
if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) {
viewModel.sortAToZ = prefs.getBoolean("module_sort_a_to_z", true)
viewModel.sortZToA = prefs.getBoolean("module_sort_z_to_a", false)
viewModel.fetchModuleList()
}
}
@@ -177,9 +197,13 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
onClick = {
viewModel.sortAToZ = !viewModel.sortAToZ
viewModel.sortZToA = false
viewModel.sortSizeLowToHigh = false
viewModel.sortSizeHighToLow = false
prefs.edit()
.putBoolean("module_sort_a_to_z", viewModel.sortAToZ)
.putBoolean("module_sort_z_to_a", false)
.putBoolean("module_sort_size_low_to_high", false)
.putBoolean("module_sort_size_high_to_low", false)
.apply()
scope.launch {
viewModel.fetchModuleList()
@@ -197,9 +221,61 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
onClick = {
viewModel.sortZToA = !viewModel.sortZToA
viewModel.sortAToZ = false
viewModel.sortSizeLowToHigh = false
viewModel.sortSizeHighToLow = false
prefs.edit()
.putBoolean("module_sort_z_to_a", viewModel.sortZToA)
.putBoolean("module_sort_a_to_z", false)
.putBoolean("module_sort_size_low_to_high", false)
.putBoolean("module_sort_size_high_to_low", false)
.apply()
scope.launch {
viewModel.fetchModuleList()
}
}
)
DropdownMenuItem(
text = {
Text(stringResource(R.string.module_size_low_to_high))
},
trailingIcon = {
Checkbox(checked = viewModel.sortSizeLowToHigh, onCheckedChange = null)
},
onClick = {
viewModel.sortSizeLowToHigh = !viewModel.sortSizeLowToHigh
viewModel.sortAToZ = false
viewModel.sortZToA = false
viewModel.sortSizeHighToLow = false
prefs.edit()
.putBoolean("module_sort_size_low_to_high", viewModel.sortSizeLowToHigh)
.putBoolean("module_sort_a_to_z", false)
.putBoolean("module_sort_z_to_a", false)
.putBoolean("module_sort_size_high_to_low", false)
.apply()
scope.launch {
viewModel.fetchModuleList()
}
}
)
DropdownMenuItem(
text = {
Text(stringResource(R.string.module_size_high_to_low))
},
trailingIcon = {
Checkbox(checked = viewModel.sortSizeHighToLow, onCheckedChange = null)
},
onClick = {
viewModel.sortSizeHighToLow = !viewModel.sortSizeHighToLow
viewModel.sortAToZ = false
viewModel.sortZToA = false
viewModel.sortSizeLowToHigh = false
prefs.edit()
.putBoolean("module_sort_size_high_to_low", viewModel.sortSizeHighToLow)
.putBoolean("module_sort_a_to_z", false)
.putBoolean("module_sort_z_to_a", false)
.putBoolean("module_sort_size_low_to_high", false)
.apply()
scope.launch {
viewModel.fetchModuleList()
@@ -215,12 +291,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 ->
@@ -239,19 +309,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(
@@ -298,17 +362,21 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
},
onClickModule = { id, name, hasWebUi ->
if (hasWebUi) {
val wxEngine = Intent(context, WebUIXActivity::class.java)
.setData("kernelsu://webuix/$id".toUri())
.putExtra("id", id)
.putExtra("name", name)
val ksuEngine = Intent(context, WebUIActivity::class.java)
.setData("kernelsu://webui/$id".toUri())
.putExtra("id", id)
.putExtra("name", name)
webUILauncher.launch(
if (prefs.getBoolean("use_webuix", true) && Platform.isAlive) {
Intent(context, WebUIXActivity::class.java)
.setData(Uri.parse("kernelsu://webuix/$id"))
.putExtra("id", id)
.putExtra("name", name)
wxEngine
} else {
Intent(context, WebUIActivity::class.java)
.setData(Uri.parse("kernelsu://webui/$id"))
.putExtra("id", id)
.putExtra("name", name)
ksuEngine
}
)
}
@@ -358,15 +426,11 @@ private fun ModuleList(
val hasShownWarning =
rememberSaveable { mutableStateOf(prefs.getBoolean("has_shown_warning", false)) }
var useOverlayFs by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_overlay_fs", false)
)
}
val loadingDialog = rememberLoadingDialog()
val confirmDialog = rememberConfirmDialog()
var expandedModuleId by rememberSaveable { mutableStateOf<String?>(null) }
suspend fun onModuleUpdate(
module: ModuleViewModel.ModuleInfo,
changelogUrl: String,
@@ -535,9 +599,9 @@ private fun ModuleList(
else -> {
items(viewModel.moduleList) { module ->
val scope = rememberCoroutineScope()
val updatedModule by produceState(initialValue = Triple("", "", "")) {
scope.launch(Dispatchers.IO) {
value = viewModel.checkUpdate(module)
val updatedModule by produceState(key1 = module.id, initialValue = Triple("", "", "")) {
value = withContext(Dispatchers.IO) {
viewModel.checkUpdate(module)
}
}
@@ -584,10 +648,15 @@ private fun ModuleList(
updatedModule.first,
"${module.name}-${updatedModule.second}.zip"
)
viewModel.markNeedRefresh()
}
},
onClick = {
onClickModule(it.dirId, it.name, it.hasWebUi)
},
expanded = expandedModuleId == module.id,
onExpandToggle = {
expandedModuleId = if (expandedModuleId == module.id) null else module.id
}
)
@@ -613,256 +682,404 @@ 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()
) {
val textDecoration = if (!module.remove) null else TextDecoration.LineThrough
val interactionSource = remember { MutableInteractionSource() }
val indication = LocalIndication.current
val viewModel = viewModel<ModuleViewModel>()
val context = LocalContext.current
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var developerOptionsEnabled by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_developer_options", false)
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.medium)
.clickable(
onClick = onExpandToggle
)
}
LaunchedEffect(Unit) {
developerOptionsEnabled = prefs.getBoolean("enable_developer_options", false)
}
Column(
) {
Box(
modifier = Modifier
.padding(22.dp, 18.dp, 22.dp, 12.dp)
.fillMaxWidth()
) {
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)
val context = LocalContext.current
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val useBanner = prefs.getBoolean("use_banner", true)
if (useBanner && module.banner.isNotEmpty()) {
val isDark = isSystemInDarkTheme()
val colorScheme = MaterialTheme.colorScheme
val context = LocalContext.current
val amoledMode = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
.getBoolean("amoled_mode", false)
val isDynamic = colorScheme.primary != colorScheme.secondary
val fadeColor = when {
amoledMode && isDark -> Color.Black
isDynamic -> colorScheme.surface
isDark -> Color(0xFF222222)
else -> Color.White
}
Box(
modifier = Modifier
.matchParentSize(),
contentAlignment = Alignment.Center
) {
if (module.banner.startsWith("https", true) || module.banner.startsWith("http", true)) {
AsyncImage(
model = module.banner,
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
contentScale = ContentScale.Crop,
alpha = 0.18f
)
} else {
val bannerData = remember(module.banner) {
try {
val file = SuFile("/data/adb/modules/${module.id}/${module.banner}")
file.newInputStream().use { it.readBytes() }
} catch (e: Exception) {
null
}
}
if (bannerData != null) {
AsyncImage(
model = ImageRequest.Builder(context)
.data(bannerData)
.build(),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
contentScale = ContentScale.Crop,
alpha = 0.18f
)
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(
Brush.verticalGradient(
colors = listOf(
fadeColor.copy(alpha = 0.0f),
fadeColor.copy(alpha = 0.8f)
),
startY = 0f,
endY = Float.POSITIVE_INFINITY
)
)
)
}
}
Column {
val interactionSource = remember { MutableInteractionSource() }
var developerOptionsEnabled by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_developer_options", false)
)
}
LaunchedEffect(Unit) {
developerOptionsEnabled = prefs.getBoolean("enable_developer_options", false)
}
Column(
modifier = Modifier.fillMaxWidth(0.8f)
modifier = Modifier
.padding(22.dp, 18.dp, 22.dp, 12.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,
)
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
)
)
if (module.remove) {
LabelItem(
text = stringResource(R.string.uninstall),
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.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) {
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
)
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.weight(1f))
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(12.dp))
Text(
text = "$moduleVersion: ${module.version}",
text = module.description,
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
fontWeight = MaterialTheme.typography.bodySmall.fontWeight,
overflow = TextOverflow.Ellipsis,
maxLines = 4
)
if (developerOptionsEnabled) {
Spacer(modifier = Modifier.height(2.dp))
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
)
}
}
Spacer(modifier = Modifier.weight(1f))
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(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(16.dp))
HorizontalDivider(thickness = Dp.Hairline)
Spacer(modifier = Modifier.height(4.dp))
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
if (module.hasActionScript) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
onClick = {
navigator.navigate(ExecuteModuleActionScreenDestination(module.dirId))
viewModel.markNeedRefresh()
},
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.PlayArrow,
contentDescription = null
)
if (!module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
text = stringResource(R.string.action),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize
)
}
if (expanded) {
Spacer(modifier = Modifier.height(10.dp))
}
Spacer(modifier = Modifier.weight(0.1f, true))
}
if (module.hasWebUi) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
onClick = { onClick(module) },
interactionSource = interactionSource,
contentPadding = ButtonDefaults.TextButtonContentPadding
AnimatedVisibility(
visible = expanded,
enter = fadeIn() + expandVertically(),
exit = shrinkVertically() + fadeOut()
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.AutoMirrored.Outlined.Wysiwyg,
contentDescription = null
)
if (!module.hasActionScript && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.open)
)
}
}
}
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
if (module.hasActionScript) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
onClick = {
navigator.navigate(ExecuteModuleActionScreenDestination(module.dirId))
viewModel.markNeedRefresh()
},
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Terminal,
contentDescription = null
)
if (!module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
text = stringResource(R.string.action),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize
)
}
}
Spacer(modifier = Modifier.weight(1f, true))
Spacer(modifier = Modifier.weight(0.1f, true))
}
if (updateUrl.isNotEmpty()) {
Button(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove,
onClick = { onUpdate(module) },
shape = ButtonDefaults.textShape,
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Download,
contentDescription = null
)
if (!module.hasActionScript || !module.hasWebUi) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.module_update)
)
}
}
if (module.hasWebUi) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
onClick = { onClick(module) },
interactionSource = interactionSource,
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.AutoMirrored.Outlined.Wysiwyg,
contentDescription = null
)
if (!module.hasActionScript && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.open)
)
}
}
}
Spacer(modifier = Modifier.weight(0.1f, true))
}
Spacer(modifier = Modifier.weight(1f, true))
if (module.remove) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
onClick = { onRestore(module) },
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Restore,
contentDescription = null
)
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.restore)
)
}
}
} else {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = true,
onClick = { onUninstall(module) },
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Delete,
contentDescription = null
)
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.uninstall)
)
if (updateUrl.isNotEmpty() && !module.remove && !module.update) {
Button(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove,
onClick = { onUpdate(module) },
shape = ButtonDefaults.textShape,
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Download,
contentDescription = null
)
if (!module.hasActionScript || !module.hasWebUi) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.module_update)
)
}
}
Spacer(modifier = Modifier.weight(0.1f, true))
}
if (module.remove) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
onClick = { onRestore(module) },
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Restore,
contentDescription = null
)
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.restore)
)
}
}
} else {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = true,
onClick = { onUninstall(module) },
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Delete,
contentDescription = null
)
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.uninstall)
)
}
}
}
}
}
}
@@ -871,6 +1088,18 @@ fun ModuleItem(
}
}
fun formatSize(size: Long): String {
val kb = 1024
val mb = kb * 1024
val gb = mb * 1024
return when {
size >= gb -> String.format("%.2f GB", size.toDouble() / gb)
size >= mb -> String.format("%.2f MB", size.toDouble() / mb)
size >= kb -> String.format("%.2f KB", size.toDouble() / kb)
else -> "$size B"
}
}
@Preview
@Composable
fun ModuleItemPreview() {
@@ -887,7 +1116,9 @@ fun ModuleItemPreview() {
updateJson = "",
hasWebUi = false,
hasActionScript = false,
dirId = "dirId"
dirId = "dirId",
size = 12345678L,
banner = ""
)
ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}, {})
ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}, {}, false, {})
}

View File

@@ -7,6 +7,7 @@ import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -65,6 +66,8 @@ import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
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
@@ -222,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) }
@@ -242,8 +247,10 @@ fun SettingScreen(navigator: DestinationsNavigator) {
useOverlayFs = it
if (useOverlayFs) {
moduleBackup()
updateMountSystemFile(true)
} else {
moduleMigration()
updateMountSystemFile(false)
}
if (isManager) install()
showRebootDialog = true
@@ -287,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)
@@ -383,6 +318,20 @@ fun SettingScreen(navigator: DestinationsNavigator) {
)
}
val customization = stringResource(id = R.string.customization)
ListItem(
leadingContent = {
Icon(
Icons.Filled.Palette,
customization
)
},
headlineContent = { Text(customization) },
modifier = Modifier.clickable {
navigator.navigate(CustomizationScreenDestination)
}
)
if (ksuVersion != null) {
val backupRestore = stringResource(id = R.string.backup_restore)
ListItem(
@@ -399,12 +348,28 @@ fun SettingScreen(navigator: DestinationsNavigator) {
)
}
// val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
// if (lkmMode) {
// UninstallItem(navigator) {
// loadingDialog.withLoading(it)
// }
// } // DISBAND LKM MODE
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) {
loadingDialog.withLoading(it)
}
}
var showBottomsheet by remember { mutableStateOf(false) }
@@ -532,107 +497,107 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
// @Composable
// fun UninstallItem(
// navigator: DestinationsNavigator,
// withLoading: suspend (suspend () -> Unit) -> Unit,
// ) {
// val context = LocalContext.current
// val scope = rememberCoroutineScope()
// val uninstallConfirmDialog = rememberConfirmDialog()
// val showTodo = {
// Toast.makeText(context, "TODO", Toast.LENGTH_SHORT).show()
// }
// val uninstallDialog = rememberUninstallDialog { uninstallType ->
// scope.launch {
// val result = uninstallConfirmDialog.awaitConfirm(
// title = context.getString(uninstallType.title),
// content = context.getString(uninstallType.message)
// )
// if (result == ConfirmResult.Confirmed) {
// withLoading {
// when (uninstallType) {
// UninstallType.TEMPORARY -> showTodo()
// UninstallType.PERMANENT -> navigator.navigate(
// FlashScreenDestination(FlashIt.FlashUninstall)
// )
// UninstallType.RESTORE_STOCK_IMAGE -> navigator.navigate(
// FlashScreenDestination(FlashIt.FlashRestore)
// )
// UninstallType.NONE -> Unit
// }
// }
// }
// }
// }
// val uninstall = stringResource(id = R.string.settings_uninstall)
// ListItem(
// leadingContent = {
// Icon(
// Icons.Filled.Delete,
// uninstall
// )
// },
// headlineContent = { Text(uninstall) },
// modifier = Modifier.clickable {
// uninstallDialog.show()
// }
// )
// }
@Composable
fun UninstallItem(
navigator: DestinationsNavigator,
withLoading: suspend (suspend () -> Unit) -> Unit,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val uninstallConfirmDialog = rememberConfirmDialog()
val showTodo = {
Toast.makeText(context, "TODO", Toast.LENGTH_SHORT).show()
}
val uninstallDialog = rememberUninstallDialog { uninstallType ->
scope.launch {
val result = uninstallConfirmDialog.awaitConfirm(
title = context.getString(uninstallType.title),
content = context.getString(uninstallType.message)
)
if (result == ConfirmResult.Confirmed) {
withLoading {
when (uninstallType) {
UninstallType.TEMPORARY -> showTodo()
UninstallType.PERMANENT -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashUninstall)
)
UninstallType.RESTORE_STOCK_IMAGE -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashRestore)
)
UninstallType.NONE -> Unit
}
}
}
}
}
val uninstall = stringResource(id = R.string.settings_uninstall)
ListItem(
leadingContent = {
Icon(
Icons.Filled.Delete,
uninstall
)
},
headlineContent = { Text(uninstall) },
modifier = Modifier.clickable {
uninstallDialog.show()
}
)
}
// enum class UninstallType(val title: Int, val message: Int, val icon: ImageVector) {
// TEMPORARY(
// R.string.settings_uninstall_temporary,
// R.string.settings_uninstall_temporary_message,
// Icons.Filled.Delete
// ),
// PERMANENT(
// R.string.settings_uninstall_permanent,
// R.string.settings_uninstall_permanent_message,
// Icons.Filled.DeleteForever
// ),
// RESTORE_STOCK_IMAGE(
// R.string.settings_restore_stock_image,
// R.string.settings_restore_stock_image_message,
// Icons.AutoMirrored.Filled.Undo
// ),
// NONE(0, 0, Icons.Filled.Delete)
// }
enum class UninstallType(val title: Int, val message: Int, val icon: ImageVector) {
TEMPORARY(
R.string.settings_uninstall_temporary,
R.string.settings_uninstall_temporary_message,
Icons.Filled.Delete
),
PERMANENT(
R.string.settings_uninstall_permanent,
R.string.settings_uninstall_permanent_message,
Icons.Filled.DeleteForever
),
RESTORE_STOCK_IMAGE(
R.string.settings_restore_stock_image,
R.string.settings_restore_stock_image_message,
Icons.AutoMirrored.Filled.Undo
),
NONE(0, 0, Icons.Filled.Delete)
}
// @OptIn(ExperimentalMaterial3Api::class)
// @Composable
// fun rememberUninstallDialog(onSelected: (UninstallType) -> Unit): DialogHandle {
// return rememberCustomDialog { dismiss ->
// val options = listOf(
// // UninstallType.TEMPORARY,
// UninstallType.PERMANENT,
// UninstallType.RESTORE_STOCK_IMAGE
// )
// val listOptions = options.map {
// ListOption(
// titleText = stringResource(it.title),
// subtitleText = if (it.message != 0) stringResource(it.message) else null,
// icon = IconSource(it.icon)
// )
// }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun rememberUninstallDialog(onSelected: (UninstallType) -> Unit): DialogHandle {
return rememberCustomDialog { dismiss ->
val options = listOf(
// UninstallType.TEMPORARY,
UninstallType.PERMANENT,
UninstallType.RESTORE_STOCK_IMAGE
)
val listOptions = options.map {
ListOption(
titleText = stringResource(it.title),
subtitleText = if (it.message != 0) stringResource(it.message) else null,
icon = IconSource(it.icon)
)
}
// var selection = UninstallType.NONE
// ListDialog(state = rememberUseCaseState(visible = true, onFinishedRequest = {
// if (selection != UninstallType.NONE) {
// onSelected(selection)
// }
// }, onCloseRequest = {
// dismiss()
// }), header = Header.Default(
// title = stringResource(R.string.settings_uninstall),
// ), selection = ListSelection.Single(
// showRadioButtons = false,
// options = listOptions,
// ) { index, _ ->
// selection = options[index]
// })
// }
// } // DISBAND LKM MODE
var selection = UninstallType.NONE
ListDialog(state = rememberUseCaseState(visible = true, onFinishedRequest = {
if (selection != UninstallType.NONE) {
onSelected(selection)
}
}, onCloseRequest = {
dismiss()
}), header = Header.Default(
title = stringResource(R.string.settings_uninstall),
), selection = ListSelection.Single(
showRadioButtons = false,
options = listOptions,
) { index, _ ->
selection = options[index]
})
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable

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))
}
}
@@ -152,6 +138,9 @@ private fun AppItem(
supportingContent = {
Column {
Text(app.packageName)
Spacer(modifier = Modifier.height(4.dp))
FlowRow(
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {

View File

@@ -2,9 +2,14 @@ package com.rifsxd.ksunext.ui.theme
import androidx.compose.ui.graphics.Color
val YELLOW = Color(0xFFeed502)
val YELLOW_LIGHT = Color(0xFFffff52)
val SECONDARY_LIGHT = Color(0xffa9817f)
val PRIMARY = Color(0xFF8AADF4) // Catppuccin Blue
val PRIMARY_LIGHT = Color(0xFFB7BDF8) // Catppuccin Lavender
val SECONDARY_LIGHT = Color(0xFFA6DA95) // Catppuccin Green
val YELLOW_DARK = Color(0xFFb7a400)
val SECONDARY_DARK = Color(0xFF4c2b2b)
val PRIMARY_DARK = Color(0xFF7DC4E4) // Catppuccin Sky
val SECONDARY_DARK = Color(0xFFF5BDE6) // Catppuccin Pink
val AMOLED_BLACK = Color(0xFF000000) // Pure black for AMOLED
val DARK_PURPLE = Color(0xFF6E6CB6) // Catppuccin Mauve (dark purple)
val DARK_GREY = Color(0xFF363A4F) // Catppuccin Surface (dark grey)

View File

@@ -17,29 +17,66 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme(
primary = YELLOW,
secondary = YELLOW_DARK,
primary = PRIMARY,
secondary = PRIMARY_DARK,
tertiary = SECONDARY_DARK
)
private val LightColorScheme = lightColorScheme(
primary = YELLOW,
secondary = YELLOW_LIGHT,
primary = PRIMARY,
secondary = PRIMARY_LIGHT,
tertiary = SECONDARY_LIGHT
)
fun Color.blend(other: Color, ratio: Float): Color {
val inverse = 1f - ratio
return Color(
red = red * inverse + other.red * ratio,
green = green * inverse + other.green * ratio,
blue = blue * inverse + other.blue * ratio,
alpha = alpha
)
}
@Composable
fun KernelSUTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
amoledMode: Boolean = false,
content: @Composable () -> Unit
) {
val colorScheme = when {
amoledMode && darkTheme && dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
val dynamicScheme = dynamicDarkColorScheme(context)
dynamicScheme.copy(
background = AMOLED_BLACK,
surface = AMOLED_BLACK,
surfaceVariant = dynamicScheme.surfaceVariant.blend(AMOLED_BLACK, 0.6f),
surfaceContainer = dynamicScheme.surfaceContainer.blend(AMOLED_BLACK, 0.6f),
surfaceContainerLow = dynamicScheme.surfaceContainerLow.blend(AMOLED_BLACK, 0.6f),
surfaceContainerLowest = dynamicScheme.surfaceContainerLowest.blend(AMOLED_BLACK, 0.6f),
surfaceContainerHigh = dynamicScheme.surfaceContainerHigh.blend(AMOLED_BLACK, 0.6f),
surfaceContainerHighest = dynamicScheme.surfaceContainerHighest.blend(AMOLED_BLACK, 0.6f),
)
}
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
amoledMode && darkTheme -> {
DarkColorScheme.copy(
background = AMOLED_BLACK,
surface = AMOLED_BLACK,
surfaceVariant = DARK_GREY.blend(AMOLED_BLACK, 0.8f),
surfaceContainer = DARK_GREY.blend(AMOLED_BLACK, 0.8f),
surfaceContainerLow = DARK_GREY.blend(AMOLED_BLACK, 0.8f),
surfaceContainerLowest = DARK_GREY.blend(AMOLED_BLACK, 0.8f),
surfaceContainerHigh = DARK_GREY.blend(AMOLED_BLACK, 0.8f),
surfaceContainerHighest = DARK_GREY.blend(AMOLED_BLACK, 0.8f),
)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}

View File

@@ -37,10 +37,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 +55,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 +105,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)
@@ -605,6 +621,17 @@ fun currentMountSystem(): String {
return result.substringAfter(":").substringAfter(" ").trim()
}
fun getModuleSize(dir: File): Long {
val shell = getRootShell()
val cmd = "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 setAppProfileTemplate(id: String, template: String): Boolean {
val shell = getRootShell()
val escapedTemplate = template.replace("\"", "\\\"")

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
@@ -8,14 +9,20 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dergoogler.mmrl.platform.Platform
import com.dergoogler.mmrl.platform.TIMEOUT_MILLIS
import kotlinx.coroutines.delay
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import java.io.File
import java.text.Collator
import java.util.Locale
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.overlayFsAvailable
import com.rifsxd.ksunext.ui.util.getModuleSize
import org.json.JSONArray
import org.json.JSONObject
@@ -39,7 +46,9 @@ class ModuleViewModel : ViewModel() {
val updateJson: String,
val hasWebUi: Boolean,
val hasActionScript: Boolean,
val dirId: String
val dirId: String,
val size: Long,
val banner: String
)
data class ModuleUpdateInfo(
@@ -49,9 +58,6 @@ class ModuleViewModel : ViewModel() {
val changelog: String,
)
var isOverlayAvailable by mutableStateOf(overlayFsAvailable())
private set
var isRefreshing by mutableStateOf(false)
private set
@@ -59,11 +65,15 @@ class ModuleViewModel : ViewModel() {
var sortAToZ by mutableStateOf(false)
var sortZToA by mutableStateOf(false)
var sortSizeLowToHigh by mutableStateOf(false)
var sortSizeHighToLow by mutableStateOf(false)
val moduleList by derivedStateOf {
val comparator = when {
sortAToZ -> compareBy<ModuleInfo> { it.name.lowercase() }
sortZToA -> compareByDescending<ModuleInfo> { it.name.lowercase() }
sortSizeLowToHigh -> compareBy<ModuleInfo> { it.size }
sortSizeHighToLow -> compareByDescending<ModuleInfo> { it.size }
else -> compareBy<ModuleInfo> { it.dirId }
}.thenBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id)
@@ -84,55 +94,84 @@ 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(Dispatchers.IO) {
isRefreshing = true
viewModelScope.launch {
val oldModuleList = modules
val start = SystemClock.elapsedRealtime()
kotlin.runCatching {
isOverlayAvailable = overlayFsAvailable()
val result = listModules()
Log.i(TAG, "result: $result")
val array = JSONArray(result)
modules = (0 until array.length())
.asSequence()
.map { array.getJSONObject(it) }
.map { obj ->
ModuleInfo(
obj.getString("id"),
obj.optString("name"),
obj.optString("author", "Unknown"),
obj.optString("version", "Unknown"),
obj.optInt("versionCode", 0),
obj.optString("description"),
obj.getBoolean("enabled"),
obj.getBoolean("update"),
obj.getBoolean("remove"),
obj.optString("updateJson"),
obj.optBoolean("web"),
obj.optBoolean("action"),
obj.getString("dir_id")
)
}.toList()
isNeedRefresh = false
}.onFailure { e ->
Log.e(TAG, "fetchModuleList: ", e)
isRefreshing = false
withContext(Dispatchers.Main) {
isRefreshing = true
}
// when both old and new is kotlin.collections.EmptyList
// moduleList update will don't trigger
if (oldModuleList === modules) {
isRefreshing = false
}
withContext(Dispatchers.IO) {
withTimeoutOrNull(TIMEOUT_MILLIS) {
while (!Platform.isAlive) {
delay(500)
}
} ?: run {
isRefreshing = false
Log.e(TAG, "Platform is not alive, aborting fetchModuleList")
return@withContext
}
Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules")
val start = SystemClock.elapsedRealtime()
val oldModuleList = modules
kotlin.runCatching {
val result = listModules()
Log.i(TAG, "result: $result")
val array = JSONArray(result)
modules = (0 until array.length())
.asSequence()
.map { array.getJSONObject(it) }
.map { obj ->
val id = obj.getString("id")
val dirId = obj.getString("dir_id")
val moduleDir = File("/data/adb/modules/$dirId")
val size = getModuleSize(moduleDir)
ModuleInfo(
id,
obj.optString("name"),
obj.optString("author", "Unknown"),
obj.optString("version", "Unknown"),
obj.optInt("versionCode", 0),
obj.optString("description"),
obj.getBoolean("enabled"),
obj.getBoolean("update"),
obj.getBoolean("remove"),
obj.optString("updateJson"),
obj.optBoolean("web"),
obj.optBoolean("action"),
dirId,
size,
obj.optString("banner")
)
}.toList()
isNeedRefresh = false
}.onFailure { e ->
Log.e(TAG, "fetchModuleList: ", e)
isRefreshing = false
}
// when both old and new is kotlin.collections.EmptyList
// moduleList update will don't trigger
if (oldModuleList === modules) {
isRefreshing = false
}
Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules")
}
}
}

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

@@ -41,10 +41,10 @@ class WebUIActivity : ComponentActivity() {
val name = intent.getStringExtra("name")!!
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
setTaskDescription(ActivityManager.TaskDescription("KernelSU Next - $name"))
} else {
val taskDescription =
ActivityManager.TaskDescription.Builder().setLabel("KernelSU - $name").build()
ActivityManager.TaskDescription.Builder().setLabel("KernelSU Next - $name").build()
setTaskDescription(taskDescription)
}

View File

@@ -59,10 +59,10 @@ class WebUIXActivity : ComponentActivity() {
val name = intent.getStringExtra("name")!!
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
setTaskDescription(ActivityManager.TaskDescription("KernelSU Next - $name"))
} else {
val taskDescription =
ActivityManager.TaskDescription.Builder().setLabel("KernelSU - $name").build()
ActivityManager.TaskDescription.Builder().setLabel("KernelSU Next - $name").build()
setTaskDescription(taskDescription)
}

Binary file not shown.

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

@@ -12,13 +12,19 @@
<string name="home">Strona 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">Tryb hookowania</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,13 +45,16 @@
<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>
@@ -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,13 @@
<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="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 +45,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>
@@ -100,6 +106,7 @@
<string name="proceed">Prosseguir</string>
<string name="cancel">Cancelar</string>
<string name="later">Mais tarde</string>
<string name="lkm_warning_message">O patch LKM depende de componentes de código fechado. Deseja continuar?</string>
<string name="home_next_kernelsu">🔥 Compilação next</string>
<string name="home_next_kernelsu_repo">https://github.com/KernelSU-Next/KernelSU-Next</string>
<string name="home_next_kernelsu_body">Branch next experimental. Confira no GitHub!</string>
@@ -133,6 +140,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>
@@ -140,6 +148,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>
@@ -169,6 +181,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>
@@ -198,8 +211,13 @@
<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="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>
</resources>

View File

@@ -18,13 +18,16 @@
<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_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>
@@ -42,13 +45,16 @@
<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_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>
@@ -169,6 +181,7 @@
<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>
@@ -198,8 +211,11 @@
<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="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>
</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

@@ -18,13 +18,14 @@
<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_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="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>
@@ -44,11 +45,14 @@
<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>
@@ -87,19 +91,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,7 +114,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 +138,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 +146,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>
@@ -169,6 +179,7 @@
<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>
@@ -179,15 +190,15 @@
<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>
@@ -198,8 +209,14 @@
<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>
</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_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>
@@ -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>
@@ -102,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">App Profile</string>
<string name="profile_default">默认</string>
<string name="profile_template">模板</string>
@@ -126,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>
@@ -133,15 +148,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 +178,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="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 +193,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 +209,15 @@
<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="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>
</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,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>
@@ -133,22 +148,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>
@@ -161,10 +180,11 @@
<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="action">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 +193,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 +209,15 @@
<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="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>
</resources>

View File

@@ -18,10 +18,13 @@
<string name="home_working_version">Version: %d</string>
<string name="home_superuser_count">Superusers: %d</string>
<string name="home_module_count">Modules: %d</string>
<string name="home_module_update_count">Updates: %d</string>
<string name="home_failure">KernelSU Next v2 signature not found in kernel! [ !KSU_NEXT || != size/hash ]</string>
<string name="home_failure_tip">Ask your kernel developer to integrate KernelSU Next!</string>
<string name="home_kernel">Kernel version</string>
<string name="hook_mode">Hook mode</string>
<string name="enable">Enable</string>
<string name="disable">Disable</string>
<string name="enabled">Enabled</string>
<string name="disabled">Disabled</string>
<string name="susfs_supported">Supported</string>
@@ -42,13 +45,16 @@
<string name="module_empty">No module installed</string>
<string name="module">Module</string>
<string name="module_install_prompt_with_name">The following module(s) will be installed: %1$s</string>
<string name="module_sort_a_to_z">Sort (A-Z)</string>
<string name="module_sort_z_to_a">Sort (Z-A)</string>
<string name="module_sort_a_to_z">Sort (AZ)</string>
<string name="module_sort_z_to_a">Sort (ZA)</string>
<string name="module_size_low_to_high">Sort (Low → High)</string>
<string name="module_size_high_to_low">Sort (High → Low)</string>
<string name="uninstall">Uninstall</string>
<string name="restore">Restore</string>
<string name="module_install">Install</string>
<string name="install">Install</string>
<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_recovery">Reboot to Recovery</string>
@@ -100,6 +106,7 @@
<string name="proceed">Proceed</string>
<string name="cancel">Cancel</string>
<string name="later">Later</string>
<string name="lkm_warning_message">The LKM patch relies on closed source components. Do you want to continue?</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 experimental branch. Check it out on GitHub!</string>
@@ -133,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_updated">Updated</string>
<string name="module_downloading">Downloading module: %s</string>
<string name="module_start_downloading">Start downloading: %s</string>
<string name="new_version_available">New version %s is available, click to upgrade.</string>
@@ -140,6 +148,10 @@
<string name="close">Close</string>
<string name="force_stop_app">Force stop</string>
<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_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>
<string name="module_changelog">Changelog</string>
@@ -169,6 +181,7 @@
<string name="settings_check_update_summary">Automatically check for updates when opening the app.</string>
<string name="grant_root_failed">Failed to grant root!</string>
<string name="action">Action</string>
<string name="webui">WebUI</string>
<string name="open">Open</string>
<string name="enable_web_debugging">Enable WebView debugging</string>
<string name="enable_web_debugging_summary">Can be used to debug WebUI. Please enable only when needed.</string>
@@ -198,8 +211,15 @@
<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="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>
<string name="use_webuix">Use WebUI X</string>
<string name="use_webuix_summary">Use WebUI X instead of WebUI, which supports more APIs.</string>
<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>
</resources>

View File

@@ -18,7 +18,7 @@ cmaker {
"-DANDROID_STL=none",
)
)
abiFilters("arm64-v8a", "armeabi-v7a")
abiFilters("arm64-v8a", "armeabi-v7a", "x86_64")
}
buildTypes {
if (it.name == "release") {
@@ -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
@@ -78,7 +78,7 @@ subprojects {
versionName = managerVersionName
}
ndk {
abiFilters += listOf("arm64-v8a", "armeabi-v7a")
abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64")
}
}

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,13 +11,13 @@ 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"
apksign = "1.4"
cmaker = "1.2"
mmrl = "1998c70b77"
mmrl = "2bb00b3c2b"
[plugins]
agp-app = { id = "com.android.application", version.ref = "agp" }
@@ -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"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -7,7 +7,7 @@ use crate::{defs::BINARY_DIR, utils};
pub const RESETPROP_PATH: &str = concatcp!(BINARY_DIR, "resetprop");
pub const BUSYBOX_PATH: &str = concatcp!(BINARY_DIR, "busybox");
#[allow(dead_code)]
pub const BOOTCTL_PATH: &str = concatcp!(BINARY_DIR, "bootctl");
#[allow(dead_code)]
@@ -23,6 +23,11 @@ struct Asset;
#[folder = "bin/arm"]
struct Asset;
#[cfg(all(target_arch = "x86_64", target_os = "android"))]
#[derive(RustEmbed)]
#[folder = "bin/x86_64"]
struct Asset;
pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> {
for file in Asset::iter() {
if file == "ksuinit" || file.ends_with(".ko") {

View File

@@ -19,7 +19,6 @@ use crate::defs::{KSU_BACKUP_DIR, KSU_BACKUP_FILE_PREFIX};
use crate::{assets, utils};
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn ensure_gki_kernel() -> Result<()> {
let version = get_kernel_version()?;
let is_gki = version.0 == 5 && version.1 >= 10 || version.2 > 5;
@@ -28,7 +27,6 @@ fn ensure_gki_kernel() -> Result<()> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
let uname = rustix::system::uname();
let version = uname.release().to_string_lossy();
@@ -53,7 +51,6 @@ pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn parse_kmi(version: &str) -> Result<String> {
let re = Regex::new(r"(.* )?(\d+\.\d+)(\S+)?(android\d+)(.*)")?;
let cap = re
@@ -65,7 +62,6 @@ fn parse_kmi(version: &str) -> Result<String> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn parse_kmi_from_uname() -> Result<String> {
let uname = rustix::system::uname();
let version = uname.release().to_string_lossy();
@@ -73,7 +69,6 @@ fn parse_kmi_from_uname() -> Result<String> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn parse_kmi_from_modules() -> Result<String> {
use std::io::BufRead;
// find a *.ko in /vendor/lib/modules
@@ -92,18 +87,15 @@ fn parse_kmi_from_modules() -> Result<String> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
pub fn get_current_kmi() -> Result<String> {
parse_kmi_from_uname().or_else(|_| parse_kmi_from_modules())
}
#[cfg(not(target_os = "android"))]
#[allow(dead_code)]
pub fn get_current_kmi() -> Result<String> {
bail!("Unsupported platform")
}
#[allow(dead_code)]
fn parse_kmi_from_kernel(kernel: &PathBuf, workdir: &Path) -> Result<String> {
use std::fs::{File, copy};
use std::io::{BufReader, Read};
@@ -137,7 +129,6 @@ fn parse_kmi_from_kernel(kernel: &PathBuf, workdir: &Path) -> Result<String> {
bail!("Try to choose LKM manually")
}
#[allow(dead_code)]
fn parse_kmi_from_boot(magiskboot: &Path, image: &PathBuf, workdir: &Path) -> Result<String> {
let image_path = workdir.join("image");
@@ -162,7 +153,6 @@ fn parse_kmi_from_boot(magiskboot: &Path, image: &PathBuf, workdir: &Path) -> Re
parse_kmi_from_kernel(&image_path, workdir)
}
#[allow(dead_code)]
fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -177,7 +167,21 @@ fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
fn do_vendor_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
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())
.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)
@@ -190,7 +194,6 @@ fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.code() == Some(1))
}
#[allow(dead_code)]
fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -202,7 +205,6 @@ fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.success())
}
#[allow(dead_code)]
fn dd<P: AsRef<Path>, Q: AsRef<Path>>(ifile: P, ofile: Q) -> Result<()> {
let status = Command::new("dd")
.stdout(Stdio::null())
@@ -219,7 +221,6 @@ fn dd<P: AsRef<Path>, Q: AsRef<Path>>(ifile: P, ofile: Q) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
pub fn restore(
image: Option<PathBuf>,
magiskboot_path: Option<PathBuf>,
@@ -248,6 +249,7 @@ pub fn restore(
.status()?;
ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists();
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
ensure!(
is_kernelsu_patched,
@@ -284,16 +286,29 @@ pub fn restore(
}
if new_boot.is_none() {
// remove kernelsu.ko
do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
if no_ramdisk {
// vendor ramdisk restore
do_vendor_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_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_vendor_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let vendor_ramdisk = workdir.join("vendor_ramdisk").join("init_boot.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");
@@ -337,7 +352,6 @@ pub fn restore(
Ok(())
}
#[allow(dead_code)]
#[allow(clippy::too_many_arguments)]
pub fn patch(
image: Option<PathBuf>,
@@ -357,7 +371,6 @@ pub fn patch(
result
}
#[allow(dead_code)]
#[allow(clippy::too_many_arguments)]
fn do_patch(
image: Option<PathBuf>,
@@ -457,11 +470,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)
@@ -484,17 +492,29 @@ fn do_patch(
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 no_ramdisk {
// vendor ramdisk patching
let status = do_vendor_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_vendor_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 {
do_vendor_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_vendor_cpio_cmd(&magiskboot, workdir, "add 0755 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 {
@@ -544,7 +564,6 @@ fn do_patch(
Ok(())
}
#[allow(dead_code)]
#[cfg(target_os = "android")]
fn calculate_sha1(file_path: impl AsRef<Path>) -> Result<String> {
use sha1::Digest;
@@ -565,7 +584,6 @@ fn calculate_sha1(file_path: impl AsRef<Path>) -> Result<String> {
Ok(format!("{:x}", result))
}
#[allow(dead_code)]
#[cfg(target_os = "android")]
fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> {
let sha1 = calculate_sha1(image)?;
@@ -586,7 +604,6 @@ fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
#[cfg(target_os = "android")]
fn clean_backup(sha1: &str) -> Result<()> {
println!("- Clean up backup");
@@ -610,7 +627,6 @@ fn clean_backup(sha1: &str) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
fn flash_boot(bootdevice: &Option<String>, new_boot: PathBuf) -> Result<()> {
let Some(bootdevice) = bootdevice else {
bail!("boot device not found")
@@ -624,7 +640,6 @@ fn flash_boot(bootdevice: &Option<String>, new_boot: PathBuf) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
fn find_magiskboot(magiskboot_path: Option<PathBuf>, workdir: &Path) -> Result<PathBuf> {
let magiskboot = {
if which("magiskboot").is_ok() {
@@ -649,7 +664,6 @@ fn find_magiskboot(magiskboot_path: Option<PathBuf>, workdir: &Path) -> Result<P
Ok(magiskboot)
}
#[allow(dead_code)]
fn find_boot_image(
image: &Option<PathBuf>,
skip_init: bool,
@@ -680,8 +694,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

@@ -62,65 +62,67 @@ enum Commands {
#[command(subcommand)]
command: Profile,
},
//
// /// Patch boot or init_boot images to apply KernelSU Next
// BootPatch {
// /// boot image path, if not specified, will try to find the boot image automatically
// #[arg(short, long)]
// boot: Option<PathBuf>,
//
// /// kernel image path to replace
// #[arg(short, long)]
// kernel: Option<PathBuf>,
//
// /// LKM module path to replace, if not specified, will use the builtin one
// #[arg(short, long)]
// module: Option<PathBuf>,
//
// /// init to be replaced
// #[arg(short, long, requires("module"))]
// init: Option<PathBuf>,
//
// /// will use another slot when boot image is not specified
// #[arg(short = 'u', long, default_value = "false")]
// ota: bool,
//
// /// Flash it to boot partition after patch
// #[arg(short, long, default_value = "false")]
// flash: bool,
//
// /// output path, if not specified, will use current directory
// #[arg(short, long, default_value = None)]
// out: Option<PathBuf>,
//
// /// magiskboot path, if not specified, will search from $PATH
// #[arg(long, default_value = None)]
// magiskboot: Option<PathBuf>,
//
// /// KMI version, if specified, will use the specified KMI
// #[arg(long, default_value = None)]
// kmi: Option<String>,
// },
//
// /// Restore boot or init_boot images patched by KernelSU Next
// BootRestore {
// /// boot image path, if not specified, will try to find the boot image automatically
// #[arg(short, long)]
// boot: Option<PathBuf>,
//
// /// Flash it to boot partition after patch
// #[arg(short, long, default_value = "false")]
// flash: bool,
//
// /// magiskboot path, if not specified, will search from $PATH
// #[arg(long, default_value = None)]
// magiskboot: Option<PathBuf>,
// },
/// Patch boot or init_boot images to apply KernelSU Next
BootPatch {
/// boot image path, if not specified, will try to find the boot image automatically
#[arg(short, long)]
boot: Option<PathBuf>,
/// kernel image path to replace
#[arg(short, long)]
kernel: Option<PathBuf>,
/// LKM module path to replace, if not specified, will use the builtin one
#[arg(short, long)]
module: Option<PathBuf>,
/// init to be replaced
#[arg(short, long, requires("module"))]
init: Option<PathBuf>,
/// will use another slot when boot image is not specified
#[arg(short = 'u', long, default_value = "false")]
ota: bool,
/// Flash it to boot partition after patch
#[arg(short, long, default_value = "false")]
flash: bool,
/// output path, if not specified, will use current directory
#[arg(short, long, default_value = None)]
out: Option<PathBuf>,
/// magiskboot path, if not specified, will search from $PATH
#[arg(long, default_value = None)]
magiskboot: Option<PathBuf>,
/// KMI version, if specified, will use the specified KMI
#[arg(long, default_value = None)]
kmi: Option<String>,
},
/// Restore boot or init_boot images patched by KernelSU Next
BootRestore {
/// boot image path, if not specified, will try to find the boot image automatically
#[arg(short, long)]
boot: Option<PathBuf>,
/// Flash it to boot partition after patch
#[arg(short, long, default_value = "false")]
flash: bool,
/// magiskboot path, if not specified, will search from $PATH
#[arg(long, default_value = None)]
magiskboot: Option<PathBuf>,
},
/// Show boot information
BootInfo {
#[command(subcommand)]
command: BootInfo,
},
/// For developers
Debug {
#[command(subcommand)]
@@ -354,17 +356,17 @@ pub fn run() -> Result<()> {
Debug::Test => assets::ensure_binaries(false),
},
// Commands::BootPatch {
// boot,
// init,
// kernel,
// module,
// ota,
// flash,
// out,
// magiskboot,
// kmi,
// } => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot, kmi), // DISBAND LKM MODE
Commands::BootPatch {
boot,
init,
kernel,
module,
ota,
flash,
out,
magiskboot,
kmi,
} => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot, kmi),
Commands::BootInfo { command } => match command {
BootInfo::CurrentKmi => {
let kmi = crate::boot_patch::get_current_kmi()?;
@@ -378,11 +380,11 @@ pub fn run() -> Result<()> {
return Ok(());
}
},
// Commands::BootRestore {
// boot,
// magiskboot,
// flash,
// } => crate::boot_patch::restore(boot, magiskboot, flash),
Commands::BootRestore {
boot,
magiskboot,
flash,
} => crate::boot_patch::restore(boot, magiskboot, flash),
};
if let Err(e) = &result {

View File

@@ -202,6 +202,10 @@ pub fn root_shell() -> Result<()> {
if free_idx < matches.free.len() {
let name = &matches.free[free_idx];
uid = unsafe {
#[cfg(target_arch = "x86_64")]
let pw = libc::getpwnam(name.as_ptr() as *const i8).as_ref();
#[cfg(not(target_arch = "x86_64"))]
let pw = libc::getpwnam(name.as_ptr()).as_ref();
match pw {
Some(pw) => pw.pw_uid,

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"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -8,7 +8,6 @@ use crate::{defs::BINARY_DIR, utils};
pub const RESETPROP_PATH: &str = concatcp!(BINARY_DIR, "resetprop");
pub const BUSYBOX_PATH: &str = concatcp!(BINARY_DIR, "busybox");
#[allow(dead_code)]
pub const BOOTCTL_PATH: &str = concatcp!(BINARY_DIR, "bootctl");
#[allow(dead_code)]
@@ -24,6 +23,11 @@ struct Asset;
#[folder = "bin/arm"]
struct Asset;
#[cfg(all(target_arch = "x86_64", target_os = "android"))]
#[derive(RustEmbed)]
#[folder = "bin/x86_64"]
struct Asset;
pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> {
for file in Asset::iter() {
if file == "ksuinit" || file.ends_with(".ko") {

View File

@@ -19,7 +19,6 @@ use crate::defs::{KSU_BACKUP_DIR, KSU_BACKUP_FILE_PREFIX};
use crate::{assets, utils};
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn ensure_gki_kernel() -> Result<()> {
let version = get_kernel_version()?;
let is_gki = version.0 == 5 && version.1 >= 10 || version.2 > 5;
@@ -28,7 +27,6 @@ fn ensure_gki_kernel() -> Result<()> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
let uname = rustix::system::uname();
let version = uname.release().to_string_lossy();
@@ -94,12 +92,10 @@ pub fn get_current_kmi() -> Result<String> {
}
#[cfg(not(target_os = "android"))]
#[allow(dead_code)]
pub fn get_current_kmi() -> Result<String> {
bail!("Unsupported platform")
}
#[allow(dead_code)]
fn parse_kmi_from_kernel(kernel: &PathBuf, workdir: &Path) -> Result<String> {
use std::fs::{File, copy};
use std::io::{BufReader, Read};
@@ -133,7 +129,6 @@ fn parse_kmi_from_kernel(kernel: &PathBuf, workdir: &Path) -> Result<String> {
bail!("Try to choose LKM manually")
}
#[allow(dead_code)]
fn parse_kmi_from_boot(magiskboot: &Path, image: &PathBuf, workdir: &Path) -> Result<String> {
let image_path = workdir.join("image");
@@ -158,7 +153,6 @@ fn parse_kmi_from_boot(magiskboot: &Path, image: &PathBuf, workdir: &Path) -> Re
parse_kmi_from_kernel(&image_path, workdir)
}
#[allow(dead_code)]
fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -173,7 +167,21 @@ fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
fn do_vendor_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
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())
.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)
@@ -186,7 +194,6 @@ fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.code() == Some(1))
}
#[allow(dead_code)]
fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
@@ -198,7 +205,6 @@ fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
Ok(status.success())
}
#[allow(dead_code)]
fn dd<P: AsRef<Path>, Q: AsRef<Path>>(ifile: P, ofile: Q) -> Result<()> {
let status = Command::new("dd")
.stdout(Stdio::null())
@@ -243,6 +249,7 @@ pub fn restore(
.status()?;
ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists();
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
ensure!(
is_kernelsu_patched,
@@ -279,16 +286,29 @@ pub fn restore(
}
if new_boot.is_none() {
// remove kernelsu.ko
do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
if no_ramdisk {
// vendor ramdisk restore
do_vendor_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_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_vendor_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let vendor_ramdisk = workdir.join("vendor_ramdisk").join("init_boot.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");
@@ -310,7 +330,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")
));
@@ -332,7 +352,6 @@ pub fn restore(
Ok(())
}
#[allow(dead_code)]
#[allow(clippy::too_many_arguments)]
pub fn patch(
image: Option<PathBuf>,
@@ -352,7 +371,6 @@ pub fn patch(
result
}
#[allow(dead_code)]
#[allow(clippy::too_many_arguments)]
fn do_patch(
image: Option<PathBuf>,
@@ -452,11 +470,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)
@@ -479,17 +492,29 @@ fn do_patch(
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 no_ramdisk {
// vendor ramdisk patching
let status = do_vendor_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_vendor_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 {
do_vendor_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
do_vendor_cpio_cmd(&magiskboot, workdir, "add 0755 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 {
@@ -540,7 +565,6 @@ fn do_patch(
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn calculate_sha1(file_path: impl AsRef<Path>) -> Result<String> {
use sha1::Digest;
use std::io::Read;
@@ -561,7 +585,6 @@ fn calculate_sha1(file_path: impl AsRef<Path>) -> Result<String> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> {
let sha1 = calculate_sha1(image)?;
let filename = format!("{KSU_BACKUP_FILE_PREFIX}{sha1}");
@@ -582,7 +605,6 @@ fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> {
}
#[cfg(target_os = "android")]
#[allow(dead_code)]
fn clean_backup(sha1: &str) -> Result<()> {
println!("- Clean up backup");
let backup_name = format!("{}{}", KSU_BACKUP_FILE_PREFIX, sha1);
@@ -605,7 +627,6 @@ fn clean_backup(sha1: &str) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
fn flash_boot(bootdevice: &Option<String>, new_boot: PathBuf) -> Result<()> {
let Some(bootdevice) = bootdevice else {
bail!("boot device not found")
@@ -619,7 +640,6 @@ fn flash_boot(bootdevice: &Option<String>, new_boot: PathBuf) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
fn find_magiskboot(magiskboot_path: Option<PathBuf>, workdir: &Path) -> Result<PathBuf> {
let magiskboot = {
if which("magiskboot").is_ok() {
@@ -644,7 +664,6 @@ fn find_magiskboot(magiskboot_path: Option<PathBuf>, workdir: &Path) -> Result<P
Ok(magiskboot)
}
#[allow(dead_code)]
fn find_boot_image(
image: &Option<PathBuf>,
skip_init: bool,
@@ -675,8 +694,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}")
};
@@ -694,7 +717,6 @@ fn find_boot_image(
Ok((bootimage, bootdevice))
}
#[allow(dead_code)]
fn post_ota() -> Result<()> {
use crate::defs::ADB_DIR;
use assets::BOOTCTL_PATH;

View File

@@ -58,65 +58,67 @@ enum Commands {
#[command(subcommand)]
command: Profile,
},
//
// /// Patch boot or init_boot images to apply KernelSU Next
// BootPatch {
// /// boot image path, if not specified, will try to find the boot image automatically
// #[arg(short, long)]
// boot: Option<PathBuf>,
//
// /// kernel image path to replace
// #[arg(short, long)]
// kernel: Option<PathBuf>,
//
// /// LKM module path to replace, if not specified, will use the builtin one
// #[arg(short, long)]
// module: Option<PathBuf>,
//
// /// init to be replaced
// #[arg(short, long, requires("module"))]
// init: Option<PathBuf>,
//
// /// will use another slot when boot image is not specified
// #[arg(short = 'u', long, default_value = "false")]
// ota: bool,
//
// /// Flash it to boot partition after patch
// #[arg(short, long, default_value = "false")]
// flash: bool,
//
// /// output path, if not specified, will use current directory
// #[arg(short, long, default_value = None)]
// out: Option<PathBuf>,
//
// /// magiskboot path, if not specified, will search from $PATH
// #[arg(long, default_value = None)]
// magiskboot: Option<PathBuf>,
//
// /// KMI version, if specified, will use the specified KMI
// #[arg(long, default_value = None)]
// kmi: Option<String>,
// }, // DISBAND LKM MODE
//
// /// Restore boot or init_boot images patched by KernelSU Next
// BootRestore {
// /// boot image path, if not specified, will try to find the boot image automatically
// #[arg(short, long)]
// boot: Option<PathBuf>,
//
// /// Flash it to boot partition after patch
// #[arg(short, long, default_value = "false")]
// flash: bool,
//
// /// magiskboot path, if not specified, will search from $PATH
// #[arg(long, default_value = None)]
// magiskboot: Option<PathBuf>,
// },
/// Patch boot or init_boot images to apply KernelSU Next
BootPatch {
/// boot image path, if not specified, will try to find the boot image automatically
#[arg(short, long)]
boot: Option<PathBuf>,
/// kernel image path to replace
#[arg(short, long)]
kernel: Option<PathBuf>,
/// LKM module path to replace, if not specified, will use the builtin one
#[arg(short, long)]
module: Option<PathBuf>,
/// init to be replaced
#[arg(short, long, requires("module"))]
init: Option<PathBuf>,
/// will use another slot when boot image is not specified
#[arg(short = 'u', long, default_value = "false")]
ota: bool,
/// Flash it to boot partition after patch
#[arg(short, long, default_value = "false")]
flash: bool,
/// output path, if not specified, will use current directory
#[arg(short, long, default_value = None)]
out: Option<PathBuf>,
/// magiskboot path, if not specified, will search from $PATH
#[arg(long, default_value = None)]
magiskboot: Option<PathBuf>,
/// KMI version, if specified, will use the specified KMI
#[arg(long, default_value = None)]
kmi: Option<String>,
},
/// Restore boot or init_boot images patched by KernelSU Next
BootRestore {
/// boot image path, if not specified, will try to find the boot image automatically
#[arg(short, long)]
boot: Option<PathBuf>,
/// Flash it to boot partition after patch
#[arg(short, long, default_value = "false")]
flash: bool,
/// magiskboot path, if not specified, will search from $PATH
#[arg(long, default_value = None)]
magiskboot: Option<PathBuf>,
},
/// Show boot information
BootInfo {
#[command(subcommand)]
command: BootInfo,
},
/// For developers
Debug {
#[command(subcommand)]
@@ -326,7 +328,7 @@ pub fn run() -> Result<()> {
Module::Shrink => module::shrink_ksu_images(),
}
}
Commands::Install { magiskboot } => utils::install(magiskboot), // DISBAND LKM MODE
Commands::Install { magiskboot } => utils::install(magiskboot),
Commands::Uninstall { magiskboot } => utils::uninstall(magiskboot),
Commands::Sepolicy { command } => match command {
Sepolicy::Patch { sepolicy } => crate::sepolicy::live_patch(&sepolicy),
@@ -369,17 +371,17 @@ pub fn run() -> Result<()> {
Debug::Test => assets::ensure_binaries(false),
},
// Commands::BootPatch {
// boot,
// init,
// kernel,
// module,
// ota,
// flash,
// out,
// magiskboot,
// kmi,
// } => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot, kmi), // DISBAND LKM MODE
Commands::BootPatch {
boot,
init,
kernel,
module,
ota,
flash,
out,
magiskboot,
kmi,
} => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot, kmi),
Commands::BootInfo { command } => match command {
BootInfo::CurrentKmi => {
let kmi = crate::boot_patch::get_current_kmi()?;
@@ -393,11 +395,11 @@ pub fn run() -> Result<()> {
return Ok(());
}
},
// Commands::BootRestore {
// boot,
// magiskboot,
// flash,
// } => crate::boot_patch::restore(boot, magiskboot, flash),
Commands::BootRestore {
boot,
magiskboot,
flash,
} => crate::boot_patch::restore(boot, magiskboot, flash),
};
if let Err(e) = &result {

View File

@@ -202,6 +202,10 @@ pub fn root_shell() -> Result<()> {
if free_idx < matches.free.len() {
let name = &matches.free[free_idx];
uid = unsafe {
#[cfg(target_arch = "x86_64")]
let pw = libc::getpwnam(name.as_ptr() as *const i8).as_ref();
#[cfg(not(target_arch = "x86_64"))]
let pw = libc::getpwnam(name.as_ptr()).as_ref();
match pw {
Some(pw) => pw.pw_uid,

View File

@@ -1,3 +1,3 @@
APP_ABI := arm64-v8a armeabi-v7a
APP_ABI := arm64-v8a armeabi-v7a x86_64
APP_PLATFORM := android-24
APP_STL := none

View File

@@ -1,3 +1,3 @@
APP_ABI := arm64-v8a armeabi-v7a
APP_ABI := arm64-v8a armeabi-v7a x86_64
APP_PLATFORM := android-24
APP_STL := none